diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 66cf7f6..4638b0a 100644 --- a/src/allocator_thread.c +++ b/src/allocator_thread.c @@ -174,7 +174,7 @@ static int trywrite(int fd, void* buf, size_t bytes) { ssize_t ret; unsigned char *out = buf; again: - ret = write(fd, out, bytes); + ret = true_write(fd, out, bytes); switch(ret) { case -1: if(errno == EINTR) goto again; @@ -200,7 +200,7 @@ static int tryread(int fd, void* buf, size_t bytes) { ssize_t ret; unsigned char *out = buf; again: - ret = read(fd, out, bytes); + ret = true_read(fd, out, bytes); switch(ret) { case -1: if(errno == EINTR) goto again; @@ -350,11 +350,11 @@ void at_init(void) { void at_close(void) { PFUNC(); const int msg = ATM_EXIT; - write(req_pipefd[1], &msg, sizeof(int)); + true_write(req_pipefd[1], &msg, sizeof(int)); pthread_join(allocator_thread, NULL); - close(req_pipefd[0]); - close(req_pipefd[1]); - close(resp_pipefd[0]); - close(resp_pipefd[1]); + true_close(req_pipefd[0]); + true_close(req_pipefd[1]); + true_close(resp_pipefd[0]); + true_close(resp_pipefd[1]); MUTEX_DESTROY(internal_ips_lock); } diff --git a/src/core.c b/src/core.c index bd7691b..cd50acf 100644 --- a/src/core.c +++ b/src/core.c @@ -122,7 +122,7 @@ static int write_n_bytes(int fd, char *buff, size_t size) { int i = 0; size_t wrote = 0; for(;;) { - i = write(fd, &buff[wrote], size - wrote); + i = true_write(fd, &buff[wrote], size - wrote); if(i <= 0) return i; wrote += i; @@ -141,7 +141,7 @@ static int read_n_bytes(int fd, char *buff, size_t size) { for(i = 0; i < size; i++) { pfd[0].revents = 0; ready = poll_retry(pfd, 1, tcp_read_time_out); - if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1)) + if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != true_read(fd, &buff[i], 1)) return -1; } return (int) size; @@ -250,7 +250,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c ulen ? "Proxy-Authorization: Basic " : dst, dst, ulen ? "\r\n" : dst); - if(len < 0 || len != send(sock, buff, len, 0)) + if(len < 0 || len != true_send(sock, buff, len, 0)) goto err; len = 0; @@ -423,13 +423,536 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c return SOCKET_ERROR; } + +/* Given a socket connected to a SOCKS5 proxy server, performs a UDP_ASSOCIATE handshake and returns BND_ADDR and BND_PORT if successfull. +Pass NULL dst_addr and dst_port to fill those fields with 0 if expected local addr and port for udp sending are unknown (see RFC1928) */ +static int udp_associate(int sock, ip_type* dst_addr, unsigned short dst_port, ip_type* bnd_addr, unsigned short* bnd_port, char* user, char* pass){ + + PFUNC(); + + size_t ulen = strlen(user); + size_t passlen = strlen(pass); + + if(ulen > 0xFF || passlen > 0xFF) { + proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass!\n"); + goto err; + } + + int len; + unsigned char buff[BUFF_SIZE]; + char ip_buf[INET6_ADDRSTRLEN]; + + int n_methods = ulen ? 2 : 1; + buff[0] = 5; // version + buff[1] = n_methods ; // number of methods + buff[2] = 0; // no auth method + if(ulen) buff[3] = 2; /// auth method -> username / password + if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods)) + goto err; + + if(2 != read_n_bytes(sock, (char *) buff, 2)) + goto err; + + if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) { + if(buff[0] == 5 && buff[1] == 0xFF) + return BLOCKED; + else + goto err; + } + + if(buff[1] == 2) { + // authentication + char in[2]; + char out[515]; + char *cur = out; + size_t c; + *cur++ = 1; // version + c = ulen & 0xFF; + *cur++ = c; + memcpy(cur, user, c); + cur += c; + c = passlen & 0xFF; + *cur++ = c; + memcpy(cur, pass, c); + cur += c; + + if((cur - out) != write_n_bytes(sock, out, cur - out)) + goto err; + + + if(2 != read_n_bytes(sock, in, 2)) + goto err; +/* according to RFC 1929 the version field for the user/pass auth sub- +negotiation should be 1, which is kinda counter-intuitive, so there +are some socks5 proxies that return 5 instead. other programs like +curl work fine when the version is 5, so let's do the same and accept +either of them. */ + if(!(in[0] == 5 || in[0] == 1)) + goto err; + if(in[1] != 0) + return BLOCKED; + } + int buff_iter = 0; + buff[buff_iter++] = 5; // version + buff[buff_iter++] = 3; // udp_associate + buff[buff_iter++] = 0; // reserved + + if(dst_addr) { + int v6 = dst_addr->is_v6; + buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6 + memcpy(buff + buff_iter, dst_addr->addr.v6, v6?16:4); // dest host + buff_iter += v6?16:4; + memcpy(buff + buff_iter, &dst_port, 2); // dest port + buff_iter += 2; + } else { + buff[buff_iter++] = 1; //we put atyp = 1, should we put 0 ? + buff[buff_iter++] = 0; // v4 byte1 + buff[buff_iter++] = 0; // v4 byte2 + buff[buff_iter++] = 0; // v4 byte3 + buff[buff_iter++] = 0; // v4 byte4 + buff[buff_iter++] = 0; // port byte1 + buff[buff_iter++] = 0; // port byte2 + } + + if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter)) + goto err; + + if(4 != read_n_bytes(sock, (char *) buff, 4)) + goto err; + + if(buff[0] != 5 || buff[1] != 0) + goto err; + + + switch (buff[3]) { + case ATYP_V4: + bnd_addr->is_v6 = 0; + break; + case ATYP_V6: + bnd_addr->is_v6 = 1; + break; + case ATYP_DOM: + PDEBUG("BND_ADDR in UDP_ASSOCIATE response should not be a domain name!\n"); + goto err; + break; + default: + goto err; + } + len = bnd_addr->is_v6?16:4; + + if(len != read_n_bytes(sock, (char *) buff, len)) + goto err; + + memcpy(bnd_addr->addr.v6, buff,len); + + if(2 != read_n_bytes(sock, (char *) buff, 2)) + goto err; + + memcpy(bnd_port, buff, 2); + + return SUCCESS; + + err: + return SOCKET_ERROR; +} + +/* Fills buf with the SOCKS5 udp request header for the target dst_addr:dst_port*/ +static int write_udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, char * buf, size_t buflen) { + + int size = 0; + int v6 = dst_addr.atyp == ATYP_V6; + + if(dst_addr.atyp == ATYP_DOM){ + size = dst_addr.addr.dom.len; + } else { + size = v6?16:4; + } + + if (buflen <= size) { + return -1; + } + + int buf_iter = 0; + buf[buf_iter++] = 0; // reserved + buf[buf_iter++] = 0; // reserved + buf[buf_iter++] = frag; // frag + buf[buf_iter++] = dst_addr.atyp; // atyp + + + switch (dst_addr.atyp){ + case ATYP_V6: + case ATYP_V4: + memcpy(buf + buf_iter, dst_addr.addr.v6, v6?16:4); + buf_iter += v6?16:4; + break; + + case ATYP_DOM: + buf[buf_iter++] = dst_addr.addr.dom.len; + memcpy(buf + buf_iter, dst_addr.addr.dom.name, dst_addr.addr.dom.len); + buf_iter += dst_addr.addr.dom.len; + break; + } + + memcpy(buf + buf_iter, &dst_port, 2); // dest port + buf_iter += 2; + + return buf_iter; +} + + +int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned short* src_port, char* frag) { + + PFUNC(); + PDEBUG("buflen : %d\n", buflen); + if (buflen < 5){ + PDEBUG("buffer too short to contain a UDP header\n"); + return -1; + } + + int buf_iter = 0; + buf_iter += 2; // first 2 bytes are reserved; + *frag = buf[buf_iter++]; + src_addr->atyp = buf[buf_iter++]; + int v6; + + switch (src_addr->atyp) + { + case ATYP_DOM: + PDEBUG("UDP header with ATYP_DOM addr type\n"); + src_addr->addr.dom.len = buf[buf_iter++]; + if(buflen < (5 + 2 + src_addr->addr.dom.len) ) { + PDEBUG("buffer too short to read the UDP header\n"); + return -1; + } + memcpy(src_addr->addr.dom.name, buf + buf_iter, src_addr->addr.dom.len); + buf_iter += src_addr->addr.dom.len; + break; + + case ATYP_V4: + case ATYP_V6: + PDEBUG("UDP header with ATYP_V4/6 addr type\n"); + v6 = src_addr->atyp == ATYP_V6; + if(buflen < (4 + 2 + v6?16:4) ){ + PDEBUG("buffer too short to read the UDP header\n"); + return -1; + } + memcpy(src_addr->addr.v6, buf + buf_iter, v6?16:4); + buf_iter += v6?16:4; + cast_socks5addr_v4inv6_to_v4(src_addr); + break; + default: + break; + } + + memcpy(src_port, buf+buf_iter, 2); + buf_iter += 2; + + return buf_iter; +} + +size_t get_iov_total_len(struct iovec* iov, size_t iov_len){ + size_t n = 0; + for(int i=0; iatyp == ATYP_V6) && !memcmp(addr->addr.v6, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12)){ + PDEBUG("casting v4inv6 address to v4 address\n"); + addr->atyp=ATYP_V4; + memcpy(addr->addr.v4.octet, addr->addr.v6+12, 4); + } +} + +int compare_iptype_sockaddr(ip_type addr1, struct sockaddr* addr2){ + if(addr1.is_v6 && (((struct sockaddr_in6 *)addr2)->sin6_family == AF_INET6)){ + //Both are IPv6 + return !memcmp(((struct sockaddr_in6 *)addr2)->sin6_addr.s6_addr, addr1.addr.v6, 16); + } else if(!addr1.is_v6 && (((struct sockaddr_in *)addr2)->sin_family == AF_INET)){ + //Both are IPv4 + return ((uint32_t)(((struct sockaddr_in *)addr2)->sin_addr.s_addr) == addr1.addr.v4.as_int); + } else { + // Not the same address type + return 0; + } +} + +int compare_socks5_addr_iptype(socks5_addr addr1, ip_type addr2){ + PFUNC(); + if(addr1.atyp == ATYP_DOM){ + //addr1 is a domain name + return 0; + } + + if((addr1.atyp == ATYP_V6) && addr2.is_v6){ + //Both are IPv6 + return !memcmp(addr1.addr.v6, addr2.addr.v6, 16); + } else if((addr1.atyp == ATYP_V4) && !addr2.is_v6){ + //Both are IPv4 + return (addr1.addr.v4.as_int == addr2.addr.v4.as_int); + } else { + // Not the same address type + return 0; + } +} + +int is_from_chain_head(udp_relay_chain chain, struct sockaddr* src_addr){ + + if(compare_iptype_sockaddr(chain.head->bnd_addr, src_addr)){ + return (chain.head->bnd_port == ((struct sockaddr_in*)src_addr)->sin_port); + } + return 0; +} + + + +int decapsulate_check_udp_packet(void* in_buffer, size_t in_buffer_len, udp_relay_chain chain, socks5_addr* src_addr, unsigned short* src_port, void** udp_data){ + + PFUNC(); + // Go through the whole proxy chain, decapsulate each header and check that the addresses match + + udp_relay_node * tmp = chain.head; + int read = 0; + int rc = 0; + socks5_addr header_addr; + unsigned short header_port; + char header_frag; + while (tmp->next != NULL) + { + rc = read_udp_header(in_buffer+read, in_buffer_len-read, &header_addr, &header_port, &header_frag ); + if(-1 == rc){ + PDEBUG("error reading UDP header\n"); + return -1; + } + read += rc; + + if(header_frag != 0x00){ + printf("WARNING: received UDP packet with frag != 0 while fragmentation is unsupported.\n"); + } + + if(!compare_socks5_addr_iptype(header_addr, tmp->next->bnd_addr)){ + PDEBUG("UDP header addr is not equal to proxy node addr, dropping packet\n"); + return -1; + } + + if(tmp->next->bnd_port != header_port){ + PDEBUG("UDP header port is not equal to proxy node port, dropping packet\n"); + return -1; + } + + PDEBUG("UDP header's addr and port correspond to proxy node's addr and port\n"); + tmp = tmp->next; + } + + PDEBUG("all UDP headers validated\n"); + + + // Decapsulate the last header. No checks needed here, just pass the source addr and port as return values + rc = read_udp_header(in_buffer+read, in_buffer_len-read, src_addr, src_port, &header_frag); + if(-1 == rc){ + PDEBUG("error reading UDP header\n"); + return -1; + } + read += rc; + + if(header_frag != 0x00){ + printf("WARNING: received UDP packet with frag != 0 while fragmentation is unsupported.\n"); + } + + + // Point udp_data to the position of the UDP data inside in_buffer + *udp_data = in_buffer+read; + + return 0; +} + +//Takes an in_buffer of size in_buffer_len, checks that all UDP headers are correct (against chain), fills src_ip and src_port with address of the peer sending the packet through the relay, and fills udp_data with the address of the udp data inside in_buff +int unsocksify_udp_packet(void* in_buffer, size_t in_buffer_len, udp_relay_chain chain, ip_type* src_ip, unsigned short* src_port, void** udp_data){ + PFUNC(); + // Decapsulate all the UDP headers and check that the packet came from the right proxy nodes + int rc; + socks5_addr src_addr; + rc = decapsulate_check_udp_packet(in_buffer, in_buffer_len, chain, &src_addr, src_port, udp_data); + if(rc != SUCCESS){ + PDEBUG("error decapsulating the packet\n"); + return -1; + } + PDEBUG("all UDP headers decapsulated and validated\n"); + + // If the innermost UDP header (containing the address of the final target) is of type ATYP_DOM, perform a + // reverse mapping to hand the 224.X.X.X IP to the client application + + if(src_addr.atyp == ATYP_DOM){ + PDEBUG("Fetching matching IP for hostname\n"); + DUMP_BUFFER(src_addr.addr.dom.name,src_addr.addr.dom.len); + ip_type4 tmp_ip = IPT4_INVALID; + char host_string[256]; + memcpy(host_string, src_addr.addr.dom.name, src_addr.addr.dom.len); + host_string[src_addr.addr.dom.len] = 0x00; + + tmp_ip = rdns_get_ip_for_host(host_string, src_addr.addr.dom.len); + if(tmp_ip.as_int == -1){ + PDEBUG("error getting ip for host\n"); + return -1; + } + src_addr.atyp = ATYP_V4; + src_addr.addr.v4.as_int = tmp_ip.as_int; + + } + + src_ip->is_v6 = (src_addr.atyp == ATYP_V6); + if(src_ip->is_v6){ + memcpy(src_ip->addr.v6, src_addr.addr.v6, 16); + } else{ + src_ip->addr.v4.as_int = src_addr.addr.v4.as_int; + } + + return 0; +} + + +int encapsulate_udp_packet(udp_relay_chain chain, socks5_addr dst_addr, unsigned short dst_port, void* buffer, size_t* buffer_len){ + + PFUNC(); + + unsigned int written = 0; + unsigned int offset = 0; + udp_relay_node * tmp = chain.head; + + while ((tmp->next != NULL) && (written < *buffer_len)) + { + socks5_addr tmpaddr; + tmpaddr.atyp = (tmp->next)->bnd_addr.is_v6?ATYP_V6:ATYP_V4; + memcpy(tmpaddr.addr.v6, (tmp->next)->bnd_addr.addr.v6, (tmp->next)->bnd_addr.is_v6?16:4); + + written = write_udp_header(tmpaddr, (tmp->next)->bnd_port, 0, buffer+offset, *buffer_len - offset); + if (written == -1){ + PDEBUG("error write_udp_header\n"); + return -1; + } + offset += written; + + tmp = tmp->next; + } + + written = write_udp_header(dst_addr, dst_port, 0, buffer+offset, *buffer_len-offset); + if (written == -1){ + PDEBUG("error write_udp_header\n"); + return -1; + } + offset += written; + + *buffer_len = offset; + + return 0; +} + +int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain chain, ip_type dst_ip, unsigned short dst_port, void* buffer, size_t* buffer_len){ + + PFUNC(); + if (chain.head == NULL ){ + PDEBUG("provided chain is empty\n"); + return -1; + } + + char *dns_name = NULL; + char hostnamebuf[MSG_LEN_MAX]; + size_t dns_len = 0; + socks5_addr dst_addr; + // we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution + // 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(!dst_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && dst_ip.addr.v4.octet[0] == remote_dns_subnet) { + dst_addr.atyp = ATYP_DOM; + dns_len = rdns_get_host_for_ip(dst_ip.addr.v4, dst_addr.addr.dom.name); + PDEBUG("dnslen: %d\n", dns_len); + if(!dns_len) return -1; + else dns_name = dst_addr.addr.dom.name; + dst_addr.addr.dom.len = dns_len & 0xFF; + PDEBUG("dnslen in struct: %d\n", dst_addr.addr.dom.len); + + } else { + if(dst_ip.is_v6){ + dst_addr.atyp = ATYP_V6; + memcpy(dst_addr.addr.v6, dst_ip.addr.v6, 16); + + } else { + dst_addr.atyp = ATYP_V4; + memcpy(dst_addr.addr.v4.octet, dst_ip.addr.v4.octet, 4); + } + } + + PDEBUG("host dns %s\n", dns_name ? dns_name : ""); + + + // Write all the UDP headers into the provided buffer + int rc; + size_t tmp_buffer_len = *buffer_len; + rc = encapsulate_udp_packet(chain, dst_addr, dst_port, buffer, &tmp_buffer_len); + if(rc != SUCCESS){ + PDEBUG("error encapsulate_udp_packet()\n"); + return -1; + + } + + + // Append UDP data in the remaining space of the buffer + size_t min = (udp_data_len>(buffer_len-tmp_buffer_len))?(buffer_len-tmp_buffer_len):udp_data_len; + memcpy(buffer + tmp_buffer_len, udp_data, min); + + *buffer_len = tmp_buffer_len + min; + + return 0; + +} + + #define TP " ... " #define DT "Dynamic chain" #define ST "Strict chain" #define RT "Random chain" #define RRT "Round Robin chain" +#define UDPC "UDP_ASSOCIATE tcp socket chain" static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { + PFUNC(); int v6 = pd->ip.is_v6; *fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0); @@ -463,13 +986,14 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { proxychains_write_log(TP " timeout\n"); error: if(*fd != -1) { - close(*fd); + true_close(*fd); *fd = -1; } return SOCKET_ERROR; } static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { + PFUNC(); unsigned int i = 0, k = 0; if(*offset >= proxy_count) return NULL; @@ -563,7 +1087,7 @@ static int chain_step(int *ns, proxy_data * pfrom, proxy_data * pto) { return retcode; err: if(errmsg) proxychains_write_log(errmsg); - if(*ns != -1) close(*ns); + if(*ns != -1) true_close(*ns); *ns = -1; return retcode; } @@ -719,11 +1243,11 @@ int connect_proxy_chain(int sock, ip_type target_ip, proxychains_write_log(TP " OK\n"); dup2(ns, sock); - close(ns); + true_close(ns); return 0; error: if(ns != -1) - close(ns); + true_close(ns); errno = ECONNREFUSED; // for nmap ;) return -1; @@ -734,11 +1258,276 @@ int connect_proxy_chain(int sock, ip_type target_ip, release_all(pd, proxy_count); if(ns != -1) - close(ns); + true_close(ns); errno = ETIMEDOUT; return -1; } + +int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ + PFUNC(); + // Allocate memory for the new node structure + udp_relay_node * new_node = NULL; + if(NULL == (new_node = (udp_relay_node *)malloc(sizeof(udp_relay_node)))){ + PDEBUG("error malloc new node\n"); + return -1; + } + new_node->next = NULL; + + + udp_relay_node * tmp = chain->head; + + if(tmp == NULL){ // Means new_node is the first node to be created + chain->head = new_node; + new_node->prev = NULL; + } else { + // Moving to the end of the current chain + while(tmp->next != NULL){ + tmp = tmp->next; + } + // Adding the new node at the end + tmp->next = new_node; + new_node->prev = tmp; + } + + + // Initializing the new node + new_node->pd.ip = pd->ip; + new_node->pd.port = pd->port; + new_node->pd.pt = pd->pt; + new_node->pd.ps = pd->ps; + strcpy(new_node->pd.user, pd->user); + strcpy(new_node->pd.pass, pd->pass); + + // Connecting the new node tcp_socketfd to the associated proxy through the current chain + // + tmp = chain->head; + // First connect to the chain head + if(SUCCESS != start_chain(&(new_node->tcp_sockfd), &(tmp->pd), UDPC)){ + PDEBUG("start_chain failed\n"); + new_node->tcp_sockfd = -1; + goto err; + } + // Connect to the rest of the chain + while(tmp->next != NULL){ + if(SUCCESS != chain_step(&(new_node->tcp_sockfd), &(tmp->pd), &(tmp->next->pd))){ + PDEBUG("chain step failed\n"); + new_node->tcp_sockfd = -1; + goto err; + } + tmp = tmp->next; + } + + // Performing UDP_ASSOCIATE handshake in order to fill the new node BND_ADDR and BND_PORT + if(SUCCESS != udp_associate(new_node->tcp_sockfd, NULL, NULL, &(new_node->bnd_addr), &(new_node->bnd_port), new_node->pd.user, new_node->pd.pass)){ + PDEBUG("udp_associate failed\n"); + goto err; + } + + char ip_buf[INET6_ADDRSTRLEN]; + proxychains_write_log(" --> Node[%s:%i] open\n", inet_ntop(new_node->bnd_addr.is_v6?AF_INET6:AF_INET, new_node->bnd_addr.is_v6?(void*)new_node->bnd_addr.addr.v6:(void*)new_node->bnd_addr.addr.v4.octet, ip_buf, sizeof(ip_buf)) , ntohs(new_node->bnd_port)); + PDEBUG("new node added and open to relay UDP packets\n"); + return SUCCESS; + + err: + // Ensure new node tcp socket is closed + if(new_node->tcp_sockfd != -1){ + true_close(new_node->tcp_sockfd); + } + + // Remove the new node from the chain + if(new_node->prev == NULL){ // means new_node is the only node in chain + chain->head = NULL; + } else{ + (new_node->prev)->next = NULL; + } + + + // Free memory + free(new_node); + + return -1; +} + +int free_relay_chain_contents(udp_relay_chain* chain){ + if(NULL != chain->connected_peer_addr){ + free(chain->connected_peer_addr); + chain->connected_peer_addr = NULL; + } + + if(chain->head == NULL){ + return SUCCESS; + } + + udp_relay_node * current = chain->head; + udp_relay_node * next = NULL; + + while(current != NULL){ + next = current->next; + + true_close(current->tcp_sockfd); + free(current); + + current = next; + } + chain->head = NULL; + + return SUCCESS; +} + +udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, chain_type ct, unsigned int max_chains){ + + PFUNC(); + // Allocate memory for the new relay chain + udp_relay_chain * new_chain = NULL; + if(NULL == (new_chain = (udp_relay_chain *)malloc(sizeof(udp_relay_chain)))){ + PDEBUG("error malloc new chain\n"); + return NULL; + } + + new_chain->head = NULL; + new_chain->sockfd = -1; + new_chain->connected_peer_addr = NULL; + new_chain->connected_peer_addr_len = -1; + + + unsigned int alive_count = 0; + unsigned int offset = 0; + proxy_data *p1; + + + switch (ct) + { + case DYNAMIC_TYPE: + PDEBUG("DYNAMIC_TYPE not yet supported for UDP\n"); + goto error; + break; + case ROUND_ROBIN_TYPE: + PDEBUG("ROUND_ROBIN_TYPE not yet supported for UDP\n"); + goto error; + break; + case STRICT_TYPE: + alive_count = calc_alive(pd, proxy_count); + offset = 0; + PDEBUG("opening STRICT_TYPE relay chain, alive_count=%d, offset=%d\n", alive_count, offset); + while((p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) { + if(SUCCESS != add_node_to_chain(p1, new_chain)) { + PDEBUG("add_node_to_chain failed\n"); + p1->ps = BLOCKED_STATE; + goto error; + } + p1->ps = BUSY_STATE; + } + return new_chain; + + break; + case RANDOM_TYPE: + PDEBUG("RANDOM_TYPE not yet supported for UDP\n"); + goto error; + break; + default: + break; + } + + error: + PDEBUG("error\n"); + release_all(pd, proxy_count); + free_relay_chain_contents(new_chain); + free(new_chain); + errno = ETIMEDOUT; + return NULL; +} + +// Checks the address family of addr, allocates a matching structure and keeps a pointer to it in the chain structure to store the address of the connected peer +void set_connected_peer_addr(udp_relay_chain* chain, struct sockaddr* addr, socklen_t addrlen){ + + sa_family_t fam = ((struct sockaddr_in*)addr)->sin_family; + int v6 = fam == AF_INET6; + + + + if(v6){ + struct sockaddr_in6* old_addr6 = (struct sockaddr_in6*)addr; + struct sockaddr_in6* new_addr6 = NULL; + if(NULL == (new_addr6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6)))){ + PDEBUG("error malloc\n"); + return -1; + } + + new_addr6->sin6_family = old_addr6->sin6_family; + new_addr6->sin6_port = old_addr6->sin6_port; + memcpy(new_addr6->sin6_addr.s6_addr, old_addr6->sin6_addr.s6_addr, 16); + + chain->connected_peer_addr = (struct sockaddr*)new_addr6; + chain->connected_peer_addr_len = sizeof(struct sockaddr_in6); + + } else{ + struct sockaddr_in* old_addr = (struct sockaddr_in*)addr; + struct sockaddr_in* new_addr = NULL; + if(NULL == (new_addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)))){ + PDEBUG("error malloc\n"); + return -1; + } + + new_addr->sin_family = old_addr->sin_family; + new_addr->sin_port = old_addr->sin_port; + new_addr->sin_addr.s_addr = old_addr->sin_addr.s_addr; + + chain->connected_peer_addr = (struct sockaddr*)new_addr; + chain->connected_peer_addr_len = sizeof(struct sockaddr_in); + } +} + + +void add_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* new_chain){ + + new_chain->next = NULL; + + if(chains_list->tail == NULL){ // The current list is empty, set head and tail to the new chain + chains_list->head = new_chain; + chains_list->tail = new_chain; + new_chain->prev = NULL; + } else { + // Add the new chain at the end + (chains_list->tail)->next = new_chain; + new_chain->prev = chains_list->tail; + chains_list->tail = new_chain; + } +} + +void del_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* chain){ + if(chain == chains_list->head){ + if(chain->next == NULL){ + free(chain); + chains_list->head = NULL; + chains_list->tail = NULL; + }else{ + chains_list->head = chain->next; + chains_list->head->prev = NULL; + free(chain); + } + } else if (chain == chains_list->tail){ + chains_list->tail = chain->prev; + chains_list->tail->next = NULL; + free(chain); + } else { + chain->next->prev = chain->prev; + chain->prev->next = chain->next; + free(chain); + } +} + +udp_relay_chain* get_relay_chain(udp_relay_chain_list chains_list, int sockfd){ + udp_relay_chain* tmp = chains_list.head; + while(tmp != NULL){ + if(tmp->sockfd == sockfd){ + break; + } + tmp = tmp->next; + } + return tmp; +} + static pthread_mutex_t servbyname_lock; void core_initialize(void) { MUTEX_INIT(&servbyname_lock); @@ -806,9 +1595,9 @@ struct hostent* proxy_gethostbyname_old(const char *name) case 0: // child proxychains_write_log("|DNS-request| %s \n", name); - close(pipe_fd[0]); + true_close(pipe_fd[0]); dup2(pipe_fd[1],1); - close(pipe_fd[1]); + true_close(pipe_fd[1]); // putenv("LD_PRELOAD="); execlp("proxyresolv","proxyresolv",name,NULL); @@ -816,17 +1605,17 @@ struct hostent* proxy_gethostbyname_old(const char *name) exit(2); case -1: //error - close(pipe_fd[0]); - close(pipe_fd[1]); + true_close(pipe_fd[0]); + true_close(pipe_fd[1]); perror("can't fork"); goto err; default: - close(pipe_fd[1]); + true_close(pipe_fd[1]); waitpid(pid, &status, 0); buff[0] = 0; - read(pipe_fd[0],&buff,sizeof(buff)); - close(pipe_fd[0]); + true_read(pipe_fd[0],&buff,sizeof(buff)); + true_close(pipe_fd[0]); got_buff: l = strlen(buff); if (!l) goto err_dns; diff --git a/src/core.h b/src/core.h index 59a8e12..e05dac6 100644 --- a/src/core.h +++ b/src/core.h @@ -20,6 +20,7 @@ #include #include #include +#include //Needed to hook uv_close() #ifndef __CORE_HEADER #define __CORE_HEADER @@ -64,6 +65,7 @@ typedef enum { FIFOLY } select_type; + typedef struct { sa_family_t family; unsigned short port; @@ -93,6 +95,55 @@ typedef struct { char pass[256]; } proxy_data; + + +typedef enum { + ATYP_V4 = 0x01, + ATYP_V6 = 0x04, + ATYP_DOM = 0x03 +} ATYP; + +typedef struct{ + union { + ip_type4 v4; + unsigned char v6[16]; + struct { + char len; + char name[255]; + } dom; + } addr ; + ATYP atyp; +} socks5_addr; + +/* A structure to hold necessary information about an UDP relay server that has been set up +with a UDP_ASSOCIATE command issued on the tcp_sockfd */ +typedef struct s_udp_relay_node { + int tcp_sockfd; // the tcp socket on which the UDP_ASSOCIATE command has been issued. Closing this fd closes the udp relay. + proxy_data pd; // the associated SOCKS5 server + ip_type bnd_addr; // the BND_ADDR returned by the udp relay server in the response to the UDP_ASSOCIATE command. + unsigned short bnd_port; // the BND_PORT returned by the udp relay server in the response to the UDP_ASSOCIATE command. + ip_type dst_addr; // ?? the DST_ADDR sent in the UDP_ASSOCIATE command. + unsigned short dst_port; // ?? the DST_PORT sent in the UDP_ASSOCIATE command. + struct s_udp_relay_node * prev; + struct s_udp_relay_node * next; +} udp_relay_node; + + +/* A structure to hold the chain of udp relay servers assiociated with a client socket */ +typedef struct s_udp_relay_chain { + int sockfd; // the client socket for which the chain of relays has been set up + udp_relay_node * head; // head of the linked list of udp_relay_node + struct sockaddr* connected_peer_addr; // used to store the address of the peer which the sockfd is connected to (in case connect() is used on the socket) + socklen_t connected_peer_addr_len; + struct s_udp_relay_chain * prev; + struct s_udp_relay_chain * next; +} udp_relay_chain; + +typedef struct { + udp_relay_chain * head; + udp_relay_chain * tail; +} udp_relay_chain_list; + int connect_proxy_chain (int sock, ip_type target_ip, unsigned short target_port, proxy_data * pd, unsigned int proxy_count, chain_type ct, unsigned int max_chain ); @@ -101,6 +152,7 @@ void proxychains_write_log(char *str, ...); typedef int (*close_t)(int); typedef int (*close_range_t)(unsigned, unsigned, int); +typedef void (*uv_close_t)(uv_handle_t* , uv_close_cb); typedef int (*connect_t)(int, const struct sockaddr *, socklen_t); typedef struct hostent* (*gethostbyname_t)(const char *); typedef void (*freeaddrinfo_t)(struct addrinfo *); @@ -115,6 +167,19 @@ typedef int (*getnameinfo_t) (const struct sockaddr *, socklen_t, char *, typedef ssize_t (*sendto_t) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +typedef ssize_t (*send_t) (int sockfd, const void *buf, size_t len, int flags); + +typedef ssize_t (*recv_t) (int sockfd, void *buf, size_t len, int flags); + +typedef ssize_t (*recvfrom_t) (int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + +typedef ssize_t (*sendmsg_t) (int sockfd, const struct msghdr *msg, int flags); +typedef int (*sendmmsg_t) (int sockfd, struct mmsghdr* msgvec, unsigned int vlen, int flags); +typedef ssize_t (*recvmsg_t) (int sockfd, struct msghdr *msg, int flags); +typedef int (*getpeername_t) (int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen); +typedef ssize_t (*read_t)(int fd, void* buf, size_t count); +typedef ssize_t (*write_t)(int fd, const void* buf, size_t count); extern connect_t true_connect; @@ -123,6 +188,18 @@ extern getaddrinfo_t true_getaddrinfo; extern freeaddrinfo_t true_freeaddrinfo; extern getnameinfo_t true_getnameinfo; extern gethostbyaddr_t true_gethostbyaddr; +extern sendto_t true_sendto; +extern recvfrom_t true_recvfrom; +extern recv_t true_recv; +extern send_t true_send; +extern sendmsg_t true_sendmsg; +extern sendmmsg_t true_sendmmsg; +extern recvmsg_t true_recvmsg; +extern getpeername_t true_getpeername; +extern read_t true_read; +extern write_t true_write; +extern close_t true_close; +extern uv_close_t true_uv_close; struct gethostbyname_data { struct hostent hostent_space; @@ -141,6 +218,23 @@ void proxy_freeaddrinfo(struct addrinfo *res); void core_initialize(void); void core_unload(void); +static int udp_associate(int sock, ip_type * dst_addr, unsigned short dst_port, ip_type *bnd_addr, unsigned short *bnd_port, char *user, char *pass); +udp_relay_chain* get_relay_chain(udp_relay_chain_list chains_list, int sockfd); +void del_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* chain); +void add_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* new_chain); +int free_relay_chain_contents(udp_relay_chain* chain); +udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, chain_type ct, unsigned int max_chains); +int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsigned short target_port, char frag, char * data, unsigned int data_len, int flags); +int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ); +size_t get_msg_iov_total_len(struct iovec* iov, size_t iov_len); +size_t write_buf_to_iov(void* buff, size_t buff_len, struct iovec* iov, size_t iov_len); +size_t write_iov_to_buf(void* buff, size_t buff_len, struct iovec* iov, size_t iov_len); +int is_from_chain_head(udp_relay_chain chain, struct sockaddr* src_addr); +int unsocksify_udp_packet(void* in_buffer, size_t in_buffer_len, udp_relay_chain chain, ip_type* src_ip, unsigned short* src_port, void** udp_data); +int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain chain, ip_type dst_ip, unsigned short dst_port, void* buffer, size_t* buffer_len); +int encapsulate_udp_packet(udp_relay_chain chain, socks5_addr dst_addr, unsigned short dst_port, void* buffer, size_t* buffer_len); +void set_connected_peer_addr(udp_relay_chain* chain, struct sockaddr* addr, socklen_t addrlen); + #include "debug.h" #endif diff --git a/src/debug.c b/src/debug.c index 314aadd..be1937f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -22,6 +22,40 @@ void dump_proxy_chain(proxy_data *pchain, unsigned int count) { } } +void dump_buffer(unsigned char * data, size_t len){ + printf("buffer_dump["); + for(size_t i=0; inext; + } +} + +void dump_relay_chain(udp_relay_chain* chain){ + printf("Chain %x: fd=%d\n", chain, chain->sockfd); + udp_relay_node* current_node; + current_node = chain->head; + char ip_buf[INET6_ADDRSTRLEN]; + char ip_buf2[INET6_ADDRSTRLEN]; + while(current_node){ + printf("\tNode%x", current_node); + printf("[%s:%i]", inet_ntop(current_node->bnd_addr.is_v6?AF_INET6:AF_INET, current_node->bnd_addr.is_v6?(void*)current_node->bnd_addr.addr.v6:(void*)current_node->bnd_addr.addr.v4.octet, ip_buf2, sizeof(ip_buf2)) , ntohs(current_node->bnd_port)); + printf("(ctrl_fd%i-%s:%i)", current_node->tcp_sockfd, inet_ntop(current_node->pd.ip.is_v6?AF_INET6:AF_INET, current_node->pd.ip.is_v6?(void*)current_node->pd.ip.addr.v6:(void*)current_node->pd.ip.addr.v4.octet, ip_buf, sizeof(ip_buf)) , ntohs(current_node->pd.port) ); + printf("\n"); + current_node = current_node->next; + } + +} #else // Do not allow this translation unit to end up empty diff --git a/src/debug.h b/src/debug.h index 45082c2..94afa01 100644 --- a/src/debug.h +++ b/src/debug.h @@ -5,20 +5,26 @@ #ifdef DEBUG # define PSTDERR(fmt, args...) do { dprintf(2,fmt, ## args); } while(0) -# define PDEBUG(fmt, args...) PSTDERR("DEBUG:pid[%d]:" fmt, getpid(), ## args) +# define PDEBUG(fmt, args...) PSTDERR("DEBUG:pid[%d]tid[%d]func[%s()]:" fmt, getpid(),gettid(),__FUNCTION__, ## args) # define DEBUGDECL(args...) args # define DUMP_PROXY_CHAIN(A, B) dump_proxy_chain(A, B) +# define DUMP_BUFFER(data, len) dump_buffer(data, len) +# define DUMP_RELAY_CHAINS_LIST(list) dump_relay_chains_list(list) #else # define PDEBUG(fmt, args...) do {} while (0) # define DEBUGDECL(args...) # define DUMP_PROXY_CHAIN(args...) do {} while (0) +# define DUMP_BUFFER(data, len) do {} while (0) +# define DUMP_RELAY_CHAINS_LIST(list) do {} while (0) #endif # define PFUNC() do { PDEBUG("%s()\n", __FUNCTION__); } while(0) #include "core.h" void dump_proxy_chain(proxy_data *pchain, unsigned int count); - +void dump_buffer(unsigned char* data, size_t len); +void dump_relay_chain(udp_relay_chain* chain); +void dump_relay_chains_list(udp_relay_chain_list list); #endif diff --git a/src/libproxychains.c b/src/libproxychains.c index 84a8f00..0ce1745 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -36,10 +36,16 @@ #include #include +#include +#include + + + #include "core.h" #include "common.h" #include "rdns.h" +#include "mutex.h" #undef satosin #define satosin(x) ((struct sockaddr_in *) &(x)) @@ -48,6 +54,7 @@ #define SOCKPORT(x) (satosin(x)->sin_port) #define SOCKFAMILY(x) (satosin(x)->sin_family) #define MAX_CHAIN 512 +#define RECV_BUFFER_SIZE 65536 //Should be larger than any possible UDP packet #ifdef IS_SOLARIS #undef connect @@ -57,6 +64,7 @@ connect_t true___xnet_connect; close_t true_close; close_range_t true_close_range; +uv_close_t true_uv_close; connect_t true_connect; gethostbyname_t true_gethostbyname; getaddrinfo_t true_getaddrinfo; @@ -64,6 +72,15 @@ freeaddrinfo_t true_freeaddrinfo; getnameinfo_t true_getnameinfo; gethostbyaddr_t true_gethostbyaddr; sendto_t true_sendto; +send_t true_send; +recv_t true_recv; +recvfrom_t true_recvfrom; +sendmsg_t true_sendmsg; +recvmsg_t true_recvmsg; +sendmmsg_t true_sendmmsg; +getpeername_t true_getpeername; +read_t true_read; +write_t true_write; int tcp_read_time_out; int tcp_connect_time_out; @@ -81,6 +98,9 @@ dnat_arg dnats[MAX_DNAT]; size_t num_dnats = 0; unsigned int remote_dns_subnet = 224; +udp_relay_chain_list relay_chains = {NULL, NULL}; +pthread_mutex_t relay_chains_mutex; + pthread_once_t init_once = PTHREAD_ONCE_INIT; static int init_l = 0; @@ -136,6 +156,7 @@ static void do_init(void) { char *env; srand(get_rand_seed()); + MUTEX_INIT(&relay_chains_mutex); core_initialize(); env = getenv(PROXYCHAINS_QUIET_MODE_ENV_VAR); @@ -582,23 +603,85 @@ inv_host: #endif HOOKFUNC(int, close, int fd) { + PFUNC(); + if(!init_l) { if(close_fds_cnt>=(sizeof close_fds/sizeof close_fds[0])) goto err; close_fds[close_fds_cnt++] = fd; errno = 0; return 0; } - if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close(fd); + + /***** UDP STUFF *******/ + //PDEBUG("checking if a relay chain is opened for fd %d\n", fd); + udp_relay_chain* relay_chain = NULL; + + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + relay_chain = get_relay_chain(relay_chains, fd); + if(NULL != relay_chain){ + PDEBUG("fd %d corresponds to chain %x, closing it\n", fd, relay_chain); + free_relay_chain_contents(relay_chain); + del_relay_chain(&relay_chains, relay_chain); + PDEBUG("chain %x corresponding to fd %d closed\n", relay_chain, fd); + DUMP_RELAY_CHAINS_LIST(relay_chains); + } + + /***** END UDP STUFF *******/ + + if(proxychains_resolver != DNSLF_RDNS_THREAD){ + MUTEX_UNLOCK(&relay_chains_mutex); + return true_close(fd); + } /* prevent rude programs (like ssh) from closing our pipes */ if(fd != req_pipefd[0] && fd != req_pipefd[1] && fd != resp_pipefd[0] && fd != resp_pipefd[1]) { + MUTEX_UNLOCK(&relay_chains_mutex); return true_close(fd); } err: errno = EBADF; + MUTEX_UNLOCK(&relay_chains_mutex); return -1; } + +HOOKFUNC(void, uv_close, uv_handle_t* handle, uv_close_cb close_cb){ + PFUNC(); + + switch (handle->type) + { + case UV_UDP: + int fd = ((uv_udp_t*)handle)->io_watcher.fd; + + /***** UDP STUFF *******/ + //PDEBUG("checking if a relay chain is opened for fd %d\n", fd); + udp_relay_chain* relay_chain = NULL; + + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + relay_chain = get_relay_chain(relay_chains, fd); + if(NULL != relay_chain){ + PDEBUG("fd %d corresponds to chain %x, closing it\n", fd, relay_chain); + free_relay_chain_contents(relay_chain); + del_relay_chain(&relay_chains, relay_chain); + PDEBUG("chain %x corresponding to fd %d closed\n", relay_chain, fd); + DUMP_RELAY_CHAINS_LIST(relay_chains); + } + MUTEX_UNLOCK(&relay_chains_mutex); + /***** END UDP STUFF *******/ + break; + + default: + + break; + } + return true_uv_close(handle, close_cb); + +} + static int is_v4inv6(const struct in6_addr *a) { return !memcmp(a->s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); } @@ -616,6 +699,7 @@ static void intsort(int *a, int n) { /* Warning: Linux manual says the third arg is `unsigned int`, but unistd.h says `int`. */ HOOKFUNC(int, close_range, unsigned first, unsigned last, int flags) { + PFUNC(); if(true_close_range == NULL) { fprintf(stderr, "Calling close_range, but this platform does not provide this system call. "); return -1; @@ -666,6 +750,73 @@ HOOKFUNC(int, close_range, unsigned first, unsigned last, int flags) { return res; } +HOOKFUNC(int, getpeername, int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen){ + INIT(); + PFUNC(); + + int socktype = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if( socktype != SOCK_DGRAM){ + PDEBUG("sockfd %d is not a SOCK_DGRAM socket, returning to true_getpeername\n", sockfd); + return true_getpeername(sockfd, addr, addrlen); + } + PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); + + struct sockaddr_storage sock_addr; + socklen_t sock_addr_len = sizeof(sock_addr); + if(SUCCESS != getsockname(sockfd, (struct sockaddr *)&sock_addr, &sock_addr_len )){ + PDEBUG("error getsockname, errno=%d. Returning to true_getpeernam()\n", errno); + return true_getpeername(sockfd, addr, addrlen); + } + sa_family_t fam = SOCKFAMILY(sock_addr); + if(!(fam == AF_INET || fam == AF_INET6)){ + PDEBUG("sockfd %d address familiy is not a AF_INET or AF_INET6, returning to true_getpeername\n", sockfd); + return true_getpeername(sockfd, addr, addrlen); + } + + PDEBUG("sockfd %d's address family is AF_INET or AF_INET6\n", sockfd); + + + /* BEGIN UDP STUFF*/ + + + // Check if a relay chain exists for the socket + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + PDEBUG("no relay chain exists for socket %d, returning true_getpeername()\n", sockfd); + MUTEX_UNLOCK(&relay_chains_mutex); + return true_getpeername(sockfd, addr, addrlen); + } + + // Check if a connected peer address is stored in the relay chain structure + if(relay_chain->connected_peer_addr == NULL){ + PDEBUG("no connected peer address is stored for socket %d, returning true_getpeername()\n", sockfd); + MUTEX_UNLOCK(&relay_chains_mutex); + return true_getpeername(sockfd, addr, addrlen); + } + + // If a connected peer address is stored in the relay chain structure, return it + + socklen_t provided_addr_len = *addrlen; + + + size_t min = (provided_addr_lenconnected_peer_addr_len)?provided_addr_len:relay_chain->connected_peer_addr_len; + memcpy(addr, relay_chain->connected_peer_addr, min); + + *addrlen = min; + + MUTEX_UNLOCK(&relay_chains_mutex); + return SUCCESS; + + /* END UDP STUFF */ + +} + HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) { INIT(); PFUNC(); @@ -684,8 +835,59 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) optlen = sizeof(socktype); sa_family_t fam = SOCKFAMILY(*addr); getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + + /* BEGIN UDP STUFF*/ + if(((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_DGRAM)){ + PDEBUG("connect() on an UDP socket\n"); + + // Check if a relay chain is already opened for the socket fd, otherwise open it + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sock); + if(relay_chain == NULL){ + // No chain is opened for this socket, open one + PDEBUG("opening new chain of relays for %d\n", sock); + if(NULL == (relay_chain = open_relay_chain(proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain))){ + PDEBUG("could not open a chain of relay\n"); + errno = ECONNREFUSED; + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + relay_chain->sockfd = sock; + add_relay_chain(&relay_chains, relay_chain); + DUMP_RELAY_CHAINS_LIST(relay_chains); + } + + + + // Store the peer address in the relay chain structure, in order to be able to retrieve it in subsequent calls to send(), sendmsg(), ... + set_connected_peer_addr(relay_chain, addr, len); + + + // Connect the socket to the relay chain's head, so that subsequent calls to poll(), recv(), recvfrom(), ... can return data comming from this peer + + int v6 = relay_chain->head->bnd_addr.is_v6 == ATYP_V6; + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = relay_chain->head->bnd_port, + .sin_addr.s_addr = (in_addr_t) relay_chain->head->bnd_addr.addr.v4.as_int, + }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = relay_chain->head->bnd_port, + }; + if(v6) memcpy(&addr6.sin6_addr.s6_addr, relay_chain->head->bnd_addr.addr.v6, 16); + + MUTEX_UNLOCK(&relay_chains_mutex); + return true_connect(sock, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + } + + /* END UDP STUFF*/ + if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_STREAM)) - return true_connect(sock, addr, len); + return true_connect(sock, addr, len); int v6 = dest_ip.is_v6 = fam == AF_INET6; @@ -898,8 +1100,1109 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, dest_addr = NULL; addrlen = 0; flags &= ~MSG_FASTOPEN; + + return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); } - return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + + DEBUGDECL(char str[256]); + + // Check that sockfd is a SOCK_DGRAM socket with an AF_INET or AF_INET6 address + int socktype = 0, ret = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + sa_family_t fam = SOCKFAMILY(*dest_addr); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_DGRAM)){ + return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + } + + // Here we have a SOCK_DRGAM socket with an AF_INET or AF_INET6 address + ip_type dest_ip; + struct in_addr *p_addr_in; + struct in6_addr *p_addr_in6; + dnat_arg *dnat = NULL; + size_t i; + int remote_dns_connect = 0; + unsigned short port; + int v6 = dest_ip.is_v6 = fam == AF_INET6; + + p_addr_in = &((struct sockaddr_in *) dest_addr)->sin_addr; + p_addr_in6 = &((struct sockaddr_in6 *) dest_addr)->sin6_addr; + port = !v6 ? ntohs(((struct sockaddr_in *) dest_addr)->sin_port) + : ntohs(((struct sockaddr_in6 *) dest_addr)->sin6_port); + struct in_addr v4inv6; + if(v6 && is_v4inv6(p_addr_in6)) { + memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr[12], 4); + v6 = dest_ip.is_v6 = 0; + p_addr_in = &v4inv6; + } + if(!v6 && !memcmp(p_addr_in, "\0\0\0\0", 4)) { + errno = ECONNREFUSED; + return -1; + } + + PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str))); + PDEBUG("port: %d\n", port); + PDEBUG("client socket: %d\n", sockfd); + PDEBUG("trying to send %lu bytes : ", len); + DUMP_BUFFER(buf, len); + + // check if connect called from proxydns + remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); + + // more specific first + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(dnats[i].orig_port && (dnats[i].orig_port == port)) + dnat = &dnats[i]; + + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(!dnats[i].orig_port) + dnat = &dnats[i]; + + if (dnat) { + p_addr_in = &dnat->new_dst; + if (dnat->new_port) + port = dnat->new_port; + } + + for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { + if (localnet_addr[i].port && localnet_addr[i].port != port) + continue; + if (localnet_addr[i].family != (v6 ? AF_INET6 : AF_INET)) + continue; + if (v6) { + size_t prefix_bytes = localnet_addr[i].in6_prefix / CHAR_BIT; + size_t prefix_bits = localnet_addr[i].in6_prefix % CHAR_BIT; + if (prefix_bytes && memcmp(p_addr_in6->s6_addr, localnet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0) + continue; + if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ localnet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits)) + continue; + } else { + if((p_addr_in->s_addr ^ localnet_addr[i].in_addr.s_addr) & localnet_addr[i].in_mask.s_addr) + continue; + } + PDEBUG("accessing localnet using true_sendto\n"); + return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + } + + // Check if a chain of UDP relay is already opened for this socket + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + // No chain is opened for this socket, open one + PDEBUG("opening new chain of relays for %d\n", sockfd); + if(NULL == (relay_chain = open_relay_chain(proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain))){ + PDEBUG("could not open a chain of relay\n"); + errno = ECONNREFUSED; + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + relay_chain->sockfd = sockfd; + add_relay_chain(&relay_chains, relay_chain); + DUMP_RELAY_CHAINS_LIST(relay_chains); + } + + + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); + + char send_buffer[65535]; + size_t send_buffer_len = sizeof(send_buffer); + + int rc; + rc = socksify_udp_packet(buf, len, *relay_chain, dest_ip, htons(port), send_buffer, &send_buffer_len); + if(rc != SUCCESS){ + PDEBUG("error socksify_udp_packet()\n"); + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + + // Send the packet + + v6 = relay_chain->head->bnd_addr.is_v6; + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = relay_chain->head->bnd_port, + .sin_addr.s_addr = (in_addr_t) relay_chain->head->bnd_addr.addr.v4.as_int, + }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = relay_chain->head->bnd_port, + }; + if(v6) memcpy(&addr6.sin6_addr.s6_addr, relay_chain->head->bnd_addr.addr.v6, 16); + + + //Drop the MSG_DONTROUTE flag if it exists + if(flags & MSG_DONTROUTE){ + proxychains_write_log(LOG_PREFIX "dropping MSG_DONTROUTE flag\n"); + flags ^= MSG_DONTROUTE; + } + //Return EOPNOTSUPP if flag MSG_MORE is set + //TODO: implement MSG_MORE logic so that data from multiple sendto calls can be merged into one UDP datagram and sent to the SOCKS + if(flags & MSG_MORE){ + PDEBUG("error, MSG_MORE not yet supported\n"); + errno = EOPNOTSUPP; + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + MUTEX_UNLOCK(&relay_chains_mutex); + + ssize_t sent = 0; + sent = true_sendto(sockfd, send_buffer, send_buffer_len, flags, (struct sockaddr*)(v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr)); + + if(sent == -1){ + PDEBUG("error true_sendto()\n"); + return sent; + } + + PDEBUG("Successful sendto() hook\n\n"); + return sent; +} + +HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ + INIT(); + PFUNC(); + + struct sockaddr_storage dest_addr; + socklen_t addrlen = sizeof(dest_addr); + + if(msg->msg_name == NULL){ // try to find a peer addr that could have been set with connect() + int rc = 0; + rc = getpeername(sockfd, (struct sockaddr*)&dest_addr, &addrlen); + if(rc != SUCCESS){ + PDEBUG("error in getpeername(): %d\n", errno); + return -1; + } + } else { + if(msg->msg_namelen > addrlen){ + PDEBUG("msg->msg_name too long\n"); + return -1; + } + addrlen = msg->msg_namelen; + memcpy(&dest_addr, msg->msg_name, addrlen); + } + + + + DEBUGDECL(char str[256]); + int socktype = 0, ret = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + sa_family_t fam = SOCKFAMILY(dest_addr); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_DGRAM)){ + return true_sendmsg(sockfd, msg, flags); + } + + PDEBUG("before send dump : "); + DUMP_BUFFER(&dest_addr, addrlen); + + ip_type dest_ip; + struct in_addr *p_addr_in; + struct in6_addr *p_addr_in6; + dnat_arg *dnat = NULL; + size_t i; + int remote_dns_connect = 0; + unsigned short port; + int v6 = dest_ip.is_v6 = fam == AF_INET6; + + p_addr_in = &((struct sockaddr_in *) &dest_addr)->sin_addr; + p_addr_in6 = &((struct + sockaddr_in6 *) &dest_addr)->sin6_addr; + port = !v6 ? ntohs(((struct sockaddr_in *) &dest_addr)->sin_port) + : ntohs(((struct sockaddr_in6 *) &dest_addr)->sin6_port); + struct in_addr v4inv6; + if(v6 && is_v4inv6(p_addr_in6)) { + memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr[12], 4); + v6 = dest_ip.is_v6 = 0; + p_addr_in = &v4inv6; + } + if(!v6 && !memcmp(p_addr_in, "\0\0\0\0", 4)) { + errno = ECONNREFUSED; + return -1; + } + + PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str))); + PDEBUG("port: %d\n", port); + PDEBUG("client socket: %d\n", sockfd); + + // check if connect called from proxydns + remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); + + // more specific first + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(dnats[i].orig_port && (dnats[i].orig_port == port)) + dnat = &dnats[i]; + + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(!dnats[i].orig_port) + dnat = &dnats[i]; + + if (dnat) { + p_addr_in = &dnat->new_dst; + if (dnat->new_port) + port = dnat->new_port; + } + + for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { + if (localnet_addr[i].port && localnet_addr[i].port != port) + continue; + if (localnet_addr[i].family != (v6 ? AF_INET6 : AF_INET)) + continue; + if (v6) { + size_t prefix_bytes = localnet_addr[i].in6_prefix / CHAR_BIT; + size_t prefix_bits = localnet_addr[i].in6_prefix % CHAR_BIT; + if (prefix_bytes && memcmp(p_addr_in6->s6_addr, localnet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0) + continue; + if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ localnet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits)) + continue; + } else { + if((p_addr_in->s_addr ^ localnet_addr[i].in_addr.s_addr) & localnet_addr[i].in_mask.s_addr) + continue; + } + PDEBUG("accessing localnet using true_sendmsg\n"); + return true_sendmsg(sockfd, msg, flags); + } + + // Check if a chain of UDP relay is already opened for this socket + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + // No chain is opened for this socket, open one + PDEBUG("opening new chain of relays for %d\n", sockfd); + if(NULL == (relay_chain = open_relay_chain(proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain))){ + PDEBUG("could not open a chain of relay\n"); + errno = ECONNREFUSED; + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + relay_chain->sockfd = sockfd; + add_relay_chain(&relay_chains, relay_chain); + DUMP_RELAY_CHAINS_LIST(relay_chains); + } + + + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); + + + // Allocate buffer for header creation + char send_buffer[65535]; //TODO maybe we can do better about size ? + size_t send_buffer_len = 65535; + + //Move iovec udp data contained in msg to one buffer + char udp_data[65535]; + size_t udp_data_len = 65535; + udp_data_len = write_iov_to_buf(udp_data, udp_data_len, msg->msg_iov, msg->msg_iovlen); + + // Exec socksify_udp_packet + int rc; + rc = socksify_udp_packet(udp_data, udp_data_len, *relay_chain, dest_ip, htons(port),send_buffer, &send_buffer_len); + if(rc != SUCCESS){ + PDEBUG("error socksify_udp_packet()\n"); + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + + + // send with true_sendmsg() + //prepare our msg + struct iovec iov[1]; + iov[0].iov_base = send_buffer; + iov[0].iov_len = send_buffer_len; + + + struct msghdr tmp_msg; + tmp_msg.msg_control = msg->msg_control; + tmp_msg.msg_controllen = msg->msg_controllen; + tmp_msg.msg_flags = msg->msg_flags; + tmp_msg.msg_iov = iov; + tmp_msg.msg_iovlen = 1; + + v6 = relay_chain->head->bnd_addr.is_v6 == ATYP_V6; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = relay_chain->head->bnd_port, + .sin_addr.s_addr = (in_addr_t) relay_chain->head->bnd_addr.addr.v4.as_int, + }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = relay_chain->head->bnd_port, + }; + if(v6) memcpy(&addr6.sin6_addr.s6_addr, relay_chain->head->bnd_addr.addr.v6, 16); + + + + tmp_msg.msg_name = (struct sockaddr*)(v6?(void*)&addr6:(void*)&addr); + tmp_msg.msg_namelen = v6?sizeof(addr6):sizeof(addr) ; + + MUTEX_UNLOCK(&relay_chains_mutex); + + //send it + + //Drop the MSG_DONTROUTE flag if it exists + if(flags & MSG_DONTROUTE){ + proxychains_write_log(LOG_PREFIX "dropping MSG_DONTROUTE flag\n"); + flags ^= MSG_DONTROUTE; + } + //Return EOPNOTSUPP if flag MSG_MORE is set + //TODO: implement MSG_MORE logic so that data from multiple sendto calls can be merged into one UDP datagram and sent to the SOCKS + if(flags & MSG_MORE){ + PDEBUG("error, MSG_MORE not yet supported\n"); + errno = EOPNOTSUPP; + return -1; + } + + int sent = 0; + sent = true_sendmsg(sockfd, &tmp_msg, flags); + if(-1 == sent){ + PDEBUG("error true_sendmsg\n"); + return -1; + } + PDEBUG("Successfully sent UDP packet with true_sendmsg()\n"); + + PDEBUG("Successful sendmsg() hook\n\n"); + return sent; +} + +HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, int flags){ + + PFUNC(); + int nmsg = -1; // The sendmmsg return code (-1 if error, otherwise number of messages sent) + int allocated_len = 0; // A counter for dynamic memory allocations, used in freeAndExit section + + // As the call contains multiple message, we only filter on the first one address type :) + + struct sockaddr_storage first_dest_addr; + socklen_t first_addrlen = sizeof(first_dest_addr); + + if(msgvec[0].msg_hdr.msg_name == NULL){ // try to find a peer addr that could have been set with connect() + int rc = 0; + rc = getpeername(sockfd, (struct sockaddr*)&first_dest_addr, &first_addrlen); + if(rc != SUCCESS){ + PDEBUG("error in getpeername(): %d\n", errno); + goto freeAndExit; + } + } else { + if(msgvec[0].msg_hdr.msg_namelen > first_addrlen){ + PDEBUG("msgvec[0].msg_hdr.msg_namelen too long\n"); + return -1; + } + first_addrlen = msgvec[0].msg_hdr.msg_namelen; + memcpy(&first_dest_addr, msgvec[0].msg_hdr.msg_name, first_addrlen); + } + + + + DEBUGDECL(char str[256]); + int socktype = 0, ret = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + sa_family_t fam = SOCKFAMILY(first_dest_addr); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if(!((fam == AF_INET || fam == AF_INET6) && socktype == SOCK_DGRAM)){ + nmsg = true_sendmmsg(sockfd, msgvec, vlen, flags); + goto freeAndExit; + } + + // Check if a chain of UDP relay is already opened for this socket + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + // No chain is opened for this socket, open one + PDEBUG("opening new chain of relays for %d\n", sockfd); + if(NULL == (relay_chain = open_relay_chain(proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain))){ + PDEBUG("could not open a chain of relay\n"); + errno = ECONNREFUSED; + MUTEX_UNLOCK(&relay_chains_mutex); + goto freeAndExit; + } + relay_chain->sockfd = sockfd; + add_relay_chain(&relay_chains, relay_chain); + DUMP_RELAY_CHAINS_LIST(relay_chains); + + } + + + // Prepare our mmsg + struct mmsghdr* tmp_msgvec = NULL; + if(NULL == (tmp_msgvec = (struct mmsghdr*)calloc(vlen, sizeof(struct mmsghdr)))){ + PDEBUG("error allocating memory for tmp_mmsghdr\n"); + MUTEX_UNLOCK(&relay_chains_mutex); + goto freeAndExit; + } + + + + for(int msg_index=0; msg_index addrlen){ + PDEBUG("msgvec[%d].msg_hdr.msg_namelen too long\n", msg_index); + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + addrlen = msgvec[msg_index].msg_hdr.msg_namelen; + memcpy(&dest_addr, msgvec[msg_index].msg_hdr.msg_name, addrlen); + } + + ip_type dest_ip; + struct in_addr *p_addr_in; + struct in6_addr *p_addr_in6; + dnat_arg *dnat = NULL; + size_t i; + int remote_dns_connect = 0; + unsigned short port; + int v6 = dest_ip.is_v6 = fam == AF_INET6; + + p_addr_in = &((struct sockaddr_in *) &dest_addr)->sin_addr; + p_addr_in6 = &((struct + sockaddr_in6 *) &dest_addr)->sin6_addr; + port = !v6 ? ntohs(((struct sockaddr_in *) &dest_addr)->sin_port) + : ntohs(((struct sockaddr_in6 *) &dest_addr)->sin6_port); + struct in_addr v4inv6; + if(v6 && is_v4inv6(p_addr_in6)) { + memcpy(&v4inv6.s_addr, &p_addr_in6->s6_addr[12], 4); + v6 = dest_ip.is_v6 = 0; + p_addr_in = &v4inv6; + } + if(!v6 && !memcmp(p_addr_in, "\0\0\0\0", 4)) { + errno = ECONNREFUSED; + goto cleanCurrentLoop; + } + + PDEBUG("message %d/%d\n", msg_index+1, vlen); + PDEBUG("target: %s\n", inet_ntop(v6 ? AF_INET6 : AF_INET, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, str, sizeof(str))); + PDEBUG("port: %d\n", port); + PDEBUG("client socket: %d\n", sockfd); + + // check if connect called from proxydns + remote_dns_connect = !v6 && (ntohl(p_addr_in->s_addr) >> 24 == remote_dns_subnet); + + // more specific first + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(dnats[i].orig_port && (dnats[i].orig_port == port)) + dnat = &dnats[i]; + + if (!v6) for(i = 0; i < num_dnats && !remote_dns_connect && !dnat; i++) + if(dnats[i].orig_dst.s_addr == p_addr_in->s_addr) + if(!dnats[i].orig_port) + dnat = &dnats[i]; + + if (dnat) { + p_addr_in = &dnat->new_dst; + if (dnat->new_port) + port = dnat->new_port; + } + + for(i = 0; i < num_localnet_addr && !remote_dns_connect; i++) { + if (localnet_addr[i].port && localnet_addr[i].port != port) + continue; + if (localnet_addr[i].family != (v6 ? AF_INET6 : AF_INET)) + continue; + if (v6) { + size_t prefix_bytes = localnet_addr[i].in6_prefix / CHAR_BIT; + size_t prefix_bits = localnet_addr[i].in6_prefix % CHAR_BIT; + if (prefix_bytes && memcmp(p_addr_in6->s6_addr, localnet_addr[i].in6_addr.s6_addr, prefix_bytes) != 0) + continue; + if (prefix_bits && (p_addr_in6->s6_addr[prefix_bytes] ^ localnet_addr[i].in6_addr.s6_addr[prefix_bytes]) >> (CHAR_BIT - prefix_bits)) + continue; + } else { + if((p_addr_in->s_addr ^ localnet_addr[i].in_addr.s_addr) & localnet_addr[i].in_mask.s_addr) + continue; + } + PDEBUG("message %d/%d is accessing localnet\n", msg_index, vlen); + goto cleanCurrentLoop; + } + + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); + + // Allocate buffer for header creation + + if(NULL == (send_buffer = (char*)malloc(65535))){ + PDEBUG("error malloc\n"); + goto cleanCurrentLoop; + } + size_t send_buffer_len = 65535; + + //Move iovec udp data contained in msg to one buffer + char udp_data[65535]; + size_t udp_data_len = 65535; + + udp_data_len = write_iov_to_buf(udp_data, udp_data_len,msgvec[msg_index].msg_hdr.msg_iov ,msgvec[msg_index].msg_hdr.msg_iovlen); + + // Exec socksify_udp_packet + int rc; + rc = socksify_udp_packet(udp_data, udp_data_len, *relay_chain, dest_ip, htons(port),send_buffer, &send_buffer_len); + if(rc != SUCCESS){ + PDEBUG("error socksify_udp_packet()\n"); + goto cleanCurrentLoop; + } + + //prepare our msg + + if(NULL == (iov = (struct iovec*)calloc(1, sizeof(struct iovec)))){ + PDEBUG("error calloc\n"); + goto cleanCurrentLoop; + } + iov->iov_base = send_buffer; + iov->iov_len = send_buffer_len; + + + + tmp_msgvec[msg_index].msg_hdr.msg_control = msgvec[msg_index].msg_hdr.msg_control; + tmp_msgvec[msg_index].msg_hdr.msg_controllen = msgvec[msg_index].msg_hdr.msg_controllen; + tmp_msgvec[msg_index].msg_hdr.msg_flags = msgvec[msg_index].msg_hdr.msg_flags; + + tmp_msgvec[msg_index].msg_hdr.msg_iov = iov; + tmp_msgvec[msg_index].msg_hdr.msg_iovlen = 1; + + v6 = relay_chain->head->bnd_addr.is_v6 == ATYP_V6; + + if(!v6){ + + if(NULL == (pAddr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)))){ + PDEBUG("error malloc\n"); + goto cleanCurrentLoop; + } + pAddr->sin_family = AF_INET; + pAddr->sin_port = relay_chain->head->bnd_port; + pAddr->sin_addr.s_addr = (in_addr_t) relay_chain->head->bnd_addr.addr.v4.as_int; + + tmp_msgvec[msg_index].msg_hdr.msg_name = (struct sockaddr*)pAddr; + tmp_msgvec[msg_index].msg_hdr.msg_namelen = sizeof(*pAddr) ; + } else{ + + if(NULL == (pAddr6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6)))){ + PDEBUG("error malloc\n"); + goto cleanCurrentLoop; + } + pAddr6->sin6_family = AF_INET6; + pAddr6->sin6_port = relay_chain->head->bnd_port; + if(v6) memcpy(pAddr6->sin6_addr.s6_addr, relay_chain->head->bnd_addr.addr.v6, 16); + + tmp_msgvec[msg_index].msg_hdr.msg_name = (struct sockaddr*)pAddr6; + tmp_msgvec[msg_index].msg_hdr.msg_namelen = sizeof(*pAddr6); + } + + allocated_len += 1; + continue; + + cleanCurrentLoop: + if(send_buffer != NULL){ + free(send_buffer); + } + if(iov != NULL){ + free(iov); + } + if(pAddr != NULL){ + free(pAddr); + } + if(pAddr6 != NULL){ + free(pAddr6); + } + MUTEX_UNLOCK(&relay_chains_mutex); + goto freeAndExit; + } + + MUTEX_UNLOCK(&relay_chains_mutex); + + //Drop the MSG_DONTROUTE flag if it exists + if(flags & MSG_DONTROUTE){ + proxychains_write_log(LOG_PREFIX "dropping MSG_DONTROUTE flag\n"); + flags ^= MSG_DONTROUTE; + } + //Return EOPNOTSUPP if flag MSG_MORE is set + //TODO: implement MSG_MORE logic so that data from multiple sendto calls can be merged into one UDP datagram and sent to the SOCKS + if(flags & MSG_MORE){ + PDEBUG("error, MSG_MORE not yet supported\n"); + errno = EOPNOTSUPP; + return -1; + } + + nmsg = true_sendmmsg(sockfd, tmp_msgvec, vlen, flags); + + if(nmsg == -1){ + PDEBUG("error true_sendmmsg: %d - %s\n", errno, strerror(errno) ); + goto freeAndExit; + } + + // Update msg_len values of msgvec for the nmsg sent messages + for(int i=0; iiov_base); + free(tmp_msgvec[i].msg_hdr.msg_iov); + } + if(NULL != tmp_msgvec){ + free(tmp_msgvec); + } + + return nmsg; +} + +HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ + + + INIT(); + PFUNC(); + + int socktype = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if( socktype != SOCK_DGRAM){ + PDEBUG("sockfd %d is not a SOCK_DGRAM socket, returning to true_recvmsg\n", sockfd); + return true_recvmsg(sockfd, msg, flags); + } + PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); + + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + if(SUCCESS != getsockname(sockfd, (struct sockaddr*)&addr, &addr_len )){ + PDEBUG("error getsockname, errno=%d. Returning to true_recvmsg()\n", errno); + return true_recvmsg(sockfd,msg, flags); + } + sa_family_t fam = SOCKFAMILY(addr); + if(!(fam == AF_INET || fam == AF_INET6)){ + PDEBUG("sockfd %d address familiy is not a AF_INET or AF_INET6, returning to true_recvmsg\n", sockfd); + return true_recvmsg(sockfd,msg, flags); + } + + PDEBUG("sockfd %d's address family is AF_INET or AF_INET6\n", sockfd); + + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + // No chain is opened for this socket + PDEBUG("sockfd %d does not corresponds to any opened relay chain, returning to true_recvmsg\n", sockfd); + MUTEX_UNLOCK(&relay_chains_mutex); + return true_recvmsg(sockfd,msg, flags); + } + PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); + + + char buffer[RECV_BUFFER_SIZE]; //buffer to receive and decapsulate a UDP relay packet + size_t bytes_received; + + int trunc = flags & MSG_TRUNC; + + struct sockaddr_storage from; + + + + struct iovec iov[1]; + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + + + struct msghdr tmp_msg; + + tmp_msg.msg_name = (void *)&from; + tmp_msg.msg_namelen = sizeof(from); + tmp_msg.msg_iov = iov; + tmp_msg.msg_iovlen = 1; + tmp_msg.msg_control = msg->msg_control; // Pass directly + tmp_msg.msg_controllen = msg->msg_controllen; // Pass directly + tmp_msg.msg_flags = msg->msg_flags; + + PDEBUG("exec true_recvmsg\n"); + bytes_received = true_recvmsg(sockfd, &tmp_msg, flags); + if(-1 == bytes_received){ + PDEBUG("true_recvmsg returned -1, errno: %d, %s\n", errno,strerror(errno)); + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + if(RECV_BUFFER_SIZE == bytes_received){ + PDEBUG("UDP PACKET SHOULD NOT BE THAT BIG\n"); + } + + // Transfer the fields we do not manage + + msg->msg_controllen = tmp_msg.msg_controllen; + msg->msg_control = tmp_msg.msg_control; //Not sure this one is necessary + msg->msg_flags = tmp_msg.msg_flags; + + PDEBUG("successful recvmsg(), %d bytes received\n", bytes_received); + //Check that the packet was received from the first relay of the chain + DUMP_BUFFER(tmp_msg.msg_name, tmp_msg.msg_namelen); + DUMP_BUFFER(relay_chain->head->bnd_addr.addr.v4.octet, 4); + if(!is_from_chain_head(*relay_chain, (struct sockaddr *)(tmp_msg.msg_name))){ + PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); + // Write the data we received in tmp_msg to msg + int written = write_buf_to_iov(buffer, bytes_received, msg->msg_iov, msg->msg_iovlen); + + // Write the addr we received in tmp_msg to msg + if(msg->msg_name != NULL){ + socklen_t min = (msg->msg_namelen>tmp_msg.msg_namelen)?tmp_msg.msg_namelen:msg->msg_namelen; + memcpy(msg->msg_name, tmp_msg.msg_name, min); + msg->msg_namelen = min; + } + MUTEX_UNLOCK(&relay_chains_mutex); + return trunc?bytes_received:written; //if MSG_TRUNC flag is set, return the real length of the packet/datagram even when it was longer than the passed buffer (msg->msg_iov) + } + + PDEBUG("packet received from the proxy chain's head\n"); + + + int rc; + ip_type src_ip; + unsigned short src_port; + void* udp_data = NULL; + size_t udp_data_len = 0; + + rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); + MUTEX_UNLOCK(&relay_chains_mutex); + if(rc != SUCCESS){ + PDEBUG("error unSOCKSing the UDP packet\n"); + return -1; + } + PDEBUG("UDP packet successfully unSOCKified\n"); + udp_data_len = bytes_received - (udp_data - (void*)buffer); + + /*debug*/ + DEBUGDECL(char str[256]); + PDEBUG("received %d bytes through receive_udp_packet()\n", udp_data_len); + PDEBUG("data: "); + DUMP_BUFFER(udp_data, udp_data_len); + PDEBUG("src_ip: "); + DUMP_BUFFER(src_ip.addr.v6, src_ip.is_v6?16:4); + PDEBUG("src_ip: %s\n", inet_ntop(src_ip.is_v6 ? AF_INET6 : AF_INET, src_ip.is_v6 ? (void*)src_ip.addr.v6 : (void*)src_ip.addr.v4.octet, str, sizeof(str))); + PDEBUG("from_port: %hu\n", ntohs(src_port)); + /*end debug*/ + + + // Write the udp data we received in tmp_msg and unsocksified to msg + int written = write_buf_to_iov(udp_data, udp_data_len, msg->msg_iov, msg->msg_iovlen); + + // Overwrite the addresse in msg with the src_addr retrieved from unsocks_udp_packet(); + + if(msg->msg_name != NULL){ + struct sockaddr_in* src_addr_v4; + struct sockaddr_in6* src_addr_v6; + + if(src_ip.is_v6 && is_v4inv6((struct in6_addr*)src_ip.addr.v6)){ + PDEBUG("src_ip is v4 in v6 ip\n"); + if(msg->msg_namelen < sizeof(struct sockaddr_in)){ + PDEBUG("msg_namelen too short for ipv4\n"); + } + src_addr_v4 = (struct sockaddr_in*)(msg->msg_name); + src_addr_v4->sin_family = AF_INET; + src_addr_v4->sin_port = src_port; + memcpy(&(src_addr_v4->sin_addr.s_addr), src_ip.addr.v6+12, 4); + msg->msg_namelen = sizeof(struct sockaddr_in); + } + else if(src_ip.is_v6){ + PDEBUG("src_ip is true v6\n"); + if(msg->msg_namelen < sizeof(struct sockaddr_in6)){ + PDEBUG("addrlen too short for ipv6\n"); + return -1; + } + src_addr_v6 = (struct sockaddr_in6*)(msg->msg_name); + src_addr_v6->sin6_family = AF_INET6; + src_addr_v6->sin6_port = src_port; + memcpy(src_addr_v6->sin6_addr.s6_addr, src_ip.addr.v6, 16); + msg->msg_namelen = sizeof(struct sockaddr_in6); + }else { + if(msg->msg_namelen < sizeof(struct sockaddr_in)){ + PDEBUG("addrlen too short for ipv4\n"); + } + src_addr_v4 = (struct sockaddr_in*)(msg->msg_name); + src_addr_v4->sin_family = AF_INET; + src_addr_v4->sin_port = src_port; + src_addr_v4->sin_addr.s_addr = (in_addr_t) src_ip.addr.v4.as_int; + msg->msg_namelen = sizeof(struct sockaddr_in); + } + } + PDEBUG("after recv dump : "); + DUMP_BUFFER(msg->msg_name, msg->msg_namelen); + + + PDEBUG("Successful recvmsg() hook\n\n"); + return trunc?udp_data_len:written;//if MSG_TRUNC flag is set, return the real length of the packet/datagram even when it was longer than the passed buffer (msg->msg_iov) +} + + + + +HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ + INIT(); + PFUNC(); + + return recvfrom(sockfd, buf, len, flags, NULL, NULL); +} + +HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen){ + INIT(); + PFUNC(); + DEBUGDECL(char str[256]); + int socktype = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if( socktype != SOCK_DGRAM){ + PDEBUG("sockfd %d is not a SOCK_DGRAM socket, returning to true_recvfrom\n", sockfd); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + } + PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); + + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + if(SUCCESS != getsockname(sockfd, (struct sockaddr*)&addr, &addr_len )){ + PDEBUG("error getsockname, errno=%d. Returning to true_recvfrom()\n", errno); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + } + sa_family_t fam = SOCKFAMILY(addr); + if(!(fam == AF_INET || fam == AF_INET6)){ + PDEBUG("sockfd %d address familiy is not a AF_INET or AF_INET6, returning to true_recvfrom\n", sockfd); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + } + + PDEBUG("sockfd %d's address family is AF_INET or AF_INET6\n", sockfd); + + PDEBUG("waiting for mutex\n"); + MUTEX_LOCK(&relay_chains_mutex); + PDEBUG("got mutex\n"); + udp_relay_chain* relay_chain = get_relay_chain(relay_chains, sockfd); + if(relay_chain == NULL){ + // No chain is opened for this socket + PDEBUG("sockfd %d does not corresponds to any opened relay chain, returning to true_recvfrom\n", sockfd); + MUTEX_UNLOCK(&relay_chains_mutex); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + } + PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); + + + + char buffer[RECV_BUFFER_SIZE]; //maximum theoretical size of a UDP packet. + int bytes_received; + ip_type src_ip; + unsigned short src_port; + + int trunc = flags & MSG_TRUNC; + + + struct sockaddr_storage from; + socklen_t from_len = sizeof(from); + bytes_received = true_recvfrom(sockfd, buffer, sizeof(buffer), flags, (struct sockaddr*)&from, &from_len); + if(-1 == bytes_received){ + PDEBUG("true_recvfrom returned -1\n"); + MUTEX_UNLOCK(&relay_chains_mutex); + return -1; + } + if(RECV_BUFFER_SIZE == bytes_received){ + PDEBUG("UDP PACKET SHOULD NOT BE THAT BIG\n"); + } + PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received); + PDEBUG("packet: "); + DUMP_BUFFER(buffer, bytes_received); + + //Check that the packet was received from the first relay of the chain + // i.e. does from == chain.head.bnd_addr ? + + if(!is_from_chain_head(*relay_chain, (struct sockaddr*)&from)){ + //TODO: Decide whether we should transfer such packets not coming from the proxy chain + PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); + int min = (bytes_received <= len)?bytes_received:len; + + memcpy(buf, buffer, min); + if(src_addr != NULL){ + socklen_t min_addr_len = (from_len<*addrlen)?from_len:*addrlen; + memcpy(src_addr, &from, min_addr_len); + *addrlen = min_addr_len; + } + MUTEX_UNLOCK(&relay_chains_mutex); + return trunc?bytes_received:min; //if MSG_TRUNC flag is set, return the real length of the packet/datagram even when it was longer than the passed buffer (buf) + } + PDEBUG("packet received from the proxy chain's head\n"); + + int rc; + void* udp_data = NULL; + size_t udp_data_len = 0; + rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); + MUTEX_UNLOCK(&relay_chains_mutex); + if(rc != SUCCESS){ + PDEBUG("error unsocksifying the UDP packet\n"); + return -1; + } + PDEBUG("UDP packet successfully unsocksifyied\n"); + udp_data_len = bytes_received - (udp_data - (void*)buffer); + + + + PDEBUG("received %d bytes through receive_udp_packet()\n", udp_data_len); + PDEBUG("data: "); + DUMP_BUFFER(udp_data, udp_data_len); + PDEBUG("from_addr: "); + DUMP_BUFFER(src_ip.addr.v6, src_ip.is_v6?16:4); + PDEBUG("from_addr: %s\n", inet_ntop(src_ip.is_v6 ? AF_INET6 : AF_INET, src_ip.is_v6 ? (void*)src_ip.addr.v6 : (void*)src_ip.addr.v4.octet, str, sizeof(str))); + PDEBUG("from_port: %hu\n", ntohs(src_port)); + + // Copy received UDP data to the buffer provided by the client + size_t min = (udp_data_len < len)?udp_data_len:len; + memcpy(buf, udp_data, min); + + if(src_addr != NULL){ // No need to fill src_addr if the passed pointer is NULL + struct sockaddr_in* src_addr_v4; + struct sockaddr_in6* src_addr_v6; + + if(src_ip.is_v6 && is_v4inv6((struct in6_addr*)src_ip.addr.v6)){ + PDEBUG("src_ip is v4 in v6 ip\n"); + if(addrlen < sizeof(struct sockaddr_in)){ + PDEBUG("addrlen too short for ipv4\n"); + } + src_addr_v4 = (struct sockaddr_in*)src_addr; + src_addr_v4->sin_family = AF_INET; + src_addr_v4->sin_port = src_port; + memcpy(&(src_addr_v4->sin_addr.s_addr), src_ip.addr.v6+12, 4); + *addrlen = sizeof(src_addr_v4); + } + else if(src_ip.is_v6){ + PDEBUG("src_ip is true v6\n"); + if(addrlen < sizeof(struct sockaddr_in6)){ + PDEBUG("addrlen too short for ipv6\n"); + return -1; + } + src_addr_v6 = (struct sockaddr_in6*)src_addr; + src_addr_v6->sin6_family = AF_INET6; + src_addr_v6->sin6_port = src_port; + memcpy(src_addr_v6->sin6_addr.s6_addr, src_ip.addr.v6, 16); + *addrlen = sizeof(src_addr_v6); + }else { + if(addrlen < sizeof(struct sockaddr_in)){ + PDEBUG("addrlen too short for ipv4\n"); + } + src_addr_v4 = (struct sockaddr_in*)src_addr; + src_addr_v4->sin_family = AF_INET; + src_addr_v4->sin_port = src_port; + src_addr_v4->sin_addr.s_addr = (in_addr_t) src_ip.addr.v4.as_int; + *addrlen = sizeof(src_addr_v4); + } + } + + PDEBUG("Successful recvfrom() hook\n\n"); + return trunc?udp_data_len:min; //if MSG_TRUNC flag is set, return the real length of the packet/datagram even when it was longer than the passed buffer (buf) +} + +HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ + INIT(); + PFUNC(); + + // Check if sockfd is a SOCK_DGRAM socket + + int socktype = 0; + socklen_t optlen = 0; + optlen = sizeof(socktype); + getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, &optlen); + if( socktype != SOCK_DGRAM){ + PDEBUG("sockfd %d is not a SOCK_DGRAM socket, returning to true_send\n", sockfd); + return true_send(sockfd, buf, len, flags); + } + + // Retreive the peer address the socket is connected to, and check it is of AF_INET or AF_INET6 family + + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + if(SUCCESS != getpeername(sockfd, (struct sockaddr*)&addr, &addr_len )){ + PDEBUG("error getpeername, errno=%d. Returning to true_send()\n", errno); + return true_send(sockfd, buf, len, flags); + } + + sa_family_t fam = SOCKFAMILY(addr); + if(!(fam == AF_INET || fam == AF_INET6)){ + PDEBUG("sockfd %d address familiy is not a AF_INET or AF_INET6, returning to true_send\n", sockfd); + return true_send(sockfd, buf, len, flags); + } + + // Call the sendto() hook with the send() parameters and the retrieved peer address + return sendto(sockfd, buf, len, flags, (struct sockaddr*)&addr, addr_len); +} + + +HOOKFUNC(ssize_t, read,int fd, void* buf, size_t count){ + + // If fd is a socket, call recv() with no flags as it is equivalent to read() + // WARNING: As stated in https://man7.org/linux/man-pages/man2/recv.2.html in NOTES, + //"If a zero-length datagram is pending, read(2) and recv() with a + // flags argument of zero provide different behavior. In this + // circumstance, read(2) has no effect (the datagram remains + // pending), while recv() consumes the pending datagram." + + struct stat statbuf; + fstat(fd, &statbuf); + if(S_ISSOCK(statbuf.st_mode)){ + PDEBUG("hooked read() on a socket file descriptor, calling recv() with 0 flags\n"); + return recv(fd, buf, count, 0); + } + return true_read(fd, buf, count); +} + +HOOKFUNC(ssize_t, write, int fd, const void* buf, size_t count ){ + + + // If fd is a socket, call send() with no flags as it is equivalent to write() + struct stat statbuf; + fstat(fd, &statbuf); + if(S_ISSOCK(statbuf.st_mode)){ + PDEBUG("hooked write() on a socket file descriptor, calling send() with 0 flags\n"); + return send(fd, buf,count, 0); + } + return true_write(fd, buf, count); } #ifdef MONTEREY_HOOKING @@ -913,17 +2216,27 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, static void setup_hooks(void) { SETUP_SYM(connect); + SETUP_SYM(getpeername); + SETUP_SYM(send); SETUP_SYM(sendto); + SETUP_SYM(recvfrom); + SETUP_SYM(recvmsg); + SETUP_SYM(sendmsg); + SETUP_SYM(sendmmsg); + SETUP_SYM(recv); SETUP_SYM(gethostbyname); SETUP_SYM(getaddrinfo); SETUP_SYM(freeaddrinfo); SETUP_SYM(gethostbyaddr); SETUP_SYM(getnameinfo); + SETUP_SYM(write); + SETUP_SYM(read); #ifdef IS_SOLARIS SETUP_SYM(__xnet_connect); #endif SETUP_SYM(close); SETUP_SYM_OPTIONAL(close_range); + SETUP_SYM_OPTIONAL(uv_close); } #ifdef MONTEREY_HOOKING diff --git a/src/rdns.c b/src/rdns.c index d9496b1..ea7cb67 100644 --- a/src/rdns.c +++ b/src/rdns.c @@ -22,9 +22,9 @@ size_t rdns_daemon_get_host_for_ip(ip_type4 ip, char* readbuf) { .m.ip = ip, }; int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); - sendto(fd, &msg, sizeof(msg.h)+4, 0, (void*)&rdns_server, sizeof(rdns_server)); - recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); - close(fd); + true_sendto(fd, &msg, sizeof(msg.h)+4, 0, (void*)&rdns_server, sizeof(rdns_server)); + true_recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); + true_close(fd); msg.h.datalen = ntohs(msg.h.datalen); if(!msg.h.datalen || msg.h.datalen > 256) return 0; memcpy(readbuf, msg.m.host, msg.h.datalen); @@ -39,9 +39,9 @@ static ip_type4 rdns_daemon_get_ip_for_host(char* host, size_t len) { memcpy(msg.m.host, host, len+1); msg.h.datalen = htons(len+1); int fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); - sendto(fd, &msg, sizeof(msg.h)+len+1, 0, (void*)&rdns_server, sizeof(rdns_server)); - recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); - close(fd); + true_sendto(fd, &msg, sizeof(msg.h)+len+1, 0, (void*)&rdns_server, sizeof(rdns_server)); + true_recvfrom(fd, &msg, sizeof msg, 0, (void*)0, (void*)0); + true_close(fd); if(ntohs(msg.h.datalen) != 4) return IPT4_INT(-1); return msg.m.ip; }