summaryrefslogtreecommitdiff
path: root/src/or/buffers.c
diff options
context:
space:
mode:
authorChristopher Davis <chrisd@mangrin.org>2009-06-18 16:59:18 -0700
committerNick Mathewson <nickm@torproject.org>2009-06-19 12:16:15 -0400
commit75472c19c3fdcda913eb8117c917ddfd445b2b77 (patch)
treed295a53d398b09d01e6e9c5fbcfd5a750a702471 /src/or/buffers.c
parentaa6dc9cf97eb3ab1a2578efb1b797f35adc3d3b2 (diff)
downloadtor-75472c19c3fdcda913eb8117c917ddfd445b2b77.tar.gz
tor-75472c19c3fdcda913eb8117c917ddfd445b2b77.zip
Enable Tor to connect through SOCKS 4/5 proxies
Added a sanity check in config.c and a check in directory.c directory_initiate_command_rend() to catch any direct connection attempts when a socks proxy is configured.
Diffstat (limited to 'src/or/buffers.c')
-rw-r--r--src/or/buffers.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index ed39bc0f82..31725c5f27 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1611,6 +1611,177 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
}
}
+/** Inspect a reply from SOCKS server stored in <b>buf</b> according
+ * to <b>state</b>, removing the protocol data upon success. Return 0 on
+ * incomplete response, 1 on success and -1 on error, in which case
+ * <b>reason</b> is set to a descriptive message (free() when finished
+ * with it).
+ *
+ * As a special case, 2 is returned when user/pass is required
+ * during SOCKS5 handshake and user/pass is configured.
+ */
+int
+fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
+{
+ unsigned char *data;
+ size_t addrlen;
+
+ if (buf->datalen < 2)
+ return 0;
+
+ buf_pullup(buf, 128, 0);
+ tor_assert(buf->head && buf->head->datalen >= 2);
+
+ data = (unsigned char *) buf->head->data;
+
+ switch (state) {
+ case PROXY_SOCKS4_WANT_CONNECT_OK:
+ /* Wait for the complete response */
+ if (buf->head->datalen < 8)
+ return 0;
+
+ if (data[1] != 0x5a) {
+ switch (data[1]) {
+ case 0x5b:
+ *reason = tor_strdup("server rejected connection");
+ break;
+ case 0x5c:
+ *reason = tor_strdup("server cannot connect to identd "
+ "on this client");
+ break;
+ case 0x5d:
+ *reason = tor_strdup("user id does not match identd");
+ break;
+ default:
+ *reason = tor_strdup("invalid SOCKS 4 response code");
+ break;
+ }
+
+ return -1;
+ }
+
+ /* Success */
+ buf_remove_from_front(buf, 8);
+ return 1;
+
+ case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
+ /* we don't have any credentials */
+ if (data[1] != 0x00) {
+ *reason = tor_strdup("server doesn't support any of our "
+ "available authentication methods");
+ return -1;
+ }
+
+ log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
+ buf_clear(buf);
+ return 1;
+
+ case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
+ /* we have a username and password. return 1 if we can proceed without
+ * providing authentication, or 2 otherwise. */
+ switch (data[1]) {
+ case 0x00:
+ log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
+ "doesn't require authentication.");
+ buf_clear(buf);
+ return 1;
+ case 0x02:
+ log_info(LD_NET, "SOCKS 5 client: need authentication.");
+ buf_clear(buf);
+ return 2;
+ /* fall through */
+ }
+
+ *reason = tor_strdup("server doesn't support any of our available "
+ "authentication methods");
+ return -1;
+
+ case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
+ /* handle server reply to rfc1929 authentication */
+ if (data[1] != 0x00) {
+ *reason = tor_strdup("authentication failed");
+ return -1;
+ }
+
+ log_info(LD_NET, "SOCKS 5 client: authentication successful.");
+ buf_clear(buf);
+ return 1;
+
+ case PROXY_SOCKS5_WANT_CONNECT_OK:
+ /* response is variable length. BND.ADDR, etc, isn't needed
+ * (don't bother with buf_pullup()), but make sure to eat all
+ * the data used */
+
+ /* wait for address type field to arrive */
+ if (buf->datalen < 4)
+ return 0;
+
+ switch (data[3]) {
+ case 0x01: /* ip4 */
+ addrlen = 4;
+ break;
+ case 0x04: /* ip6 */
+ addrlen = 16;
+ break;
+ case 0x03: /* fqdn (can this happen here?) */
+ if (buf->datalen < 5)
+ return 0;
+ addrlen = 1 + data[4];
+ break;
+ default:
+ *reason = tor_strdup("invalid response to connect request");
+ return -1;
+ }
+
+ /* wait for address and port */
+ if (buf->datalen < 6 + addrlen)
+ return 0;
+
+ if (data[1] != 0x00) {
+
+ switch (data[1]) {
+ case 0x01:
+ *reason = tor_strdup("general SOCKS server failure");
+ break;
+ case 0x02:
+ *reason = tor_strdup("connection not allowed by ruleset");
+ break;
+ case 0x03:
+ *reason = tor_strdup("Network unreachable");
+ break;
+ case 0x04:
+ *reason = tor_strdup("Host unreachable");
+ break;
+ case 0x05:
+ *reason = tor_strdup("Connection refused");
+ break;
+ case 0x06:
+ *reason = tor_strdup("TTL expired");
+ break;
+ case 0x07:
+ *reason = tor_strdup("Command not supported");
+ break;
+ case 0x08:
+ *reason = tor_strdup("Address type not supported");
+ break;
+ default:
+ *reason = tor_strdup("unknown reason");
+ break;
+ }
+
+ return -1;
+ }
+
+ buf_remove_from_front(buf, 6 + addrlen);
+ return 1;
+ }
+
+ /* shouldn't get here... */
+ tor_assert(0);
+
+ return -1;
+}
+
/** Return 1 iff buf looks more like it has an (obsolete) v0 controller
* command on it than any valid v1 controller command. */
int