diff options
Diffstat (limited to 'src/or/buffers.c')
-rw-r--r-- | src/or/buffers.c | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 11c4fc8b9..534f31c17 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1633,40 +1633,74 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req, uint8_t socksver; enum {socks4, socks4a} socks4_prot = socks4a; char *next, *startaddr; + unsigned char usernamelen, passlen; struct in_addr in; socksver = *data; switch (socksver) { /* which version of socks? */ + case 1: /* socks5: username/password authentication request */ + + usernamelen = (unsigned char)*(buf->head->data + 1); + if (buf->datalen < 2u + usernamelen) + return 0; + buf_pullup(buf, 2u + usernamelen + 1, 0); + passlen = (unsigned char)*(buf->head->data + 2u + usernamelen); + if (buf->datalen < 2u + usernamelen + 1u + passlen) + return 0; + if (buf->datalen > 2u + usernamelen + 1u + passlen) { + log_warn(LD_APP, + "socks5: Malformed username/password. Rejecting."); + return -1; + } + req->replylen = 2; /* 2 bytes of response */ + req->reply[0] = 5; + req->reply[1] = 0; /* authentication successful */ + buf_clear(buf); + log_debug(LD_APP, + "socks5: Accepted username/password without checking."); + return 0; + case 5: /* socks5 */ if (req->socks_version != 5) { /* we need to negotiate a method */ unsigned char nummethods = (unsigned char)*(data+1); + int r=0; tor_assert(!req->socks_version); if (datalen < 2u+nummethods) { *want_length_out = 2u+nummethods; return 0; } - if (!nummethods || !memchr(data+2, 0, nummethods)) { + buf_pullup(buf, 2u+nummethods, 0); + if (!nummethods) + return -1; + req->replylen = 2; /* 2 bytes of response */ + req->reply[0] = 5; /* socks5 reply */ + if (memchr(buf->head->data+2, SOCKS_NO_AUTH, nummethods)) { + req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth + method */ + req->socks_version = 5; /* remember we've already negotiated auth */ + log_debug(LD_APP,"socks5: accepted method 0 (no authentication)"); + r=0; + }else if (memchr(buf->head->data+2, SOCKS_USER_PASS,nummethods)) { + req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass" + auth method */ + req->socks_version = 5; /* remember we've already negotiated auth */ + log_debug(LD_APP,"socks5: accepted method 2 (username/password)"); + r=0; + } else { log_warn(LD_APP, - "socks5: offered methods don't include 'no auth'. " - "Rejecting."); - req->replylen = 2; /* 2 bytes of response */ - req->reply[0] = 5; + "socks5: offered methods don't include 'no auth' or " + "username/password. Rejecting."); req->reply[1] = '\xFF'; /* reject all methods */ - return -1; + r=-1; } /* remove packet from buf. also remove any other extraneous * bytes, to support broken socks clients. */ *drain_out = -1; - req->replylen = 2; /* 2 bytes of response */ - req->reply[0] = 5; /* socks5 reply */ - req->reply[1] = 0; /* tell client to use "none" auth method */ - req->socks_version = 5; /* remember we've already negotiated auth */ - log_debug(LD_APP,"socks5: accepted method 0"); - return 0; + return r; } /* we know the method; read in the request */ log_debug(LD_APP,"socks5: checking request"); @@ -1761,8 +1795,8 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req, } tor_assert(0); case 4: /* socks4 */ - /* http://archive.socks.permeo.com/protocol/socks4.protocol */ - /* http://archive.socks.permeo.com/protocol/socks4a.protocol */ + /* http://ss5.sourceforge.net/socks4.protocol.txt */ + /* http://ss5.sourceforge.net/socks4A.protocol.txt */ req->socks_version = 4; if (datalen < SOCKS4_NETWORK_LEN) {/* basic info available? */ |