diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 12130b5..8853dd8 100644 --- a/src/allocator_thread.c +++ b/src/allocator_thread.c @@ -38,16 +38,16 @@ pthread_mutex_t internal_ips_lock; internal_ip_lookup_table *internal_ips = NULL; internal_ip_lookup_table internal_ips_buf; -uint32_t index_from_internal_ip(ip_type internalip) { +uint32_t index_from_internal_ip(ip_type4 internalip) { PFUNC(); - ip_type tmp = internalip; + ip_type4 tmp = internalip; uint32_t ret; ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); ret -= 1; return ret; } -char *string_from_internal_ip(ip_type internalip) { +char *string_from_internal_ip(ip_type4 internalip) { PFUNC(); char *res = NULL; uint32_t index = index_from_internal_ip(internalip); @@ -57,11 +57,11 @@ char *string_from_internal_ip(ip_type internalip) { } extern unsigned int remote_dns_subnet; -ip_type make_internal_ip(uint32_t index) { - ip_type ret; +ip_type4 make_internal_ip(uint32_t index) { + ip_type4 ret; index++; // so we can start at .0.0.1 if(index > 0xFFFFFF) - return ip_type_invalid; + return ip_type_invalid.addr.v4; ret.octet[0] = remote_dns_subnet & 0xFF; ret.octet[1] = (index & 0xFF0000) >> 16; ret.octet[2] = (index & 0xFF00) >> 8; @@ -69,10 +69,10 @@ ip_type make_internal_ip(uint32_t index) { return ret; } -static ip_type ip_from_internal_list(char* name, size_t len) { +static ip_type4 ip_from_internal_list(char* name, size_t len) { uint32_t hash = dalias_hash((char *) name); size_t i; - ip_type res; + ip_type4 res; void* new_mem; // see if we already have this dns entry saved. if(internal_ips->counter) { @@ -99,7 +99,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) { } res = make_internal_ip(internal_ips->counter); - if(res.as_int == ip_type_invalid.as_int) + if(res.as_int == ip_type_invalid.addr.v4.as_int) goto err_plus_unlock; string_hash_tuple tmp = { 0 }; @@ -128,7 +128,7 @@ static ip_type ip_from_internal_list(char* name, size_t len) { err_plus_unlock: PDEBUG("return err\n"); - return ip_type_invalid; + return ip_type_invalid.addr.v4; } /* stuff for communication with the allocator thread */ @@ -205,7 +205,7 @@ static void* threadfunc(void* x) { struct at_msghdr msg; union { char host[MSG_LEN_MAX]; - ip_type ip; + ip_type4 ip; } readbuf; while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) { switch(msg.msgtype) { @@ -213,7 +213,7 @@ static void* threadfunc(void* x) { /* client wants an ip for a DNS name. iterate our list and check if we have an existing entry. * if not, create a new one. */ readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1); - msg.datalen = sizeof(ip_type); + msg.datalen = sizeof(ip_type4); break; case ATM_GETNAME: { char *host = string_from_internal_ip(readbuf.ip); @@ -237,8 +237,8 @@ static void* threadfunc(void* x) { /* API to access the internal ip mapping */ -ip_type at_get_ip_for_host(char* host, size_t len) { - ip_type readbuf; +ip_type4 at_get_ip_for_host(char* host, size_t len) { + ip_type4 readbuf; MUTEX_LOCK(&internal_ips_lock); if(len > MSG_LEN_MAX) goto inv; struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 }; @@ -246,14 +246,14 @@ ip_type at_get_ip_for_host(char* host, size_t len) { getmessage(ATD_CLIENT, &msg, &readbuf)); else { inv: - readbuf = ip_type_invalid; + readbuf = ip_type_invalid.addr.v4; } MUTEX_UNLOCK(&internal_ips_lock); return readbuf; } -size_t at_get_host_for_ip(ip_type ip, char* readbuf) { - struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type) }; +size_t at_get_host_for_ip(ip_type4 ip, char* readbuf) { + struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type4) }; size_t res = 0; MUTEX_LOCK(&internal_ips_lock); if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) { diff --git a/src/allocator_thread.h b/src/allocator_thread.h index cfa9866..734ed89 100644 --- a/src/allocator_thread.h +++ b/src/allocator_thread.h @@ -11,8 +11,8 @@ extern int resp_pipefd[2]; void at_init(void); void at_close(void); -size_t at_get_host_for_ip(ip_type ip, char* readbuf); -ip_type at_get_ip_for_host(char* host, size_t len); +size_t at_get_host_for_ip(ip_type4 ip, char* readbuf); +ip_type4 at_get_ip_for_host(char* host, size_t len); //RcB: DEP "allocator_thread.c" #endif diff --git a/src/core.c b/src/core.c index a6feb1b..ea6417f 100644 --- a/src/core.c +++ b/src/core.c @@ -198,8 +198,8 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c // the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with // the results returned from gethostbyname et al.) // the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127 - if(ip.octet[0] == remote_dns_subnet) { - dns_len = at_get_host_for_ip(ip, hostnamebuf); + if(!ip.is_v6 && ip.addr.v4.octet[0] == remote_dns_subnet) { + dns_len = at_get_host_for_ip(ip.addr.v4, hostnamebuf); if(!dns_len) goto err; else dns_name = hostnamebuf; } @@ -216,12 +216,16 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c int len; unsigned char buff[BUFF_SIZE]; - char ip_buf[16]; + char ip_buf[INET6_ADDRSTRLEN]; + int v6 = ip.is_v6; switch (pt) { case HTTP_TYPE:{ if(!dns_len) { - pc_stringfromipv4(&ip.octet[0], ip_buf); + if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) { + proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n"); + goto err; + } dns_name = ip_buf; } #define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */ @@ -264,16 +268,20 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c } break; case SOCKS4_TYPE:{ + if(v6) { + proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesnt support ipv6 addresses\n"); + goto err; + } buff[0] = 4; // socks version buff[1] = 1; // connect command memcpy(&buff[2], &port, 2); // dest port if(dns_len) { - ip.octet[0] = 0; - ip.octet[1] = 0; - ip.octet[2] = 0; - ip.octet[3] = 1; + ip.addr.v4.octet[0] = 0; + ip.addr.v4.octet[1] = 0; + ip.addr.v4.octet[2] = 0; + ip.addr.v4.octet[3] = 1; } - memcpy(&buff[4], &ip, 4); // dest host + memcpy(&buff[4], &ip.addr.v4, 4); // dest host len = ulen + 1; // username if(len > 1) memcpy(&buff[8], user, len); @@ -353,9 +361,9 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c buff[buff_iter++] = 0; // reserved if(!dns_len) { - buff[buff_iter++] = 1; // ip v4 - memcpy(buff + buff_iter, &ip, 4); // dest host - buff_iter += 4; + buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6 + memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host + buff_iter += v6?16:4; } else { buff[buff_iter++] = 3; //dns buff[buff_iter++] = dns_len & 0xFF; @@ -411,21 +419,30 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c #define RRT "Round Robin chain" static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { - *fd = socket(PF_INET, SOCK_STREAM, 0); + int v6 = pd->ip.is_v6; + + *fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0); if(*fd == -1) goto error; - char ip_buf[16]; - pc_stringfromipv4(&pd->ip.octet[0], ip_buf); + char ip_buf[INET6_ADDRSTRLEN]; + if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf)) + goto error; + proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ", begin_mark, ip_buf, htons(pd->port)); pd->ps = PLAY_STATE; struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = pd->port, - .sin_addr.s_addr = (in_addr_t) pd->ip.as_int + .sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int }; - if(timed_connect(*fd, (struct sockaddr *) &addr, sizeof(addr))) { + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = pd->port, + }; + if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16); + if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) { pd->ps = DOWN_STATE; goto error1; } @@ -496,16 +513,22 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { int retcode = -1; char *hostname; char hostname_buf[MSG_LEN_MAX]; - char ip_buf[16]; + char ip_buf[INET6_ADDRSTRLEN]; + int v6 = pto->ip.is_v6; PFUNC(); - if(pto->ip.octet[0] == remote_dns_subnet) { - if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip; + if(!v6 && pto->ip.addr.v4.octet[0] == remote_dns_subnet) { + if(!at_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip; else hostname = hostname_buf; } else { usenumericip: - pc_stringfromipv4(&pto->ip.octet[0], ip_buf); + if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) { + pto->ps = DOWN_STATE; + proxychains_write_log("<--ip conversion error!\n"); + close(ns); + return SOCKET_ERROR; + } hostname = ip_buf; } @@ -707,7 +730,7 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* data->hostent_space.h_name = data->addr_name; } -extern ip_type hostsreader_get_numeric_ip_for_name(const char* name); +extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name); struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) { PFUNC(); char buff[256]; @@ -728,19 +751,19 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* if(!strcmp(buff, name)) { data->resolved_addr = inet_addr(buff); if(data->resolved_addr == (in_addr_t) (-1)) - data->resolved_addr = (in_addr_t) (ip_type_localhost.as_int); + data->resolved_addr = (in_addr_t) (ip_type_localhost.addr.v4.as_int); goto retname; } // this iterates over the "known hosts" db, usually /etc/hosts - ip_type hdb_res = hostsreader_get_numeric_ip_for_name(name); - if(hdb_res.as_int != ip_type_invalid.as_int) { + ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name); + if(hdb_res.as_int != ip_type_invalid.addr.v4.as_int) { data->resolved_addr = hdb_res.as_int; goto retname; } data->resolved_addr = at_get_ip_for_host((char*) name, strlen(name)).as_int; - if(data->resolved_addr == (in_addr_t) ip_type_invalid.as_int) return NULL; + if(data->resolved_addr == (in_addr_t) ip_type_invalid.addr.v4.as_int) return NULL; retname: diff --git a/src/hostsreader.c b/src/hostsreader.c index dcfaa47..6589f9f 100644 --- a/src/hostsreader.c +++ b/src/hostsreader.c @@ -73,16 +73,16 @@ char* hostsreader_get_ip_for_name(const char* name, char* buf, size_t bufsize) { #include #include #include -ip_type hostsreader_get_numeric_ip_for_name(const char* name) { +ip_type4 hostsreader_get_numeric_ip_for_name(const char* name) { char *hres; char buf[320]; if((hres = hostsreader_get_ip_for_name(name, buf, sizeof buf))) { struct in_addr c; inet_aton(hres, &c); - ip_type res; + ip_type4 res; memcpy(res.octet, &c.s_addr, 4); return res; - } else return ip_type_invalid; + } else return ip_type_invalid.addr.v4; } #ifdef HOSTSREADER_TEST diff --git a/src/ip_type.c b/src/ip_type.c index 9a6f256..8b4e044 100644 --- a/src/ip_type.c +++ b/src/ip_type.c @@ -1,5 +1,5 @@ #include "ip_type.h" -const ip_type ip_type_invalid = { .as_int = -1 }; -const ip_type ip_type_localhost = { {127, 0, 0, 1} }; +const ip_type ip_type_invalid = { .addr.v4.as_int = -1 }; +const ip_type ip_type_localhost = { .addr.v4 = {127, 0, 0, 1} }; diff --git a/src/ip_type.h b/src/ip_type.h index 62b915e..064153e 100644 --- a/src/ip_type.h +++ b/src/ip_type.h @@ -6,6 +6,14 @@ typedef union { unsigned char octet[4]; uint32_t as_int; +} ip_type4; + +typedef struct { + union { + ip_type4 v4; + unsigned char v6[16]; + } addr; + char is_v6; } ip_type; extern const ip_type ip_type_invalid; diff --git a/src/libproxychains.c b/src/libproxychains.c index e78f22c..f5580b9 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -189,13 +189,14 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ exit(1); } - in_addr_t host_ip = inet_addr(host); - if(host_ip == INADDR_NONE) { + memset(&pd[count].ip, 0, sizeof(pd[count].ip)); + pd[count].ip.is_v6 = !!strchr(host, ':'); + pd[count].port = htons((unsigned short) port_n); + ip_type* host_ip = &pd[count].ip; + if(1 != inet_pton(host_ip->is_v6 ? AF_INET6 : AF_INET, host, host_ip->addr.v6)) { fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host); exit(1); } - pd[count].ip.as_int = (uint32_t) host_ip; - pd[count].port = htons((unsigned short) port_n); if(!strcmp(type, "http")) { pd[count].pt = HTTP_TYPE; @@ -206,7 +207,7 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ } else goto inv; - if(pd[count].ip.as_int && port_n && pd[count].ip.as_int != (uint32_t) - 1) + if(port_n) count++; } else { if(strstr(buff, "[ProxyList]")) { @@ -317,26 +318,32 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) { DEBUGDECL(char str[256]); struct in_addr *p_addr_in; + struct in6_addr *p_addr_in6; unsigned short port; size_t i; int remote_dns_connect = 0; optlen = sizeof(socktype); + sa_family_t fam = SOCKFAMILY(*addr); getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); - if(!(SOCKFAMILY(*addr) == AF_INET && socktype == SOCK_STREAM)) + if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM)) return true_connect(sock, addr, len); + int v6 = dest_ip.is_v6 = fam == AF_INET6; + p_addr_in = &((struct sockaddr_in *) addr)->sin_addr; - port = ntohs(((struct sockaddr_in *) addr)->sin_port); + p_addr_in6 = &((struct sockaddr_in6 *) addr)->sin6_addr; + port = !v6 ? ntohs(((struct sockaddr_in *) addr)->sin_port) + : ntohs(((struct sockaddr_in6 *) addr)->sin6_port); // PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str))); // PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str))); - PDEBUG("target: %s\n", inet_ntop(AF_INET, p_addr_in, str, sizeof(str))); + PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? p_addr_in6 : p_addr_in, str, sizeof(str))); PDEBUG("port: %d\n", port); // check if connect called from proxydns - remote_dns_connect = (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); + remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); - for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { + if (!v6) for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { if((localnet_addr[i].in_addr.s_addr & localnet_addr[i].netmask.s_addr) == (p_addr_in->s_addr & localnet_addr[i].netmask.s_addr)) { if(!localnet_addr[i].port || localnet_addr[i].port == port) { @@ -350,11 +357,11 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) { if(flags & O_NONBLOCK) fcntl(sock, F_SETFL, !O_NONBLOCK); - dest_ip.as_int = SOCKADDR(*addr); + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); ret = connect_proxy_chain(sock, dest_ip, - SOCKPORT(*addr), + htons(port), proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain); fcntl(sock, F_SETFL, flags);