Second phase of SOCKS5

This commit is contained in:
rl1987 2018-05-21 17:33:28 +02:00 committed by Nick Mathewson
parent 57342b19f5
commit bcbd3fb71e
3 changed files with 151 additions and 11 deletions

View File

@ -453,11 +453,135 @@ process_socks5_userpass_auth(socks_request_t *req)
return res; return res;
} }
static int
parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req,
size_t datalen, size_t *drain_out)
{
int res = 1;
tor_addr_t destaddr;
socks5_client_request_t *trunnel_req = NULL;
ssize_t parsed = socks5_client_request_parse(&trunnel_req, raw_data, datalen);
if (parsed == -1) {
log_warn(LD_APP, "socks5: parsing failed - invalid client request");
res = -1;
goto end;
} else if (parsed == -2) {
res = 0;
goto end;
}
tor_assert(parsed >= 0);
*drain_out = (size_t)parsed;
if (socks5_client_request_get_version(trunnel_req) != 5) {
res = -1;
goto end;
}
req->command = socks5_client_request_get_command(trunnel_req);
req->port = socks5_client_request_get_dest_port(trunnel_req);
uint8_t atype = socks5_client_request_get_atype(trunnel_req);
req->socks5_atyp = atype;
switch (atype) {
case 1: {
uint32_t ipv4 = socks5_client_request_get_dest_addr_ipv4(trunnel_req);
tor_addr_from_ipv4h(&destaddr, ipv4);
tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
} break;
case 3: {
const struct domainname_st *dns_name =
socks5_client_request_getconst_dest_addr_domainname(trunnel_req);
const char *hostname = domainname_getconstarray_name(dns_name);
strlcpy(req->address, hostname, sizeof(req->address));
} break;
case 4: {
const char *ipv6 =
(const char *)socks5_client_request_getarray_dest_addr_ipv6(trunnel_req);
tor_addr_from_ipv6_bytes(&destaddr, ipv6);
tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
} break;
default: {
res = -1;
} break;
}
end:
socks5_client_request_free(trunnel_req);
return res;
}
static int
process_socks5_client_request(socks_request_t *req,
int log_sockstype,
int safe_socks)
{
int res = 1;
if (req->command != SOCKS_COMMAND_CONNECT &&
req->command != SOCKS_COMMAND_RESOLVE &&
req->command != SOCKS_COMMAND_RESOLVE_PTR) {
socks_request_set_socks5_error(req,SOCKS5_COMMAND_NOT_SUPPORTED);
res = -1;
goto end;
}
if (req->command == SOCKS_COMMAND_RESOLVE_PTR &&
!string_is_valid_ipv4_address(req->address) &&
!string_is_valid_ipv6_address(req->address)) {
socks_request_set_socks5_error(req, SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
"hostname type. Rejecting.");
res = -1;
goto end;
}
if (!string_is_valid_dest(req->address)) {
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
log_warn(LD_PROTOCOL,
"Your application (using socks5 to port %d) gave Tor "
"a malformed hostname: %s. Rejecting the connection.",
req->port, escaped_safe_str_client(req->address));
res = -1;
goto end;;
}
if (req->socks5_atyp == 1 || req->socks5_atyp == 4) {
if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
!addressmap_have_mapping(req->address,0)) {
log_unsafe_socks_warning(5, req->address, req->port, safe_socks);
if (safe_socks) {
socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
res = -1;
goto end;
}
}
}
if (log_sockstype)
log_notice(LD_APP,
"Your application (using socks5 to port %d) instructed "
"Tor to take care of the DNS resolution itself if "
"necessary. This is good.", req->port);
end:
return res;
}
static int static int
handle_socks_message(const uint8_t *raw_data, size_t datalen, socks_request_t *req, handle_socks_message(const uint8_t *raw_data, size_t datalen, socks_request_t *req,
int log_sockstype, int safe_socks, size_t *drain_out) int log_sockstype, int safe_socks, size_t *drain_out)
{ {
int res = 0; int res = 1;
uint8_t socks_version = raw_data[0]; uint8_t socks_version = raw_data[0];
@ -497,8 +621,8 @@ handle_socks_message(const uint8_t *raw_data, size_t datalen, socks_request_t *r
goto end; goto end;
} }
/* RFC1929 SOCKS5 username/password subnegotiation. */ /* RFC1929 SOCKS5 username/password subnegotiation. */
if ((!req->got_auth && raw_data[0] == 1) || if (!req->got_auth && (raw_data[0] == 1 ||
req->auth_type == SOCKS_USER_PASS) { req->auth_type == SOCKS_USER_PASS)) {
int parse_status = parse_socks5_userpass_auth(raw_data, req, datalen, int parse_status = parse_socks5_userpass_auth(raw_data, req, datalen,
drain_out); drain_out);
@ -540,6 +664,23 @@ handle_socks_message(const uint8_t *raw_data, size_t datalen, socks_request_t *r
res = 0; res = 0;
goto end; goto end;
} else {
int parse_status = parse_socks5_client_request(raw_data, req,
datalen, drain_out);
if (parse_status != 1) {
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
res = parse_status;
goto end;
}
int process_status = process_socks5_client_request(req,
log_sockstype,
safe_socks);
if (process_status != 1) {
res = process_status;
goto end;
}
} }
} else { } else {
*drain_out = datalen; *drain_out = datalen;
@ -590,11 +731,10 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
goto end; goto end;
} }
buf_pullup(buf, datalen, &head, &datalen); // XXX
do { do {
n_drain = 0; n_drain = 0;
//buf_pullup(buf, want_length, &head, &datalen); buf_pullup(buf, MAX(want_length, buf_datalen(buf)),
&head, &datalen);
tor_assert(head && datalen >= 2); tor_assert(head && datalen >= 2);
want_length = 0; want_length = 0;
@ -605,10 +745,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
buf_clear(buf); buf_clear(buf);
else if (n_drain > 0) else if (n_drain > 0)
buf_drain(buf, n_drain); buf_drain(buf, n_drain);
} while (res == 0 && head && buf_datalen(buf) >= 2);
datalen = buf_datalen(buf);
} while (res == 0 && head && want_length < buf_datalen(buf) &&
buf_datalen(buf) >= 2);
end: end:
return res; return res;

View File

@ -53,6 +53,8 @@ struct socks_request_t {
/** The negotiated password value if any (for socks5). This value is NOT /** The negotiated password value if any (for socks5). This value is NOT
* nul-terminated; see passwordlen for its length. */ * nul-terminated; see passwordlen for its length. */
char *password; char *password;
uint8_t socks5_atyp; /* SOCKS5 address type */
}; };
#endif #endif

View File

@ -646,7 +646,8 @@ test_socks_5_malformed_commands(void *ptr)
tt_int_op(5,OP_EQ,socks->socks_version); tt_int_op(5,OP_EQ,socks->socks_version);
tt_int_op(10,OP_EQ,socks->replylen); tt_int_op(10,OP_EQ,socks->replylen);
tt_int_op(5,OP_EQ,socks->reply[0]); tt_int_op(5,OP_EQ,socks->reply[0]);
tt_int_op(SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED,OP_EQ,socks->reply[1]); /* trunnel parsing will fail with -1 */
tt_int_op(SOCKS5_GENERAL_ERROR,OP_EQ,socks->reply[1]);
tt_int_op(1,OP_EQ,socks->reply[3]); tt_int_op(1,OP_EQ,socks->reply[3]);
done: done: