summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrl1987 <rl1987@sdf.lonestar.org>2018-05-15 15:13:13 +0200
committerNick Mathewson <nickm@torproject.org>2018-07-12 11:40:49 -0400
commit27333b2298a17fc85b4d2a6c07c9c889d6bdabed (patch)
treeb4c8869352722d5e244df11abdafcc93f251c525
parentc6a0b04d33f5d2cdb8207672c18b06d689ecd1df (diff)
downloadtor-27333b2298a17fc85b4d2a6c07c9c889d6bdabed.tar.gz
tor-27333b2298a17fc85b4d2a6c07c9c889d6bdabed.zip
Reimplement phase 1 of SOCKS5 using trunnel
squash! Reimplement phase 1 of SOCKS5 using trunnel
-rw-r--r--src/or/proto_socks.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/or/proto_socks.c b/src/or/proto_socks.c
index 4fdc33d1d4..e9ea453fa2 100644
--- a/src/or/proto_socks.c
+++ b/src/or/proto_socks.c
@@ -227,6 +227,121 @@ process_socks4_request(const socks_request_t *req, int is_socks4a,
return 1;
}
+static int
+parse_socks5_methods_request(const uint8_t *raw_data, socks_request_t *req,
+ size_t datalen, int *have_user_pass,
+ int *have_no_auth, size_t *drain_out)
+{
+ int res = 1;
+ socks5_client_version_t *trunnel_req;
+
+ ssize_t parsed = socks5_client_version_parse(&trunnel_req, raw_data,
+ datalen);
+
+ (void)req;
+
+ tor_assert(have_no_auth);
+ tor_assert(have_user_pass);
+ tor_assert(drain_out);
+
+ *drain_out = 0;
+
+ if (parsed == -1) {
+ log_warn(LD_APP, "socks5: parsing failed - invalid version "
+ "id/method selection message.");
+ res = -1;
+ goto end;
+ } else if (parsed == -2) {
+ res = 0;
+ if (datalen > 1024) { // XXX
+ log_warn(LD_APP, "socks5: parsing failed - invalid version "
+ "id/method selection message.");
+ res = -1;
+ }
+ goto end;
+ }
+
+ size_t n_methods = (size_t)socks5_client_version_get_n_methods(trunnel_req);
+ if (n_methods == 0) {
+ res = -1;
+ goto end;
+ }
+
+ *have_no_auth = 0;
+ *have_user_pass = 0;
+
+ for (size_t i = 0; i < n_methods; i++) {
+ uint8_t method = socks5_client_version_get_methods(trunnel_req,
+ i);
+
+ if (method == SOCKS_USER_PASS) {
+ *have_user_pass = 1;
+ } else if (method == SOCKS_NO_AUTH) {
+ *have_no_auth = 1;
+ }
+ }
+
+ end:
+ *drain_out = (size_t)parsed;
+ socks5_client_version_free(trunnel_req);
+
+ return res;
+}
+
+static int
+process_socks5_methods_request(socks_request_t *req, int have_user_pass,
+ int have_no_auth)
+{
+ int res = 0;
+ socks5_server_method_t *trunnel_resp = socks5_server_method_new();
+
+ socks5_server_method_set_version(trunnel_resp, 5);
+
+ if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) {
+ req->auth_type = SOCKS_USER_PASS;
+ socks5_server_method_set_method(trunnel_resp, SOCKS_USER_PASS);
+
+ req->socks_version = 5; // FIXME: come up with better way to remember
+ // that we negotiated auth
+
+ log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
+ } else if (have_no_auth) {
+ req->auth_type = SOCKS_NO_AUTH;
+ socks5_server_method_set_method(trunnel_resp, SOCKS_NO_AUTH);
+
+ req->socks_version = 5;
+
+ log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
+ } else {
+ log_warn(LD_APP,
+ "socks5: offered methods don't include 'no auth' or "
+ "username/password. Rejecting.");
+ socks5_server_method_set_method(trunnel_resp, 0xFF); // reject all
+ res = -1;
+ }
+
+ const char *errmsg = socks5_server_method_check(trunnel_resp);
+ if (errmsg) {
+ log_warn(LD_APP, "socks5: method selection validation failed: %s",
+ errmsg);
+ res = -1;
+ } else {
+ ssize_t encoded =
+ socks5_server_method_encode(req->reply, sizeof(req->reply),
+ trunnel_resp);
+
+ if (encoded < 0) {
+ log_warn(LD_APP, "socks5: method selection encoding failed");
+ res = -1;
+ } else {
+ req->replylen = (size_t)encoded;
+ }
+ }
+
+ socks5_server_method_free(trunnel_resp);
+ return res;
+}
+
/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
* of the forms
* - socks4: "socksheader username\\0"
@@ -259,6 +374,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
int res = 0;
size_t datalen = buf_datalen(buf);
uint8_t *raw_data;
+ uint8_t *raw_ptr;
uint8_t socks_version;
raw_data = tor_malloc(datalen);
@@ -266,6 +382,8 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
buf_peek(buf, (char *)raw_data, datalen);
+ raw_ptr = raw_data;
+
socks_version = (uint8_t)raw_data[0];
if (socks_version == 4) {
@@ -296,6 +414,45 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
buf_clear(buf);
res = 1;
goto end;
+ } else if (socks_version == 5) {
+ if (datalen < 2) { /* version and another byte */
+ res = 0;
+ goto end;
+ }
+
+ if (!req->got_auth) {
+
+ }
+
+ if (req->socks_version != 5) {
+ int have_user_pass, have_no_auth;
+ int parse_status = parse_socks5_methods_request(raw_data,
+ req,
+ datalen,
+ &have_user_pass,
+ &have_no_auth,
+ drain_out);
+
+ if (parse_status != 1) {
+ res = parse_status;
+ goto end;
+ }
+
+ int process_status = process_socks5_methods_request(req,
+ have_user_pass,
+ have_no_auth);
+
+ if (process_status == -1) {
+ res = process_status;
+ goto end;
+ }
+
+ buf_drain(buf, n_drain); // TODO: do it like this for SOCKS4/4a as well
+ raw_ptr += n_drain;
+ datalen -= n_drain;
+ res = 0;
+ goto end;
+ }
}
ssize_t n_drain;