// SOCKS Proxy support static enum proxy_status proxy_connect(struct host *h, const char *target_host, int target_port) { struct addrinfo target_hints, *target_ais, *target_ai; char port_str[6]; int ret; snprintf(port_str, 6, "%d", target_port); port_str[5] = 0; memset(&target_hints, 0, sizeof(struct addrinfo)); target_hints.ai_socktype = (h->proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM; target_hints.ai_protocol = h->proto; target_hints.ai_family = h->af; ret = dns_getaddrinfo(target_host, port_str, &target_hints, &target_ais, h->timeout_ms); /* Some perimeter gateways block access to DNS [wifi hotspots are * particularly notorious for this] so we have to fall back to SOCKS4a * to force the proxy to DNS the address for us. If this fails, we abort. */ if(ret != 0) return socks4a_connect(h, target_host, target_port); #ifdef CONFIG_IPV6 for(target_ai = target_ais; target_ai; target_ai = target_ai->ai_next) { if(target_ai->ai_family != AF_INET6) continue; if (socks5_connect(h, target_ai) == PROXY_SUCCESS) { platform_freeaddrinfo(target_ais); return PROXY_SUCCESS; } } #endif for(target_ai = target_ais; target_ai; target_ai = target_ai->ai_next) { if(target_ai->ai_family != AF_INET) continue; if (socks5_connect(h, target_ai) == PROXY_SUCCESS) { platform_freeaddrinfo(target_ais); return PROXY_SUCCESS; } if (socks4_connect(h, target_ai) == PROXY_SUCCESS) { platform_freeaddrinfo(target_ais); return PROXY_SUCCESS; } } return PROXY_CONNECTION_FAILED; }
/* * Setup a Tor connection meaning initiating the initial SOCKS5 handshake. * * Return 0 on success else a negative value. */ static int setup_tor_connection(struct connection *conn) { int ret; assert(conn); DBG("Setting up a connection to the Tor network on fd %d", conn->fd); ret = socks5_connect(conn); if (ret < 0) { goto error; } ret = socks5_send_method(conn); if (ret < 0) { goto error; } ret = socks5_recv_method(conn); if (ret < 0) { goto error; } error: return ret; }
int handle_socks(int fd, struct sockaddr_in addr, char *host, int portnum) { struct sockaddr_in proxy; struct hostent *hp; memset(&proxy, 0, sizeof(proxy)); if (!(hp = gethostbyname(host))) { bitchsay("Unable to resolve SOCKS proxy host address: %s", host); return -1; } bcopy(hp->h_addr, (char *)&proxy.sin_addr, hp->h_length); proxy.sin_family = AF_INET; proxy.sin_port = htons(portnum); alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect(fd, (struct sockaddr *)&proxy, sizeof(proxy)) < 0) { alarm(0); bitchsay("Unable to connect to SOCKS5 proxy: %s", strerror(errno)); close(fd); return -1; } alarm(0); if (!socks5_connect(fd, portnum, &addr)) { close(fd); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { bitchsay("Unable to get socket: %s", strerror(errno)); return -1; } alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect(fd, (struct sockaddr *)&proxy, sizeof(proxy)) < 0) { alarm(0); bitchsay("Unable to connect to SOCKS4 proxy: %s", strerror(errno)); return -1; } alarm(0); if (!socks4_connect(fd, portnum, &addr)) { close(fd); return -1; } } return fd; }
jb_socket connect_to_forward(struct client_state *csp, struct forward_spec *fwd, int is_proxy) { csp->fwd = fwd; const char *dest_host; int dest_port; /* Figure out if we need to connect to the web server or a HTTP proxy. */ if (fwd->forward_host) { /* HTTP proxy */ dest_host = fwd->forward_host; dest_port = fwd->forward_port; } else { /* Web server */ dest_host = csp->http->host; dest_port = csp->http->port; } /* Connect, maybe using a SOCKS proxy */ switch (fwd->type) { case SOCKS_NONE: case FORWARD_WEBSERVER: return connect_to(dest_host, dest_port, csp, is_proxy); break; case SOCKS_4: case SOCKS_4A: return socks4_connect(fwd->gateway_host, fwd->gateway_port, fwd->type, dest_host, dest_port, csp); break; case SOCKS_5: case SOCKS_5T: return socks5_connect(fwd->gateway_host, fwd->gateway_port, fwd->type, dest_host, dest_port, csp); break; default: log_error(LOG_LEVEL_FATAL, "Internal error in rfc2553_connect_to() ip. Bad proxy type: %d", fwd->type); return JB_INVALID_SOCKET; } }
gint socks_connect(SockInfo *sock, const gchar *hostname, gushort port, SocksInfo *socks_info) { g_return_val_if_fail(sock != NULL, -1); g_return_val_if_fail(hostname != NULL, -1); g_return_val_if_fail(socks_info != NULL, -1); debug_print("socks_connect: connect to %s:%u via %s:%u\n", hostname, port, socks_info->proxy_host, socks_info->proxy_port); if (socks_info->type == SOCKS_SOCKS5) return socks5_connect(sock, hostname, port, socks_info->proxy_name, socks_info->proxy_pass); else if (socks_info->type == SOCKS_SOCKS4) return socks4_connect(sock, hostname, port); else g_warning("socks_connect: unknown SOCKS type: %d\n", socks_info->type); return -1; }
int socks5_negotiate(int clisock, struct conndesc *conn) { u_int i; char hostname[256]; u_char nmethods, len, junk; struct sockaddr_in rem_in; struct socks5_req req5; struct socks5_v_repl rep5; struct hostent *hent; req5.vn = 5; req5.rsv = 0; /* * Start by retrieving number of methods, version number has * already been consumed by the calling procedure */ if (atomicio(read, clisock, &nmethods, 1) != 1) { warnv(1, "read()"); return (-1); } /* Eat up methods */ i = 0; while (i++ < nmethods) if (atomicio(read, clisock, &junk, 1) != 1) { warnv(1, "read()"); return (-1); } /* * We don't support any authentication methods yet, so simply * ignore it and send reply with no authentication required. */ rep5.ver = 5; rep5.res = 0; if (atomicio(write, clisock, &rep5, 2) != 2) { warnv(1, "write()"); return (-1); } /* Receive data up to atyp */ if (atomicio(read, clisock, &req5, 4) != 4) { warnv(1, "read()"); return (-1); } if (req5.vn != 5) return (-1); memset(&rem_in, 0, sizeof(rem_in)); switch (req5.atyp) { case SOCKS5_ATYP_IPV4: if (atomicio(read, clisock, &req5.destaddr, 4) != 4) { warnv(1, "read()"); return (-1); } rem_in.sin_family = AF_INET; rem_in.sin_addr.s_addr = req5.destaddr; break; case SOCKS5_ATYP_FQDN: if (atomicio(read, clisock, &len, 1) != 1) { warnv(1, "read()"); return (-1); } if (atomicio(read, clisock, hostname, len) != len) { warnv(1, "read()"); return (-1); } hostname[len] = '\0'; if ((hent = gethostbyname(hostname)) == NULL) { /* XXX no hstrerror() on solaris */ #ifndef __sun__ warnxv(1, "gethostbyname(): %s", hstrerror(h_errno)); #endif /* __sun__ */ return (-1); } rem_in.sin_family = AF_INET; rem_in.sin_addr = *(struct in_addr *)hent->h_addr; break; default: return (-1); } if (atomicio(read, clisock, &req5.destport, 2) != 2) { warnv(1, "read()"); return (-1); } rem_in.sin_port = req5.destport; /* * Now we have a filled in in_addr for the target host: * target_in, no socket yet. This is provided by the command * specific functions multiplexed in the next switch * statement. */ switch (req5.cd) { case SOCKS5_CD_CONNECT: return (socks5_connect(clisock, &rem_in, &req5, conn)); case SOCKS5_CD_BIND: signal_setup(); event_dispatch(); return (socks5_bind(clisock, &rem_in, &req5)); case SOCKS5_CD_UDP_ASSOC: default: return (-1); } }