qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 1/1] slirp: add SOCKS5 support


From: Laurent Vivier
Subject: Re: [Qemu-devel] [PATCH v3 1/1] slirp: add SOCKS5 support
Date: Tue, 4 Apr 2017 12:58:22 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0

Le 04/04/2017 à 12:05, Philippe Mathieu-Daudé a écrit :
> Hi Laurent,

Hi Philippe,

> I waited this feature for long and excited to try it soon :)
> 
> Please find some comments inline.
> 
> On 04/03/2017 08:56 PM, Laurent Vivier wrote:
>> When the VM is used behind a firewall, This allows
>> the use of a SOCKS5 proxy server to connect the VM IP stack
>> directly to the Internet.
>>
>> This implementation doesn't manage UDP packets, so they
>> are simply dropped (as with restrict=on), except for
>> the localhost as we need it for DNS.
>>
>> Signed-off-by: Laurent Vivier <address@hidden>
>> ---
>>  net/slirp.c         |  39 ++++++-
>>  qapi-schema.json    |   9 ++
>>  qemu-options.hx     |  11 ++
>>  slirp/Makefile.objs |   2 +-
>>  slirp/ip_icmp.c     |   2 +-
>>  slirp/libslirp.h    |   3 +
>>  slirp/slirp.c       |  68 ++++++++++-
>>  slirp/slirp.h       |   6 +
>>  slirp/socket.h      |   4 +
>>  slirp/socks5.c      | 328
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  slirp/socks5.h      |  24 ++++
>>  slirp/tcp_subr.c    |  22 +++-
>>  slirp/udp.c         |   9 ++
>>  slirp/udp6.c        |   8 ++
>>  14 files changed, 524 insertions(+), 11 deletions(-)
>>  create mode 100644 slirp/socks5.c
>>  create mode 100644 slirp/socks5.h
>>
...
>> diff --git a/slirp/socks5.c b/slirp/socks5.c
>> new file mode 100644
>> index 0000000..813c3db
>> --- /dev/null
>> +++ b/slirp/socks5.c
>> @@ -0,0 +1,328 @@
>> +/* based on RFC 1928
>> + *   SOCKS Protocol Version 5
>> + * based on RFC 1929
>> + *   Username/Password Authentication for SOCKS V5
>> + * TODO:
>> + *   - RFC 1961 GSS-API Authentication Method for SOCKS Version 5
>> + *   - manage buffering on recv()
>> + *   - IPv6 connection to proxy
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/sockets.h"
>> +
>> +#include "socks5.h"
>> +
>> +#define SOCKS_LEN_MAX                  0xff
> 
> I can't find 0xFF in the RFC1928, I prefer a self-explanatory UINT8_MAX
> but that's up to you (RFC1929 uses 255 for UNAME/PASSWD but not
> explicitly for FQDN).

I agree UINT8_MAX looks better.

...
>> +static int socks5_recv_connect(int fd)
>> +{
>> +    uint8_t reply[7 + SOCKS_LEN_MAX]; /* can contains a FQDN */
>> +
>> +    /*
>> +     * reply[0] is protocol version: 5
>> +     * reply[1] is reply field
>> +     * reply[2] is reserved
>> +     * reply[3] is address type */
>> +
>> +    if (recv(fd, reply, 4, 0) != 4) {
>> +        return -1;
>> +    }
>> +
>> +    if (reply[0] != SOCKS_VERSION_5) {
>> +        errno = EINVAL;
>> +        return -1;
>> +    }
>> +
>> +    if (reply[1] != SOCKS5_CMD_SUCCESS) {
>> +        errno = EINVAL;
> 
> Here the failure reason is lost! It should be notified to the user, can
> you add some function to display it?

Yes, I ignore it because I don't know what to do with result.

Perhaps I can add a log...

> 
>> +        return -1;
>> +    }
>> +
>> +    switch (reply[3]) {
>> +    case SOCKS5_ATYPE_IPV4:
>> +        if (recv(fd, reply + 4, 6, 0) != 6) {
> 
> Can we avoid this magic using sizeof(struct in_addr) + sizeof(in_port_t)
> or a #define?

I have put the number directly here because in the RFC we have directly
the number, but I agree the sizeof() is a better solution.

> 
>> +            return -1;
>> +        }
>> +        break;
>> +    case SOCKS5_ATYPE_IPV6:
>> +        if (recv(fd, reply + 4, 18, 0) != 18) {
> 
> same with sizeof(struct in6_addr) + sizeof(in_port_t)

OK

>> +            return -1;
>> +        }
>> +        break;
>> +    case SOCKS5_ATYPE_FQDN:
>> +        if (recv(fd, reply + 4, 1, 0) != 1) {
>> +            return -1;
>> +        }
>> +        if (recv(fd, reply + 5,
>> +                 reply[4], 0) != reply[4]) {
> 
> Would be nice/useful to log the FQDN (but it needs to be sanitized in
> case of nasty invalid data). Let it be a /* TODO */ at least.

Yes, I can add a log.

...
>> +void socks5_recv(int fd, socks5_state_t *state)
>> +{
>> +    int ret;
>> +
>> +    switch (*state) {
>> +    case SOCKS5_STATE_NEGOCIATING:
>> +        switch (socks5_recv_negociate(fd)) {
>> +        case SOCKS5_AUTH_METHOD_NONE: /* no authentification */
>> +            *state = SOCKS5_STATE_ESTABLISH;
>> +            break;
>> +        case SOCKS5_AUTH_METHOD_PASSWORD: /* username/password */
>> +            *state = SOCKS5_STATE_AUTHENTICATE;
>> +            break;
>> +        default:
>> +            break;
> 
> Reading the RFC1928 the server can reply SOCKS5_AUTH_METHOD_GSSAPI or
> SOCKS5_AUTH_METHOD_REJECTED which are valid. RFC states:
> 
>    Compliant implementations MUST support GSSAPI and SHOULD support
>    USERNAME/PASSWORD authentication methods.

Yes, I know, GSSAPI is in the TODO of the file header ;)
For instance, neither ncat nor TOR implement it... so I think it can
wait someone really needs it.

> 
> I wonder if this could lead to and infinite negociation and being
> paranoid an evil server could keep DDoS'ing this client :)
> Anyway I think this function has to handle this (eventually reporting
> some Unsupported/Invalid protocol issue) as state the RFC for
> SOCKS5_AUTH_METHOD_REJECTED:
> 
>    If the selected METHOD is X'FF', none of the methods listed by the
>    client are acceptable, and the client MUST close the connection.

I agree error case is not correctly managed. I will fix.

>> +        }
>> +        break;
>> +    case SOCKS5_STATE_AUTHENTICATING:
>> +        ret = socks5_recv_password(fd);
>> +        if (ret >= 0) {
>> +            *state = SOCKS5_STATE_ESTABLISH;
>> +        }
>> +        break;
>> +    case SOCKS5_STATE_ESTABLISHING:
>> +        ret = socks5_recv_connect(fd);
>> +        if (ret >= 0) {
>> +            *state = SOCKS5_STATE_NONE;
>> +        }
>> +        break;
>> +    default:
>> +        break;
> 
> I think only the case SOCKS5_STATE_NONE can break, all other states
> should be handled as error in protocol.
> 

I agree.

Thanks,
Laurent




reply via email to

[Prev in Thread] Current Thread [Next in Thread]