From 39ff28a2bc1c2c21482f34e00b9cc3196ab36da8 Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 5 Sep 2023 18:52:16 +0200 Subject: [PATCH 01/35] adding missing hooks --- src/core.h | 6 ++++++ src/libproxychains.c | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/core.h b/src/core.h index 3edece8..de843c2 100644 --- a/src/core.h +++ b/src/core.h @@ -115,6 +115,12 @@ 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); extern connect_t true_connect; diff --git a/src/libproxychains.c b/src/libproxychains.c index 84a8f00..607df37 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -64,6 +64,9 @@ 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; int tcp_read_time_out; int tcp_connect_time_out; @@ -685,7 +688,7 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) sa_family_t fam = SOCKFAMILY(*addr); getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &optlen); 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; @@ -902,6 +905,25 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); } +HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ + INIT(); + PFUNC(); + return true_recv(sockfd, buf, len, flags); +} + +HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen){ + INIT(); + PFUNC(); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); +} + +HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ + INIT(); + PFUNC(); + return true_send(sockfd, buf, len, flags); +} + #ifdef MONTEREY_HOOKING #define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = &X; } while(0) #define SETUP_SYM_OPTIONAL(X) @@ -913,7 +935,10 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, static void setup_hooks(void) { SETUP_SYM(connect); + SETUP_SYM(send); SETUP_SYM(sendto); + SETUP_SYM(recvfrom); + SETUP_SYM(recv); SETUP_SYM(gethostbyname); SETUP_SYM(getaddrinfo); SETUP_SYM(freeaddrinfo); From 2c5ad9f81ac8dc74e7fd6c4a8d53c3564e61be49 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 6 Sep 2023 02:22:35 +0200 Subject: [PATCH 02/35] udp wip --- src/core.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ src/core.h | 40 ++++++++++++++++++++++++++++++++++++++ src/libproxychains.c | 5 +++++ 3 files changed, 91 insertions(+) diff --git a/src/core.c b/src/core.c index 80f443e..eabcb66 100644 --- a/src/core.c +++ b/src/core.c @@ -423,6 +423,52 @@ 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*/ +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){ + //TODO hugoc + return SUCCESS; +} + +/* Fills buf with the SOCKS5 udp request header for the target dst_addr:dst_port*/ +static int udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, char * buf, size_t buflen) { + + if (buflen <= 262) { //TODO: make something cleaner + 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 + + int v6 = dst_addr.atyp == ATYP_V6; + 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; +} + +static int encapsulate_udp_packet(udp_relay_chain rcd, ip_type target_addr, unsigned short target_port, char frag) { + +} + + #define TP " ... " #define DT "Dynamic chain" #define ST "Strict chain" diff --git a/src/core.h b/src/core.h index de843c2..c4f96ed 100644 --- a/src/core.h +++ b/src/core.h @@ -64,6 +64,7 @@ typedef enum { FIFOLY } select_type; + typedef struct { sa_family_t family; unsigned short port; @@ -93,6 +94,43 @@ typedef struct { char pass[256]; } proxy_data; + + +typedef enum { + ATYP_V4 = 0x01, + ATYP_V6 = 0x04, + ATYP_DOM = 0x03 +} ATYP; + +typedef struct{ + ATYP atyp; + union { + ip_type4 v4; + unsigned char v6[16]; + struct { + char len; + char name[255]; + } dom; + } addr ; +} 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 { + int tcp_sockfd; // the tcp socket on which the UDP_ASSOCIATE command has been issued. Closing this fd closes the udp relay. + socks5_addr 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. + socks5_addr dst_addr; // ?? the DST_ADDR sent in the UDP_ASSOCIATE command. + unsigned short dst_port; // ?? the DST_PORT sent in the UDP_ASSOCIATE command. +} udp_relay_data; + +/* A structure to hold the chain of udp relay servers assiociated with a client socket */ +typedef struct { + int sockfd; // the client socket for which the chain of relays has been set up + udp_relay_data * ud; // an array of relay, ud[0] being the closest to the client and u[len(ud)-1] the closest to the targets + unsigned int relay_count; +} udp_relay_chain; + 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 ); @@ -147,6 +185,8 @@ 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); + #include "debug.h" #endif diff --git a/src/libproxychains.c b/src/libproxychains.c index 607df37..2e2022d 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -902,12 +902,15 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, addrlen = 0; flags &= ~MSG_FASTOPEN; } + //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 + return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); } HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ INIT(); PFUNC(); + //TODO hugoc return true_recv(sockfd, buf, len, flags); } @@ -915,12 +918,14 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen){ INIT(); PFUNC(); + //TODO hugoc return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); } HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ INIT(); PFUNC(); + //TODO hugoc return true_send(sockfd, buf, len, flags); } From 8348e426086bd9eda2b2d33edceb179aee0ac6e9 Mon Sep 17 00:00:00 2001 From: hugoc Date: Fri, 8 Sep 2023 14:42:52 +0200 Subject: [PATCH 03/35] udp wip 2 --- src/core.c | 527 ++++++++++++++++++++++++++++++++++++++++++- src/core.h | 29 ++- src/libproxychains.c | 104 ++++++++- 3 files changed, 646 insertions(+), 14 deletions(-) diff --git a/src/core.c b/src/core.c index eabcb66..a911dd2 100644 --- a/src/core.c +++ b/src/core.c @@ -424,16 +424,152 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c } -/* Given a socket connected to a SOCKS5 proxy server, performs a UDP_ASSOCIATE handshake and returns BND_ADDR and BND_PORT if successfull*/ -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){ +/* 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, socks5_addr* bnd_addr, unsigned short* bnd_port, char* user, char* pass){ //TODO hugoc + + 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; + + bnd_addr->atyp = buff[3]; + + switch (buff[3]) { + case 1: + len = 4; + break; + case 4: + len = 16; + break; + case 3: + PDEBUG("BND_ADDR in UDP_ASSOCIATE response should not be a domain name!\n"); + goto err; + break; + default: + goto err; + } + + if(len != read_n_bytes(sock, (char *) buff, len)) + goto err; + + memcpy(bnd_addr->addr.v6, buff+4,(len==16)?16:4); + + 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 udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, char * buf, size_t buflen) { +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 (buflen <= 262) { //TODO: make something cleaner + if(dst_addr.atyp == ATYP_DOM){ + size = dst_addr.addr.dom.len; + } else { + size = v6?16:4; + } + + if (buflen <= size) { return -1; } @@ -443,7 +579,7 @@ static int udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, buf[buf_iter++] = frag; // frag buf[buf_iter++] = dst_addr.atyp; // atyp - int v6 = dst_addr.atyp == ATYP_V6; + switch (dst_addr.atyp){ case ATYP_V6: case ATYP_V4: @@ -464,7 +600,147 @@ static int udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, return buf_iter; } -static int encapsulate_udp_packet(udp_relay_chain rcd, ip_type target_addr, unsigned short target_port, char frag) { +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) { + + 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 target_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(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) { + target_addr.atyp = ATYP_DOM; + dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name); + if(!dns_len) goto err; + else dns_name = target_addr.addr.dom.name; + target_addr.addr.dom.len = dns_len && 0xFF; + + + } else { + if(target_ip.is_v6){ + target_addr.atyp = ATYP_V6; + memcpy(target_addr.addr.v6, target_ip.addr.v6, 16); + + } else { + target_addr.atyp = ATYP_V4; + memcpy(target_addr.addr.v4.octet, target_ip.addr.v4.octet, 4); + } + } + + PDEBUG("host dns %s\n", dns_name ? dns_name : ""); + + + + // Allocate a new buffer for the packet data and all the headers + unsigned int headers_size = 0; + udp_relay_node * tmp = chain.head; + int len = 0; + while(tmp->next != NULL){ + + switch ((tmp->next)->bnd_addr.atyp) + { + case ATYP_V4: + len = 4; + break; + case ATYP_V6: + len = 6; + break; + case ATYP_DOM: + len = (tmp->next)->bnd_addr.addr.dom.len; + break; + default: + break; + } + + headers_size += len; + tmp = tmp->next; + } + + switch (target_addr.atyp) + { + case ATYP_V4: + len = 4; + break; + case ATYP_V6: + len = 6; + break; + case ATYP_DOM: + len = target_addr.addr.dom.len; + break; + default: + break; + } + + headers_size += len; + + char * buff = NULL; + if (NULL == (buff = (char*)malloc(headers_size+data_len))){ + PDEBUG("error malloc buffer\n"); + return -1; + } + + + // Append each header to the buffer + + unsigned int written = 0; + unsigned int offset = 0; + + tmp = chain.head; + while (tmp->next != NULL) + { + written = write_udp_header((tmp->next)->bnd_addr, (tmp->next)->bnd_port, 0, buff+offset, headers_size + data_len - offset); + if (written == -1){ + PDEBUG("error write_udp_header\n"); + goto err; + } + offset += written; + + tmp = tmp->next; + } + + written = write_udp_header(target_addr, target_port, 0, buff + offset, headers_size + data_len - offset); + if (written == -1){ + PDEBUG("error write_udp_header\n"); + goto err; + } + offset += written; + + // Append data to the buffer + memcpy(buff + offset, data, data_len); + + // Send the packet + // FIXME: should write_n_bytes be used here instead ? + + if(chain.head->bnd_addr.atyp == ATYP_DOM){ + PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); + goto err; + } + int v6 = chain.head->bnd_addr.atyp == ATYP_V6; + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = chain.head->bnd_port, + .sin_addr.s_addr = (in_addr_t) chain.head->bnd_addr.addr.v4.as_int, + }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = chain.head->bnd_port, + }; + if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); + + sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + + err: + free(buff); + return -1; + } @@ -474,8 +750,10 @@ static int encapsulate_udp_packet(udp_relay_chain rcd, ip_type target_addr, unsi #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); @@ -514,6 +792,9 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { } static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { + PFUNC(); + PDEBUG("offset: %d\n", *offset); + PDEBUG("state: %d\n", pd[0].ps); unsigned int i = 0, k = 0; if(*offset >= proxy_count) return NULL; @@ -780,6 +1061,240 @@ int connect_proxy_chain(int sock, ip_type target_ip, return -1; } +// int connect_to_lastnode(int *sock, udp_relay_chain chain){ + +// udp_relay_node * current_node = chain.head; + +// //First connect to the chain head +// if(SUCCESS != start_chain(sock, &(current_node->pd), UDPC)){ +// PDEBUG("start_chain failed\n"); +// return -1; +// } +// // Connect to the rest of the chain +// while(current_node->next != NULL){ +// if(SUCCESS != chain_step(sock, &(current_node->pd), &(current_node->next->pd))){ +// PDEBUG("chain step failed\n"); +// return -1; +// } +// current_node = current_node->next; +// } + +// return SUCCESS; +// } + +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; + } + + 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){ + 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_nodes(udp_relay_chain chain){ + if(chain.head == NULL){ + return SUCCESS; + } + + udp_relay_node * current = chain.head; + udp_relay_node * next = NULL; + + while(current != NULL){ + next = current->next; + + close(current->tcp_sockfd); + free(current); + + current = next; + } + + 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; + + + 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->pt = BLOCKED_STATE; + goto error; + } + p1->pt = 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_nodes(*new_chain); + free(new_chain); + errno = ETIMEDOUT; + return NULL; +} + + +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; + free(chain); + } + } else if (chain = chains_list->tail){ + chains_list->tail = chain->prev; + 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); diff --git a/src/core.h b/src/core.h index c4f96ed..cddf92f 100644 --- a/src/core.h +++ b/src/core.h @@ -109,28 +109,38 @@ typedef struct{ unsigned char v6[16]; struct { char len; - char name[255]; + char name[256]; } dom; } addr ; } 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 { +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 socks5_addr 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. socks5_addr dst_addr; // ?? the DST_ADDR sent in the UDP_ASSOCIATE command. unsigned short dst_port; // ?? the DST_PORT sent in the UDP_ASSOCIATE command. -} udp_relay_data; + 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 { +typedef struct s_udp_relay_chain { int sockfd; // the client socket for which the chain of relays has been set up - udp_relay_data * ud; // an array of relay, ud[0] being the closest to the client and u[len(ud)-1] the closest to the targets - unsigned int relay_count; + udp_relay_node * head; // head of the linked list of udp_relay_node + 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 ); @@ -185,7 +195,12 @@ 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); +static int udp_associate(int sock, ip_type * dst_addr, unsigned short dst_port, socks5_addr *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); +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); #include "debug.h" diff --git a/src/libproxychains.c b/src/libproxychains.c index 2e2022d..09b1139 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -84,6 +84,8 @@ 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_once_t init_once = PTHREAD_ONCE_INIT; static int init_l = 0; @@ -901,10 +903,110 @@ 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); } + //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 + 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_sendto(sockfd, buf, len, flags, 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); + + // 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 + 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; + return -1; + } + relay_chain->sockfd = sockfd; + add_relay_chain(&relay_chains, relay_chain); + } - return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); + if (SUCCESS != send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len)){ + PDEBUG("could not send udp packet\n"); + errno = ECONNREFUSED; + return -1; + } + + return SUCCESS; } HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ From 68180a6b66e035b403deb16564f3dad709e94d6e Mon Sep 17 00:00:00 2001 From: hugoc Date: Mon, 11 Sep 2023 13:22:16 +0200 Subject: [PATCH 04/35] bug fixes --- src/core.c | 24 ++++++++++++++++-------- src/core.h | 1 + 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/core.c b/src/core.c index a911dd2..042f5a9 100644 --- a/src/core.c +++ b/src/core.c @@ -544,7 +544,7 @@ either of them. */ if(len != read_n_bytes(sock, (char *) buff, len)) goto err; - memcpy(bnd_addr->addr.v6, buff+4,(len==16)?16:4); + memcpy(bnd_addr->addr.v6, buff,(len==16)?16:4); if(2 != read_n_bytes(sock, (char *) buff, 2)) goto err; @@ -653,13 +653,13 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign len = 6; break; case ATYP_DOM: - len = (tmp->next)->bnd_addr.addr.dom.len; + len = (tmp->next)->bnd_addr.addr.dom.len + 1; break; default: break; } - headers_size += len; + headers_size += len + 6; tmp = tmp->next; } @@ -672,13 +672,13 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign len = 6; break; case ATYP_DOM: - len = target_addr.addr.dom.len; + len = target_addr.addr.dom.len + 1; break; default: break; } - headers_size += len; + headers_size += len + 6; char * buff = NULL; if (NULL == (buff = (char*)malloc(headers_size+data_len))){ @@ -735,7 +735,15 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign }; if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); - sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + int sent = 0; + + sent = true_sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + if (sent != offset+data_len){ + PDEBUG("true_sendto error\n"); + goto err; + } + + return SUCCESS; err: free(buff); @@ -1221,10 +1229,10 @@ udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, cha 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->pt = BLOCKED_STATE; + p1->ps = BLOCKED_STATE; goto error; } - p1->pt = BUSY_STATE; + p1->ps = BUSY_STATE; } return new_chain; diff --git a/src/core.h b/src/core.h index cddf92f..05c9e5d 100644 --- a/src/core.h +++ b/src/core.h @@ -177,6 +177,7 @@ 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; struct gethostbyname_data { struct hostent hostent_space; From 9f4cd23973fcec30c7751635de95777dad6533c7 Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 28 Nov 2023 20:20:36 +0100 Subject: [PATCH 05/35] implemented send hook logic --- src/libproxychains.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index 09b1139..fad976f 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -944,6 +944,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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); @@ -1005,7 +1006,8 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, errno = ECONNREFUSED; return -1; } - + + PDEBUG("Successfully sent UDP packet, leaving hook\n"); return SUCCESS; } @@ -1028,7 +1030,35 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ INIT(); PFUNC(); //TODO hugoc - return true_send(sockfd, buf, len, flags); + + //Checker si c'est une SOCK_DGRAM + AFINET ou AFINET6 + // Récupérer l'adresse liée avec getpeername + // Exécuter le hook sendto + 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); + } + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + + if(SUCCESS != getpeername(sockfd, &addr, &addr_len )){ + PDEBUG("error getpeername, errno=%d. Returning to true_send()\n", errno); + return true_send(sockfd, buf, len, flags); + } + //DEBUGDECL(char str[256]); + + 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); + } + + return sendto(sockfd, buf, len, flags, &addr, addr_len); } #ifdef MONTEREY_HOOKING From 560613256a0825593d9996bf6acde07b7d49ec33 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 29 Nov 2023 01:13:01 +0100 Subject: [PATCH 06/35] add read_udp_header() --- src/core.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/core.c b/src/core.c index 042f5a9..8464ee2 100644 --- a/src/core.c +++ b/src/core.c @@ -600,6 +600,51 @@ static int write_udp_header(socks5_addr dst_addr, unsigned short dst_port , char return buf_iter; } + +int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned short* src_port, char* frag) { + + 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++]; + + switch (src_addr->atyp) + { + case ATYP_DOM: + 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: + int 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; + break; + default: + break; + } + + memcpy(src_port, buf+buf_iter, 2); + buf_iter += 2; + + return buf_iter; +} + 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) { if (chain.head == NULL ){ From 48422d4c0773bc55e6115846d8fbe7d14a783b0a Mon Sep 17 00:00:00 2001 From: hugoc Date: Sun, 10 Dec 2023 16:03:04 +0100 Subject: [PATCH 07/35] add dump_buffer in debug --- src/debug.c | 8 ++++++++ src/debug.h | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/debug.c b/src/debug.c index 314aadd..cc52fc9 100644 --- a/src/debug.c +++ b/src/debug.c @@ -22,6 +22,14 @@ void dump_proxy_chain(proxy_data *pchain, unsigned int count) { } } +void dump_buffer(unsigned char * data, size_t len){ + printf("buffer_dump["); + for(int i=0; i Date: Sun, 10 Dec 2023 16:05:19 +0100 Subject: [PATCH 08/35] implements udp reception and fixes --- src/core.c | 227 ++++++++++++++++++++++++++++++++++++------- src/core.h | 13 ++- src/libproxychains.c | 99 ++++++++++++++++++- 3 files changed, 298 insertions(+), 41 deletions(-) diff --git a/src/core.c b/src/core.c index 8464ee2..cac8142 100644 --- a/src/core.c +++ b/src/core.c @@ -426,7 +426,7 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c /* 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, socks5_addr* bnd_addr, unsigned short* bnd_port, char* user, char* pass){ +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){ //TODO hugoc PFUNC(); @@ -524,27 +524,27 @@ either of them. */ if(buff[0] != 5 || buff[1] != 0) goto err; - bnd_addr->atyp = buff[3]; switch (buff[3]) { - case 1: - len = 4; + case ATYP_V4: + bnd_addr->is_v6 = 0; break; - case 4: - len = 16; + case ATYP_V6: + bnd_addr->is_v6 = 1; break; - case 3: + 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==16)?16:4); + memcpy(bnd_addr->addr.v6, buff,len); if(2 != read_n_bytes(sock, (char *) buff, 2)) goto err; @@ -603,6 +603,8 @@ static int write_udp_header(socks5_addr dst_addr, unsigned short dst_port , char 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; @@ -612,12 +614,14 @@ int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned s 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 ) { + if(buflen < (5 + 2 + src_addr->addr.dom.len) ) { PDEBUG("buffer too short to read the UDP header\n"); return -1; } @@ -627,8 +631,10 @@ int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned s case ATYP_V4: case ATYP_V6: - int v6 = src_addr->atyp == ATYP_V6; - if(buflen < 4 + 2 + v6?16:4 ){ + PDEBUG("UDP header with ATYP_V4/6 addr type\n"); + v6 = src_addr->atyp == ATYP_V6; + PDEBUG("buflen : %d\n", buflen); + if(buflen < (4 + 2 + v6?16:4) ){ PDEBUG("buffer too short to read the UDP header\n"); return -1; } @@ -645,6 +651,151 @@ int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned s return buf_iter; } +int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ){ + //receives data on sockfd, decapsulates the header for each relay in chain and check they match, returns UDP data and source address/port + + PFUNC(); + + char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 + int bytes_received; + struct sockaddr from; + socklen_t addrlen = sizeof(from); + PDEBUG("test\n"); + + bytes_received = true_recvfrom(sockfd, buffer,sizeof(buffer), 0, &from, &addrlen); + if(-1 == bytes_received){ + PDEBUG("true_receive returned -1\n"); + return -1; + } + + PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received); + //Check that the packet was received from the first relay of the chain + // i.e. does from == chain.head.bnd_addr ? + int from_isv6 = ((struct sockaddr_in *) &(from))->sin_family == AF_INET6; + int same_address = 0; + int same_port = 0; + + if(chain.head->bnd_addr.is_v6){ + if(from_isv6){ + same_address = memcmp(((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); + } + } + else{ + uint32_t from_v4_asint; + if(from_isv6){ + // Maybe from is a ipv4-mapped ipv6 ? // TODO: use the existing is_v4inv6 as in connect and sendto + memcpy(from_v4_asint, ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr + 11, 4); + } + else{ + from_v4_asint = (uint32_t)(((struct sockaddr_in *)&from)->sin_addr.s_addr); + } + + same_address = from_v4_asint == chain.head->bnd_addr.addr.v4.as_int; + } + + same_port = chain.head->bnd_port == from_isv6?((struct sockaddr_in6 *)&from)->sin6_port:((struct sockaddr_in *)&from)->sin_port; + + if(!(same_address && same_port)){ + PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); + int min = (bytes_received <= data_len)?bytes_received:data_len; + memcpy(data, buffer, min); + return min; + } + + PDEBUG("packet received from the proxy chain's head\n"); + // 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) + { + same_address = 0; + + + + rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, &header_port, &header_frag ); + if(-1 == rc){ + PDEBUG("error reading UDP header\n"); + return -1; + } + read += rc; + + int header_v6 = header_addr.atyp == ATYP_V6; + + if(tmp->next->bnd_port != header_port){ + PDEBUG("UDP header port is not equal to proxy node port, dropping packet\n"); + return -1; + } + + if(tmp->next->bnd_addr.is_v6){ + if(header_v6){ + same_address = memcmp(tmp->next->bnd_addr.addr.v6, header_addr.addr.v6, 16); + } + } + else{ + same_address = memcmp(&(tmp->next->bnd_addr.addr.v4), header_v6?(&(header_addr.addr.v6)+11):&(header_addr.addr.v4), 4); + } + + + if(!same_address){ + PDEBUG("UDP header addr is not equal to proxy node addr, 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 + char frag; + rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, src_port, &frag); + if(-1 == rc){ + PDEBUG("error reading UDP header\n"); + return -1; + } + read += rc; + + if(header_addr.atyp == ATYP_DOM){ // do the reverse mapping + PDEBUG("Fetching matching IP for hostname\n"); + DUMP_BUFFER(header_addr.addr.dom.name,header_addr.addr.dom.len); + ip_type4 tmp_ip = IPT4_INVALID; + char host_string[256]; + memcpy(host_string, header_addr.addr.dom.name, header_addr.addr.dom.len); + host_string[header_addr.addr.dom.len] = 0x00; + + tmp_ip = rdns_get_ip_for_host(host_string, header_addr.addr.dom.len); + if(tmp_ip.as_int == -1){ + PDEBUG("No matching IP found for hostname\n"); + return -1; + } + header_addr.atyp = ATYP_V4; + header_addr.addr.v4.as_int = tmp_ip.as_int; + + } + + src_addr->is_v6 = (header_addr.atyp == ATYP_V6); + if(src_addr->is_v6){ + memcpy(src_addr->addr.v6, header_addr.addr.v6, 16); + } else{ + src_addr->addr.v4.as_int = header_addr.addr.v4.as_int; + } + + + int min = ((bytes_received-read)>data_len)?data_len:(bytes_received-read); + memcpy(data,buffer+read, min); + + + return min; +} + 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) { if (chain.head == NULL ){ @@ -663,10 +814,11 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign if(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) { target_addr.atyp = ATYP_DOM; dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name); + PDEBUG("dnslen: %d\n", dns_len); if(!dns_len) goto err; else dns_name = target_addr.addr.dom.name; - target_addr.addr.dom.len = dns_len && 0xFF; - + target_addr.addr.dom.len = dns_len & 0xFF; + PDEBUG("dnslen in struct: %d\n", target_addr.addr.dom.len); } else { if(target_ip.is_v6){ @@ -689,20 +841,22 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign int len = 0; while(tmp->next != NULL){ - switch ((tmp->next)->bnd_addr.atyp) - { - case ATYP_V4: - len = 4; - break; - case ATYP_V6: - len = 6; - break; - case ATYP_DOM: - len = (tmp->next)->bnd_addr.addr.dom.len + 1; - break; - default: - break; - } + // switch ((tmp->next)->bnd_addr.atyp) + // { + // case ATYP_V4: + // len = 4; + // break; + // case ATYP_V6: + // len = 6; + // break; + // case ATYP_DOM: + // len = (tmp->next)->bnd_addr.addr.dom.len + 1; + // break; + // default: + // break; + // } + + len = (tmp->next)->bnd_addr.is_v6?16:4; headers_size += len + 6; tmp = tmp->next; @@ -740,7 +894,12 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign tmp = chain.head; while (tmp->next != NULL) { - written = write_udp_header((tmp->next)->bnd_addr, (tmp->next)->bnd_port, 0, buff+offset, headers_size + data_len - offset); + + 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, buff+offset, headers_size + data_len - offset); if (written == -1){ PDEBUG("error write_udp_header\n"); goto err; @@ -763,11 +922,11 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign // Send the packet // FIXME: should write_n_bytes be used here instead ? - if(chain.head->bnd_addr.atyp == ATYP_DOM){ - PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); - goto err; - } - int v6 = chain.head->bnd_addr.atyp == ATYP_V6; + // if(chain.head->bnd_addr.atyp == ATYP_DOM){ + // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); + // goto err; + // } + int v6 = chain.head->bnd_addr.is_v6 == ATYP_V6; struct sockaddr_in addr = { .sin_family = AF_INET, diff --git a/src/core.h b/src/core.h index 05c9e5d..422ad13 100644 --- a/src/core.h +++ b/src/core.h @@ -109,7 +109,7 @@ typedef struct{ unsigned char v6[16]; struct { char len; - char name[256]; + char name[255]; } dom; } addr ; } socks5_addr; @@ -119,9 +119,9 @@ 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 - socks5_addr bnd_addr; // the BND_ADDR returned by the udp relay server in the response to the UDP_ASSOCIATE command. + 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. - socks5_addr dst_addr; // ?? the DST_ADDR sent in 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; @@ -178,6 +178,9 @@ 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; struct gethostbyname_data { struct hostent hostent_space; @@ -196,13 +199,13 @@ 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, socks5_addr *bnd_addr, unsigned short *bnd_port, char *user, char *pass); +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); 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 receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ); #include "debug.h" #endif diff --git a/src/libproxychains.c b/src/libproxychains.c index fad976f..af1db43 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1015,7 +1015,7 @@ HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ INIT(); PFUNC(); //TODO hugoc - return true_recv(sockfd, buf, len, flags); + return recvfrom(sockfd, buf, len, flags, NULL, NULL); } HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, @@ -1023,7 +1023,102 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, INIT(); PFUNC(); //TODO hugoc - return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + 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 addr; + socklen_t addr_len = sizeof(addr); + if(SUCCESS != getsockname(sockfd, &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); + + + 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); + return true_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); + } + PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); + + // On lance un receive_udp_packet() + + char tmp_buffer[65535]; //maximum theoretical size of a UDP packet. + int bytes_received; + ip_type from_addr; + unsigned short from_port; + bytes_received = receive_udp_packet(sockfd, *relay_chain, &from_addr, &from_port, tmp_buffer, 65535); + + if(-1 == bytes_received){ + PDEBUG("true_recvfrom returned -1\n"); + return -1; + } + + PDEBUG("received %d bytes through receive_udp_packet()\n", bytes_received); + PDEBUG("data: "); + DUMP_BUFFER(tmp_buffer, bytes_received); + PDEBUG("from_addr: "); + DUMP_BUFFER(from_addr.addr.v6, from_addr.is_v6?16:4); + PDEBUG("from_addr: %s\n", inet_ntop(from_addr.is_v6 ? AF_INET6 : AF_INET, from_addr.is_v6 ? (void*)from_addr.addr.v6 : (void*)from_addr.addr.v4.octet, str, sizeof(str))); + PDEBUG("from_port: %hu\n", ntohs(from_port)); + + // WARNING : Est ce que si le client avait envoyé des packets UDP avec resolution DNS dans le socks, + // on doit lui filer comme address source pour les packets recu l'addresse de mapping DNS ? Si oui comment + // la retrouver ? + + int min = (bytes_received > len)?len:bytes_received; + memcpy(buf, tmp_buffer, min); + + if (src_addr == NULL){ // No need to fill src_addr in this case + return min; + } + + struct sockaddr_in* src_addr_v4; + struct sockaddr_in6* src_addr_v6; + + //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen + // + + if(from_addr.is_v6){ + 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 = from_port; + memcpy(src_addr_v6->sin6_addr.s6_addr, from_addr.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 = from_port; + src_addr_v4->sin_addr.s_addr = (in_addr_t) from_addr.addr.v4.as_int; + *addrlen = sizeof(src_addr_v4); + } + + + + return min; } HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ From 0ee4c00b5baadeea236a5c133bb1f7bb8f7415fc Mon Sep 17 00:00:00 2001 From: hugoc Date: Mon, 11 Dec 2023 01:04:45 +0100 Subject: [PATCH 09/35] add dump relay chain --- src/debug.c | 26 ++++++++++++++++++++++++++ src/debug.h | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/src/debug.c b/src/debug.c index cc52fc9..81ed643 100644 --- a/src/debug.c +++ b/src/debug.c @@ -30,6 +30,32 @@ void dump_buffer(unsigned char * data, size_t len){ printf("]\n"); } +void dump_relay_chains_list(udp_relay_chain_list list){ + udp_relay_chain* current; + current = list.head; + + PDEBUG("relay chains list dump: \n"); + while(current != NULL){ + dump_relay_chain(current); + current = current->next; + } +} + +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 9b4ff92..9645f1c 100644 --- a/src/debug.h +++ b/src/debug.h @@ -9,10 +9,13 @@ # 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) @@ -20,6 +23,8 @@ #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 From 45aed8644fa9104589004f4c5e9d1e99a73e791c Mon Sep 17 00:00:00 2001 From: hugoc Date: Mon, 11 Dec 2023 01:05:49 +0100 Subject: [PATCH 10/35] close relay chain and v4inv6 to v4 --- src/core.h | 1 + src/libproxychains.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/core.h b/src/core.h index 422ad13..57e5d64 100644 --- a/src/core.h +++ b/src/core.h @@ -203,6 +203,7 @@ static int udp_associate(int sock, ip_type * dst_addr, unsigned short dst_port, 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_nodes(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 receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ); diff --git a/src/libproxychains.c b/src/libproxychains.c index af1db43..2f628e9 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -593,6 +593,20 @@ HOOKFUNC(int, close, int fd) { errno = 0; return 0; } + + /***** UDP STUFF *******/ + + udp_relay_chain* chain = NULL; + + chain = get_relay_chain(relay_chains, fd); + if(NULL != chain){ + free_relay_chain_nodes(*chain); + del_relay_chain(&relay_chains, chain); + } + + + /***** END UDP STUFF *******/ + if(proxychains_resolver != DNSLF_RDNS_THREAD) return true_close(fd); /* prevent rude programs (like ssh) from closing our pipes */ @@ -999,6 +1013,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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); if (SUCCESS != send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len)){ @@ -1095,7 +1110,19 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen // - if(from_addr.is_v6){ + if(from_addr.is_v6 && is_v4inv6((struct in6_addr*)from_addr.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 = from_port; + memcpy(&(src_addr_v4->sin_addr.s_addr), from_addr.addr.v6+12, 4); + *addrlen = sizeof(src_addr_v4); + } + else if(from_addr.is_v6){ + PDEBUG("src_ip is true v6\n"); if(addrlen < sizeof(struct sockaddr_in6)){ PDEBUG("addrlen too short for ipv6\n"); return -1; From 8ed4b521405640642610603fc3e81080942308e7 Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 12 Dec 2023 00:27:51 +0100 Subject: [PATCH 11/35] separate functions, add utils, hook recvmsg --- src/core.c | 278 ++++++++++++++++++++++++++++++------------- src/core.h | 11 +- src/libproxychains.c | 192 +++++++++++++++++++++++++++++- 3 files changed, 397 insertions(+), 84 deletions(-) diff --git a/src/core.c b/src/core.c index cac8142..39d3362 100644 --- a/src/core.c +++ b/src/core.c @@ -633,13 +633,13 @@ int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned s case ATYP_V6: PDEBUG("UDP header with ATYP_V4/6 addr type\n"); v6 = src_addr->atyp == ATYP_V6; - PDEBUG("buflen : %d\n", buflen); 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; @@ -651,58 +651,81 @@ int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned s return buf_iter; } -int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ){ - //receives data on sockfd, decapsulates the header for each relay in chain and check they match, returns UDP data and source address/port - - PFUNC(); +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); } +} - PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received); - //Check that the packet was received from the first relay of the chain - // i.e. does from == chain.head.bnd_addr ? - int from_isv6 = ((struct sockaddr_in *) &(from))->sin_family == AF_INET6; - int same_address = 0; - int same_port = 0; +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; + } +} - if(chain.head->bnd_addr.is_v6){ - if(from_isv6){ - same_address = memcmp(((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); - } +int compare_socks5_addr_iptype(socks5_addr addr1, ip_type addr2){ + PFUNC(); + if(addr1.atyp == ATYP_DOM){ + //addr1 is a domain name + return 0; } - else{ - uint32_t from_v4_asint; - if(from_isv6){ - // Maybe from is a ipv4-mapped ipv6 ? // TODO: use the existing is_v4inv6 as in connect and sendto - memcpy(from_v4_asint, ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr + 11, 4); - } - else{ - from_v4_asint = (uint32_t)(((struct sockaddr_in *)&from)->sin_addr.s_addr); - } - same_address = from_v4_asint == chain.head->bnd_addr.addr.v4.as_int; + 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; } +} - same_port = chain.head->bnd_port == from_isv6?((struct sockaddr_in6 *)&from)->sin6_port:((struct sockaddr_in *)&from)->sin_port; +int is_from_chain_head(udp_relay_chain chain, struct sockaddr src_addr){ - if(!(same_address && same_port)){ - PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); - int min = (bytes_received <= data_len)?bytes_received:data_len; - memcpy(data, buffer, min); - return min; + if(compare_iptype_sockaddr(chain.head->bnd_addr, src_addr)){ + return (chain.head->bnd_port == ((struct sockaddr_in*)&src_addr)->sin_port); } + return 0; +} - PDEBUG("packet received from the proxy chain's head\n"); + +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, size_t* udp_data_len){ + + PFUNC(); // Go through the whole proxy chain, decapsulate each header and check that the addresses match udp_relay_node * tmp = chain.head; @@ -713,87 +736,182 @@ int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, uns char header_frag; while (tmp->next != NULL) { - same_address = 0; - - - - rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, &header_port, &header_frag ); + 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; - int header_v6 = header_addr.atyp == ATYP_V6; - - if(tmp->next->bnd_port != header_port){ - PDEBUG("UDP header port is not equal to proxy node port, dropping packet\n"); - return -1; + if(header_frag != 0x00){ + printf("WARNING: received UDP packet with frag != 0 while fragmentation is unsupported.\n"); } - if(tmp->next->bnd_addr.is_v6){ - if(header_v6){ - same_address = memcmp(tmp->next->bnd_addr.addr.v6, header_addr.addr.v6, 16); - } - } - else{ - same_address = memcmp(&(tmp->next->bnd_addr.addr.v4), header_v6?(&(header_addr.addr.v6)+11):&(header_addr.addr.v4), 4); + 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(!same_address){ - PDEBUG("UDP header addr is not equal to proxy node addr, dropping packet\n"); + 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 - char frag; - rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, src_port, &frag); + 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_addr.atyp == ATYP_DOM){ // do the reverse mapping + if(header_frag != 0x00){ + printf("WARNING: received UDP packet with frag != 0 while fragmentation is unsupported.\n"); + } + + + // Copy the UDP data to the provided buffer. If the provided buffer is too small, data is truncated + int min = ((in_buffer_len-read)>*udp_data_len)?*udp_data_len:(in_buffer_len-read); + memcpy(udp_data,in_buffer+read, min); + + // Write back the length of written UDP data in the input/output parameter udp_data_len + *udp_data_len = min; + + return 0; +} + +int unsocks_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, size_t* udp_data_len){ + 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, udp_data_len); + 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(header_addr.addr.dom.name,header_addr.addr.dom.len); + 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, header_addr.addr.dom.name, header_addr.addr.dom.len); - host_string[header_addr.addr.dom.len] = 0x00; + 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, header_addr.addr.dom.len); + tmp_ip = rdns_get_ip_for_host(host_string, src_addr.addr.dom.len); if(tmp_ip.as_int == -1){ - PDEBUG("No matching IP found for hostname\n"); + PDEBUG("error getting ip for host\n"); return -1; } - header_addr.atyp = ATYP_V4; - header_addr.addr.v4.as_int = tmp_ip.as_int; + src_addr.atyp = ATYP_V4; + src_addr.addr.v4.as_int = tmp_ip.as_int; } - src_addr->is_v6 = (header_addr.atyp == ATYP_V6); - if(src_addr->is_v6){ - memcpy(src_addr->addr.v6, header_addr.addr.v6, 16); + 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_addr->addr.v4.as_int = header_addr.addr.v4.as_int; + src_ip->addr.v4.as_int = src_addr.addr.v4.as_int; + } + + return 0; +} + +int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_ip, unsigned short* src_port, char* data, unsigned int data_len ){ + //receives data on sockfd, decapsulates the header for each relay in chain and check they match, returns UDP data and source address/port + + PFUNC(); + + char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 + int bytes_received; + struct sockaddr from; + socklen_t addrlen = sizeof(from); + PDEBUG("test\n"); + + bytes_received = true_recvfrom(sockfd, buffer,sizeof(buffer), 0, &from, &addrlen); + if(-1 == bytes_received){ + PDEBUG("true_receive returned -1\n"); + return -1; } + PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received); + //Check that the packet was received from the first relay of the chain + // i.e. does from == chain.head.bnd_addr ? - int min = ((bytes_received-read)>data_len)?data_len:(bytes_received-read); - memcpy(data,buffer+read, min); + if(!is_from_chain_head(chain, from)){ + PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); + int min = (bytes_received <= data_len)?bytes_received:data_len; + //TODO : il faut aussi transmettre les adresses et ports qu ón a recu a l'appli qui a fait le call !!!!! + memcpy(data, buffer, min); + return min; + } + + PDEBUG("packet received from the proxy chain's head\n"); + + int rc; + size_t udp_data_len = data_len; + rc = unsocks_udp_packet(buffer, bytes_received, chain, src_ip, src_port, data, &udp_data_len); + if(rc != SUCCESS){ + PDEBUG("error unSOCKSing the UDP packet\n"); + return -1; + } + PDEBUG("UDP packet successfully unSOCKified\n"); + return udp_data_len; + + // // Decapsulate all the UDP headers and check that the packet came from the right proxy nodes + // int rc; + // socks5_addr src_addr; + // size_t udp_data_len = data_len; + // rc = decapsulate_check_udp_packet(buffer, bytes_received, chain, &src_addr, src_port, data, &udp_data_len); + // 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 min; + // return udp_data_len; } 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) { diff --git a/src/core.h b/src/core.h index 57e5d64..1c1bc14 100644 --- a/src/core.h +++ b/src/core.h @@ -103,7 +103,6 @@ typedef enum { } ATYP; typedef struct{ - ATYP atyp; union { ip_type4 v4; unsigned char v6[16]; @@ -112,6 +111,7 @@ typedef struct{ 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 @@ -170,6 +170,9 @@ 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 ssize_t (*recvmsg_t) (int sockfd, struct msghdr *msg, int flags); + extern connect_t true_connect; extern gethostbyname_t true_gethostbyname; @@ -181,6 +184,8 @@ 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 recvmsg_t true_recvmsg; struct gethostbyname_data { struct hostent hostent_space; @@ -207,6 +212,10 @@ int free_relay_chain_nodes(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 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); +int is_from_chain_head(udp_relay_chain chain, struct sockaddr src_addr); +int unsocks_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, size_t* udp_data_len); #include "debug.h" #endif diff --git a/src/libproxychains.c b/src/libproxychains.c index 2f628e9..1cf39b4 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -67,6 +67,8 @@ sendto_t true_sendto; send_t true_send; recv_t true_recv; recvfrom_t true_recvfrom; +sendmsg_t true_sendmsg; +recvmsg_t true_recvmsg; int tcp_read_time_out; int tcp_connect_time_out; @@ -810,10 +812,13 @@ HOOKFUNC(int, getaddrinfo, const char *node, const char *service, const struct a INIT(); PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null"); - if(proxychains_resolver != DNSLF_LIBC) + if(proxychains_resolver != DNSLF_LIBC){ + PDEBUG("using proxy_getaddrinfo()\n"); return proxy_getaddrinfo(node, service, hints, res); - else + } + else{ return true_getaddrinfo(node, service, hints, res); + } } HOOKFUNC(void, freeaddrinfo, struct addrinfo *res) { @@ -1026,6 +1031,185 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return SUCCESS; } +// HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ +// //TODO hugoc +// return 0; +// } + +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 addr; + socklen_t addr_len = sizeof(addr); + if(SUCCESS != getsockname(sockfd, &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); + + 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); + return true_recvmsg(sockfd,msg, flags); + } + PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); + + + char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 + size_t bytes_received; + + struct sockaddr from; + + + + struct iovec iov[1]; + iov[0].iov_base = buffer; + iov[0].iov_len = sizeof(buffer); + + + struct msghdr tmp_msg; + + tmp_msg.msg_name = &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\n"); + return -1; + } + + // 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 + + if(!is_from_chain_head(*relay_chain, *(struct sockaddr *)(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; + } + + return written; + } + + PDEBUG("packet received from the proxy chain's head\n"); + + + int rc; + ip_type src_ip; + unsigned short src_port; + char udp_data[65535]; + size_t udp_data_len = sizeof(udp_data); + + rc = unsocks_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, udp_data, &udp_data_len); + if(rc != SUCCESS){ + PDEBUG("error unSOCKSing the UDP packet\n"); + return -1; + } + PDEBUG("UDP packet successfully unSOCKified\n"); + + + /*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; + + //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen + // TODO faire une fonction cast_iptype_to_sockaddr() + + 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(src_addr_v4); + } + 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(src_addr_v6); + }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(src_addr_v4); + } + } + + + return udp_data_len; +} + + + + HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ INIT(); PFUNC(); @@ -1095,7 +1279,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, // WARNING : Est ce que si le client avait envoyé des packets UDP avec resolution DNS dans le socks, // on doit lui filer comme address source pour les packets recu l'addresse de mapping DNS ? Si oui comment - // la retrouver ? + // la retrouver ? -> done in receive_udp_packet() int min = (bytes_received > len)?len:bytes_received; memcpy(buf, tmp_buffer, min); @@ -1197,6 +1381,8 @@ static void setup_hooks(void) { SETUP_SYM(send); SETUP_SYM(sendto); SETUP_SYM(recvfrom); + SETUP_SYM(recvmsg); + //SETUP_SYM(sendmsg); SETUP_SYM(recv); SETUP_SYM(gethostbyname); SETUP_SYM(getaddrinfo); From f3511f80a627dcc2c82d331e92c26fb32d8c7196 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 13 Dec 2023 02:22:20 +0100 Subject: [PATCH 12/35] dig works --- Makefile | 2 +- src/core.c | 353 +++++++++++++++++++++++++++++++------------ src/libproxychains.c | 206 +++++++++++++++++++++++-- 3 files changed, 451 insertions(+), 110 deletions(-) diff --git a/Makefile b/Makefile index 3320904..23ba476 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ LOBJS = src/version.o \ GENH = src/version.h -CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe +CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DDEBUG NO_AS_NEEDED = -Wl,--no-as-needed LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) $(PTHREAD) INC = diff --git a/src/core.c b/src/core.c index 39d3362..9d566c0 100644 --- a/src/core.c +++ b/src/core.c @@ -674,6 +674,23 @@ size_t write_buf_to_iov(void* buff, size_t buff_len, struct iovec* iov, size_t i return written; } + +size_t write_iov_to_buf(void* buff, size_t buff_len, struct iovec* iov, size_t iov_len){ + + size_t written = 0; + int i = 0; + size_t min = 0; + //size_t iov_total_len = get_iov_total_len(iov, iov_len); + + while( (written < buff_len) && (i < iov_len)){ + min = ((buff_len-written)atyp == 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"); @@ -723,6 +740,7 @@ int is_from_chain_head(udp_relay_chain chain, struct sockaddr src_addr){ } + 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, size_t* udp_data_len){ PFUNC(); @@ -787,7 +805,7 @@ int decapsulate_check_udp_packet(void* in_buffer, size_t in_buffer_len, udp_rela return 0; } -int unsocks_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, size_t* udp_data_len){ +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, size_t* udp_data_len){ PFUNC(); // Decapsulate all the UDP headers and check that the packet came from the right proxy nodes int rc; @@ -863,7 +881,7 @@ int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_ip, unsig int rc; size_t udp_data_len = data_len; - rc = unsocks_udp_packet(buffer, bytes_received, chain, src_ip, src_port, data, &udp_data_len); + rc = unsocksify_udp_packet(buffer, bytes_received, chain, src_ip, src_port, data, &udp_data_len); if(rc != SUCCESS){ PDEBUG("error unSOCKSing the UDP packet\n"); return -1; @@ -914,8 +932,45 @@ int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_ip, unsig // return udp_data_len; } -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 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; @@ -924,118 +979,67 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign char *dns_name = NULL; char hostnamebuf[MSG_LEN_MAX]; size_t dns_len = 0; - socks5_addr target_addr; + 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(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) { - target_addr.atyp = ATYP_DOM; - dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name); + 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) goto err; - else dns_name = target_addr.addr.dom.name; - target_addr.addr.dom.len = dns_len & 0xFF; - PDEBUG("dnslen in struct: %d\n", target_addr.addr.dom.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(target_ip.is_v6){ - target_addr.atyp = ATYP_V6; - memcpy(target_addr.addr.v6, target_ip.addr.v6, 16); + if(dst_ip.is_v6){ + dst_addr.atyp = ATYP_V6; + memcpy(dst_addr.addr.v6, dst_ip.addr.v6, 16); } else { - target_addr.atyp = ATYP_V4; - memcpy(target_addr.addr.v4.octet, target_ip.addr.v4.octet, 4); + 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 : ""); - - // Allocate a new buffer for the packet data and all the headers - unsigned int headers_size = 0; - udp_relay_node * tmp = chain.head; - int len = 0; - while(tmp->next != NULL){ - - // switch ((tmp->next)->bnd_addr.atyp) - // { - // case ATYP_V4: - // len = 4; - // break; - // case ATYP_V6: - // len = 6; - // break; - // case ATYP_DOM: - // len = (tmp->next)->bnd_addr.addr.dom.len + 1; - // break; - // default: - // break; - // } - - len = (tmp->next)->bnd_addr.is_v6?16:4; - - headers_size += len + 6; - tmp = tmp->next; - } - - switch (target_addr.atyp) - { - case ATYP_V4: - len = 4; - break; - case ATYP_V6: - len = 6; - break; - case ATYP_DOM: - len = target_addr.addr.dom.len + 1; - break; - default: - break; - } - - headers_size += len + 6; - - char * buff = NULL; - if (NULL == (buff = (char*)malloc(headers_size+data_len))){ - PDEBUG("error malloc buffer\n"); + // 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 each header to the buffer - unsigned int written = 0; - unsigned int offset = 0; + // Append UDP data in the remaining space of the buffer + int 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); - tmp = chain.head; - while (tmp->next != NULL) - { + *buffer_len = tmp_buffer_len + min; - 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); + return 0; - written = write_udp_header(tmpaddr, (tmp->next)->bnd_port, 0, buff+offset, headers_size + data_len - offset); - if (written == -1){ - PDEBUG("error write_udp_header\n"); - goto err; - } - offset += written; +} - tmp = tmp->next; - } +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) { + + PFUNC(); + char send_buffer[65535]; + size_t send_buffer_len = sizeof(send_buffer); + int rc; - written = write_udp_header(target_addr, target_port, 0, buff + offset, headers_size + data_len - offset); - if (written == -1){ - PDEBUG("error write_udp_header\n"); - goto err; + rc = socksify_udp_packet(data, data_len, chain, target_ip, target_port,send_buffer, &send_buffer_len); + if(rc != SUCCESS){ + PDEBUG("error socksify_udp_packet()\n"); + return -1; } - offset += written; - - // Append data to the buffer - memcpy(buff + offset, data, data_len); // Send the packet // FIXME: should write_n_bytes be used here instead ? @@ -1059,20 +1063,175 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign int sent = 0; - sent = true_sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); - if (sent != offset+data_len){ + sent = true_sendto(sockfd, send_buffer, send_buffer_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + if (sent != send_buffer_len){ PDEBUG("true_sendto error\n"); - goto err; + return -1; } return SUCCESS; - err: - free(buff); - return -1; +} + +// 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) { +// 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 target_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(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) { +// target_addr.atyp = ATYP_DOM; +// dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name); +// PDEBUG("dnslen: %d\n", dns_len); +// if(!dns_len) goto err; +// else dns_name = target_addr.addr.dom.name; +// target_addr.addr.dom.len = dns_len & 0xFF; +// PDEBUG("dnslen in struct: %d\n", target_addr.addr.dom.len); + +// } else { +// if(target_ip.is_v6){ +// target_addr.atyp = ATYP_V6; +// memcpy(target_addr.addr.v6, target_ip.addr.v6, 16); + +// } else { +// target_addr.atyp = ATYP_V4; +// memcpy(target_addr.addr.v4.octet, target_ip.addr.v4.octet, 4); +// } +// } + +// PDEBUG("host dns %s\n", dns_name ? dns_name : ""); + + + +// // Allocate a new buffer for the packet data and all the headers +// unsigned int headers_size = 0; +// udp_relay_node * tmp = chain.head; +// int len = 0; +// while(tmp->next != NULL){ + +// // switch ((tmp->next)->bnd_addr.atyp) +// // { +// // case ATYP_V4: +// // len = 4; +// // break; +// // case ATYP_V6: +// // len = 6; +// // break; +// // case ATYP_DOM: +// // len = (tmp->next)->bnd_addr.addr.dom.len + 1; +// // break; +// // default: +// // break; +// // } + +// len = (tmp->next)->bnd_addr.is_v6?16:4; + +// headers_size += len + 6; +// tmp = tmp->next; +// } + +// switch (target_addr.atyp) +// { +// case ATYP_V4: +// len = 4; +// break; +// case ATYP_V6: +// len = 6; +// break; +// case ATYP_DOM: +// len = target_addr.addr.dom.len + 1; +// break; +// default: +// break; +// } + +// headers_size += len + 6; + +// char * buff = NULL; +// if (NULL == (buff = (char*)malloc(headers_size+data_len))){ +// PDEBUG("error malloc buffer\n"); +// return -1; +// } + + +// // Append each header to the buffer + +// unsigned int written = 0; +// unsigned int offset = 0; + +// tmp = chain.head; +// while (tmp->next != NULL) +// { + +// 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, buff+offset, headers_size + data_len - offset); +// if (written == -1){ +// PDEBUG("error write_udp_header\n"); +// goto err; +// } +// offset += written; + +// tmp = tmp->next; +// } + +// written = write_udp_header(target_addr, target_port, 0, buff + offset, headers_size + data_len - offset); +// if (written == -1){ +// PDEBUG("error write_udp_header\n"); +// goto err; +// } +// offset += written; + +// // Append data to the buffer +// memcpy(buff + offset, data, data_len); + +// // Send the packet +// // FIXME: should write_n_bytes be used here instead ? + +// // if(chain.head->bnd_addr.atyp == ATYP_DOM){ +// // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); +// // goto err; +// // } +// int v6 = chain.head->bnd_addr.is_v6 == ATYP_V6; + +// struct sockaddr_in addr = { +// .sin_family = AF_INET, +// .sin_port = chain.head->bnd_port, +// .sin_addr.s_addr = (in_addr_t) chain.head->bnd_addr.addr.v4.as_int, +// }; +// struct sockaddr_in6 addr6 = { +// .sin6_family = AF_INET6, +// .sin6_port = chain.head->bnd_port, +// }; +// if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); + +// int sent = 0; + +// sent = true_sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); +// if (sent != offset+data_len){ +// PDEBUG("true_sendto error\n"); +// goto err; +// } + +// return SUCCESS; + +// err: +// free(buff); +// return -1; + + +// } #define TP " ... " diff --git a/src/libproxychains.c b/src/libproxychains.c index 1cf39b4..812dc1e 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1021,6 +1021,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, DUMP_RELAY_CHAINS_LIST(relay_chains); memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); + //TODO: is it better to do 'return send_udp_packet' ? if (SUCCESS != send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len)){ PDEBUG("could not send udp packet\n"); errno = ECONNREFUSED; @@ -1031,10 +1032,188 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return SUCCESS; } -// HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ -// //TODO hugoc -// return 0; -// } +HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ + INIT(); + PFUNC(); + + //TODO : do we keep this FASTOPEN code from sendto() ? + // if (flags & MSG_FASTOPEN) { + // if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) { + // return -1; + // } + // dest_addr = NULL; + // addrlen = 0; + // flags &= ~MSG_FASTOPEN; + + // return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); + // } + + //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 + struct sockaddr* dest_addr; + dest_addr = msg->msg_name; + socklen_t addrlen = msg->msg_namelen; + + 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(msg->msg_name, msg->msg_namelen); + + 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 + 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; + 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 = sizeof(send_buffer); + + //Move iovec udp data contained in msg to one buffer + char udp_data[65535]; + size_t udp_data_len = sizeof(udp_data); + 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"); + 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) ; + + + //send it + + 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"); + return sent; +} HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ @@ -1100,7 +1279,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ PDEBUG("exec true_recvmsg\n"); bytes_received = true_recvmsg(sockfd, &tmp_msg, flags); if(-1 == bytes_received){ - PDEBUG("true_recvmsg returned -1\n"); + PDEBUG("true_recvmsg returned -1, errno: %d, %s\n", errno,strerror(errno)); return -1; } @@ -1112,8 +1291,9 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ PDEBUG("successful recvmsg(), %d bytes received\n", bytes_received); //Check that the packet was received from the first relay of the chain - - if(!is_from_chain_head(*relay_chain, *(struct sockaddr *)(msg->msg_name))){ + 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); @@ -1137,7 +1317,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ char udp_data[65535]; size_t udp_data_len = sizeof(udp_data); - rc = unsocks_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, udp_data, &udp_data_len); + rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, udp_data, &udp_data_len); if(rc != SUCCESS){ PDEBUG("error unSOCKSing the UDP packet\n"); return -1; @@ -1178,7 +1358,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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(src_addr_v4); + msg->msg_namelen = sizeof(struct sockaddr_in); } else if(src_ip.is_v6){ PDEBUG("src_ip is true v6\n"); @@ -1190,7 +1370,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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(src_addr_v6); + msg->msg_namelen = sizeof(struct sockaddr_in6); }else { if(msg->msg_namelen < sizeof(struct sockaddr_in)){ PDEBUG("addrlen too short for ipv4\n"); @@ -1199,9 +1379,11 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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(src_addr_v4); + msg->msg_namelen = sizeof(struct sockaddr_in); } } + PDEBUG("after recv dump : "); + DUMP_BUFFER(msg->msg_name, msg->msg_namelen); return udp_data_len; @@ -1382,7 +1564,7 @@ static void setup_hooks(void) { SETUP_SYM(sendto); SETUP_SYM(recvfrom); SETUP_SYM(recvmsg); - //SETUP_SYM(sendmsg); + SETUP_SYM(sendmsg); SETUP_SYM(recv); SETUP_SYM(gethostbyname); SETUP_SYM(getaddrinfo); From 0197c9243cfc02d77bc7954f2562847b4938620c Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 13 Dec 2023 02:22:55 +0100 Subject: [PATCH 13/35] digworks --- src/core.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core.h b/src/core.h index 1c1bc14..33fef00 100644 --- a/src/core.h +++ b/src/core.h @@ -214,8 +214,12 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign 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 unsocks_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, size_t* udp_data_len); +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, size_t* udp_data_len); +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); + #include "debug.h" #endif From d2dc4d6ed800866747e18626f47b8adb99fcec1e Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 19 Dec 2023 20:54:58 +0100 Subject: [PATCH 14/35] fix msgname NULL when connected socket --- src/libproxychains.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index 812dc1e..ff0f9bd 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1049,22 +1049,38 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ // } //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 - struct sockaddr* dest_addr; - dest_addr = msg->msg_name; - socklen_t addrlen = msg->msg_namelen; + + //TODO: check what to do when a UDP socket has been "connected" before and then sendmsg is called with msg->msg_name = NULL ? + + struct sockaddr dest_addr; + socklen_t addrlen = sizeof(struct sockaddr); + + if(msg->msg_name == NULL){ // try to find a peer addr that could have been set with connect() + int rc = 0; + rc = getpeername(sockfd, &dest_addr, &addrlen); + if(rc != SUCCESS){ + PDEBUG("error in getpeername(): %d\n", errno); + return -1; + } + } else { + dest_addr = *( (struct sockaddr *) (msg->msg_name)); + addrlen = msg->msg_namelen; + } + + DEBUGDECL(char str[256]); int socktype = 0, ret = 0; socklen_t optlen = 0; optlen = sizeof(socktype); - sa_family_t fam = SOCKFAMILY(*dest_addr); + 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(msg->msg_name, msg->msg_namelen); + DUMP_BUFFER(&dest_addr, addrlen); ip_type dest_ip; struct in_addr *p_addr_in; @@ -1075,11 +1091,11 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ unsigned short port; int v6 = dest_ip.is_v6 = fam == AF_INET6; - p_addr_in = &((struct sockaddr_in *) dest_addr)->sin_addr; + 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); + 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); From 95036aac7ba11e07502092e6814d89b3e4e51791 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 3 Jan 2024 15:31:08 +0100 Subject: [PATCH 15/35] sendmmsg and fixes --- src/core.c | 9 +- src/core.h | 4 +- src/libproxychains.c | 296 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 298 insertions(+), 11 deletions(-) diff --git a/src/core.c b/src/core.c index 9d566c0..4735597 100644 --- a/src/core.c +++ b/src/core.c @@ -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; @@ -1028,7 +1028,7 @@ int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain cha } -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 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) { PFUNC(); char send_buffer[65535]; @@ -1063,13 +1063,14 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign int sent = 0; - sent = true_sendto(sockfd, send_buffer, send_buffer_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); + sent = true_sendto(sockfd, send_buffer, send_buffer_len, flags, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); if (sent != send_buffer_len){ PDEBUG("true_sendto error\n"); return -1; } - return SUCCESS; + + return data_len; } diff --git a/src/core.h b/src/core.h index 33fef00..94e2035 100644 --- a/src/core.h +++ b/src/core.h @@ -171,6 +171,7 @@ 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); @@ -185,6 +186,7 @@ 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; struct gethostbyname_data { @@ -210,7 +212,7 @@ 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_nodes(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 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); diff --git a/src/libproxychains.c b/src/libproxychains.c index ff0f9bd..8afaad1 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -69,6 +69,7 @@ recv_t true_recv; recvfrom_t true_recvfrom; sendmsg_t true_sendmsg; recvmsg_t true_recvmsg; +sendmmsg_t true_sendmmsg; int tcp_read_time_out; int tcp_connect_time_out; @@ -589,6 +590,8 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ #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; @@ -597,11 +600,12 @@ HOOKFUNC(int, close, int fd) { } /***** UDP STUFF *******/ - + PDEBUG("checking if a relay chain is opened for fd %d\n", fd); udp_relay_chain* chain = NULL; chain = get_relay_chain(relay_chains, fd); if(NULL != chain){ + PDEBUG("fd %d corresponds to chain %x, closing it\n", fd, chain); free_relay_chain_nodes(*chain); del_relay_chain(&relay_chains, chain); } @@ -620,6 +624,7 @@ HOOKFUNC(int, close, int fd) { errno = EBADF; return -1; } + 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); } @@ -1022,14 +1027,16 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); //TODO: is it better to do 'return send_udp_packet' ? - if (SUCCESS != send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len)){ + int sent = 0; + sent = send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len, flags); + if (-1 == sent ){ PDEBUG("could not send udp packet\n"); errno = ECONNREFUSED; return -1; } - PDEBUG("Successfully sent UDP packet, leaving hook\n"); - return SUCCESS; + PDEBUG("Successfully sent UDP packet, leaving hook\n\n"); + return sent; } HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ @@ -1171,11 +1178,11 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ // Allocate buffer for header creation char send_buffer[65535]; //TODO maybe we can do better about size ? - size_t send_buffer_len = sizeof(send_buffer); + 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 = sizeof(udp_data); + 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 @@ -1231,6 +1238,282 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ return sent; } +HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, int flags){ + + + 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 dest_addr; + socklen_t addrlen = sizeof(struct sockaddr); + + 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, &dest_addr, &addrlen); + if(rc != SUCCESS){ + PDEBUG("error in getpeername(): %d\n", errno); + goto freeAndExit; + } + } else { + dest_addr = *( (struct sockaddr *) (msgvec[0].msg_hdr.msg_name)); + addrlen = msgvec[0].msg_hdr.msg_namelen; + } + + + + 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)){ + nmsg = true_sendmmsg(sockfd, msgvec, vlen, flags); + goto freeAndExit; + } + + // Check if a chain of UDP relay is already opened for this socket + 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; + 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"); + goto freeAndExit; + } + + + + for(int i=0; isin_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", i, 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", i, 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[i].msg_hdr.msg_iov ,msgvec[i].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[i].msg_hdr.msg_control = msgvec[i].msg_hdr.msg_control; + tmp_msgvec[i].msg_hdr.msg_controllen = msgvec[i].msg_hdr.msg_controllen; + tmp_msgvec[i].msg_hdr.msg_flags = msgvec[i].msg_hdr.msg_flags; + + tmp_msgvec[i].msg_hdr.msg_iov = iov; + tmp_msgvec[i].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[i].msg_hdr.msg_name = (struct sockaddr*)pAddr; + tmp_msgvec[i].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[i].msg_hdr.msg_name = (struct sockaddr*)pAddr6; + tmp_msgvec[i].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); + } + + goto freeAndExit; + } + + + 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){ @@ -1581,6 +1864,7 @@ static void setup_hooks(void) { SETUP_SYM(recvfrom); SETUP_SYM(recvmsg); SETUP_SYM(sendmsg); + SETUP_SYM(sendmmsg); SETUP_SYM(recv); SETUP_SYM(gethostbyname); SETUP_SYM(getaddrinfo); From 23c9654cf84c783a28d2faf406e3f492572c2b9d Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 16 Jan 2024 16:00:30 +0100 Subject: [PATCH 16/35] hook connect and getpeername --- src/core.c | 52 +++++++++++++++++++- src/core.h | 9 +++- src/libproxychains.c | 113 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 168 insertions(+), 6 deletions(-) diff --git a/src/core.c b/src/core.c index 4735597..de27ab0 100644 --- a/src/core.c +++ b/src/core.c @@ -1655,7 +1655,12 @@ int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ return -1; } -int free_relay_chain_nodes(udp_relay_chain chain){ +int free_relay_chain(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; } @@ -1687,6 +1692,8 @@ udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, cha 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; @@ -1730,12 +1737,53 @@ udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, cha error: PDEBUG("error\n"); release_all(pd, proxy_count); - free_relay_chain_nodes(*new_chain); + free_relay_chain(*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){ diff --git a/src/core.h b/src/core.h index 94e2035..e5705c7 100644 --- a/src/core.h +++ b/src/core.h @@ -131,7 +131,9 @@ typedef struct s_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 + 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; @@ -173,6 +175,7 @@ typedef ssize_t (*recvfrom_t) (int sockfd, void *buf, size_t len, int flags, 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); extern connect_t true_connect; @@ -188,6 +191,7 @@ 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; struct gethostbyname_data { struct hostent hostent_space; @@ -210,7 +214,7 @@ static int udp_associate(int sock, ip_type * dst_addr, unsigned short dst_port, 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_nodes(udp_relay_chain chain); +int free_relay_chain(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 ); @@ -221,6 +225,7 @@ 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, size_t* udp_data_len); 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" diff --git a/src/libproxychains.c b/src/libproxychains.c index 8afaad1..9eed55e 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -70,6 +70,7 @@ recvfrom_t true_recvfrom; sendmsg_t true_sendmsg; recvmsg_t true_recvmsg; sendmmsg_t true_sendmmsg; +getpeername_t true_getpeername; int tcp_read_time_out; int tcp_connect_time_out; @@ -600,13 +601,13 @@ HOOKFUNC(int, close, int fd) { } /***** UDP STUFF *******/ - PDEBUG("checking if a relay chain is opened for fd %d\n", fd); + //PDEBUG("checking if a relay chain is opened for fd %d\n", fd); udp_relay_chain* chain = NULL; chain = get_relay_chain(relay_chains, fd); if(NULL != chain){ PDEBUG("fd %d corresponds to chain %x, closing it\n", fd, chain); - free_relay_chain_nodes(*chain); + free_relay_chain(*chain); del_relay_chain(&relay_chains, chain); } @@ -692,6 +693,68 @@ 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 sock_addr; + socklen_t sock_addr_len = sizeof(sock_addr); + if(SUCCESS != getsockname(sockfd, &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 + 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); + 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); + 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; + + return SUCCESS; + + /* END UDP STUFF */ + +} + HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) { INIT(); PFUNC(); @@ -710,6 +773,51 @@ 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 + 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; + 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); + + 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); @@ -1859,6 +1967,7 @@ HOOKFUNC(ssize_t, send, 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); From 120cfe96be9cea0af13bf249fc30096e0659295e Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 17 Jan 2024 10:34:41 +0100 Subject: [PATCH 17/35] comments --- src/core.c | 45 ++------------------------------------------ src/libproxychains.c | 19 +++++++++---------- 2 files changed, 11 insertions(+), 53 deletions(-) diff --git a/src/core.c b/src/core.c index de27ab0..db57cf7 100644 --- a/src/core.c +++ b/src/core.c @@ -427,7 +427,6 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c /* 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){ - //TODO hugoc PFUNC(); @@ -889,47 +888,6 @@ int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_ip, unsig PDEBUG("UDP packet successfully unSOCKified\n"); return udp_data_len; - - // // Decapsulate all the UDP headers and check that the packet came from the right proxy nodes - // int rc; - // socks5_addr src_addr; - // size_t udp_data_len = data_len; - // rc = decapsulate_check_udp_packet(buffer, bytes_received, chain, &src_addr, src_port, data, &udp_data_len); - // 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 udp_data_len; } int encapsulate_udp_packet(udp_relay_chain chain, socks5_addr dst_addr, unsigned short dst_port, void* buffer, size_t* buffer_len){ @@ -1042,7 +1000,8 @@ int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsign } // Send the packet - // FIXME: should write_n_bytes be used here instead ? + // FIXME: should write_n_bytes be used here instead ? -> No, because we send data on an unconnected socket, so we need to use sendto with an address and not send. + // We thus cannot use write(), which cannot be given an address // if(chain.head->bnd_addr.atyp == ATYP_DOM){ // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); diff --git a/src/libproxychains.c b/src/libproxychains.c index 9eed55e..651bc19 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1039,8 +1039,9 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); } - //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 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); @@ -1050,6 +1051,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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; @@ -1079,7 +1081,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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); + 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++) @@ -1802,7 +1804,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ HOOKFUNC(ssize_t, recv, int sockfd, void *buf, size_t len, int flags){ INIT(); PFUNC(); - //TODO hugoc + return recvfrom(sockfd, buf, len, flags, NULL, NULL); } @@ -1924,11 +1926,8 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ INIT(); PFUNC(); - //TODO hugoc - - //Checker si c'est une SOCK_DGRAM + AFINET ou AFINET6 - // Récupérer l'adresse liée avec getpeername - // Exécuter le hook sendto + + // Check if sockfd is a SOCK_DGRAM socket int socktype = 0; socklen_t optlen = 0; optlen = sizeof(socktype); @@ -1938,14 +1937,13 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ 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 addr; socklen_t addr_len = sizeof(addr); - if(SUCCESS != getpeername(sockfd, &addr, &addr_len )){ PDEBUG("error getpeername, errno=%d. Returning to true_send()\n", errno); return true_send(sockfd, buf, len, flags); } - //DEBUGDECL(char str[256]); sa_family_t fam = SOCKFAMILY(addr); if(!(fam == AF_INET || fam == AF_INET6)){ @@ -1953,6 +1951,7 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ 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, &addr, addr_len); } From 44c4352d72397dc4bd3229d95f540c9311854c28 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 17 Jan 2024 12:48:20 +0100 Subject: [PATCH 18/35] removed receive_udp_packet() --- src/core.c | 42 ---------------------- src/libproxychains.c | 86 +++++++++++++++++++++++++++++++------------- 2 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/core.c b/src/core.c index db57cf7..01a7f2a 100644 --- a/src/core.c +++ b/src/core.c @@ -847,48 +847,6 @@ int unsocksify_udp_packet(void* in_buffer, size_t in_buffer_len, udp_relay_chain return 0; } -int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_ip, unsigned short* src_port, char* data, unsigned int data_len ){ - //receives data on sockfd, decapsulates the header for each relay in chain and check they match, returns UDP data and source address/port - - PFUNC(); - - char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 - int bytes_received; - struct sockaddr from; - socklen_t addrlen = sizeof(from); - PDEBUG("test\n"); - - bytes_received = true_recvfrom(sockfd, buffer,sizeof(buffer), 0, &from, &addrlen); - if(-1 == bytes_received){ - PDEBUG("true_receive returned -1\n"); - return -1; - } - - PDEBUG("successful recvfrom(), %d bytes received\n", 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(chain, from)){ - PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n"); - int min = (bytes_received <= data_len)?bytes_received:data_len; - //TODO : il faut aussi transmettre les adresses et ports qu ón a recu a l'appli qui a fait le call !!!!! - memcpy(data, buffer, min); - return min; - } - - PDEBUG("packet received from the proxy chain's head\n"); - - int rc; - size_t udp_data_len = data_len; - rc = unsocksify_udp_packet(buffer, bytes_received, chain, src_ip, src_port, data, &udp_data_len); - if(rc != SUCCESS){ - PDEBUG("error unSOCKSing the UDP packet\n"); - return -1; - } - PDEBUG("UDP packet successfully unSOCKified\n"); - - return udp_data_len; -} int encapsulate_udp_packet(udp_relay_chain chain, socks5_addr dst_addr, unsigned short dst_port, void* buffer, size_t* buffer_len){ diff --git a/src/libproxychains.c b/src/libproxychains.c index 651bc19..1deeb40 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1145,7 +1145,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return -1; } - PDEBUG("Successfully sent UDP packet, leaving hook\n\n"); + PDEBUG("Successful sendto() hook\n\n"); return sent; } @@ -1345,6 +1345,8 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ return -1; } PDEBUG("Successfully sent UDP packet with true_sendmsg()\n"); + + PDEBUG("Successful sendmsg() hook\n\n"); return sent; } @@ -1608,6 +1610,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i } PDEBUG("Successfully sent %d UDP packets with true_sendmmsg()\n", nmsg); + PDEBUG("Successful sendmmsg() hook\n\n"); freeAndExit: @@ -1795,6 +1798,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ DUMP_BUFFER(msg->msg_name, msg->msg_namelen); + PDEBUG("Successful recvmsg() hook\n\n"); return udp_data_len; } @@ -1851,32 +1855,66 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, char tmp_buffer[65535]; //maximum theoretical size of a UDP packet. int bytes_received; - ip_type from_addr; - unsigned short from_port; - bytes_received = receive_udp_packet(sockfd, *relay_chain, &from_addr, &from_port, tmp_buffer, 65535); - + ip_type src_ip; + unsigned short src_port; + + + struct sockaddr from; + socklen_t from_len = sizeof(from); + bytes_received = true_recvfrom(sockfd, tmp_buffer, sizeof(tmp_buffer), 0, &from, &from_len); if(-1 == bytes_received){ PDEBUG("true_recvfrom returned -1\n"); return -1; } + PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received); + PDEBUG("packet: "); + DUMP_BUFFER(tmp_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, 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, tmp_buffer, min); + if(src_addr != NULL){ //TODO: check that the address copy is done correctly + socklen_t min_addr_len = (from_len<*addrlen)?from_len:*addrlen; + memcpy(src_addr, &from, min_addr_len); + *addrlen = min_addr_len; + } + + return min; + } + PDEBUG("packet received from the proxy chain's head\n"); + + int rc; + size_t udp_data_len = len; + rc = unsocksify_udp_packet(tmp_buffer, bytes_received, *relay_chain, &src_ip, &src_port, buf, &udp_data_len); + if(rc != SUCCESS){ + PDEBUG("error unsocksifying the UDP packet\n"); + return -1; + } + PDEBUG("UDP packet successfully unsocksifyied\n"); + + - PDEBUG("received %d bytes through receive_udp_packet()\n", bytes_received); + PDEBUG("received %d bytes through receive_udp_packet()\n", udp_data_len); PDEBUG("data: "); - DUMP_BUFFER(tmp_buffer, bytes_received); + DUMP_BUFFER(buf, udp_data_len); PDEBUG("from_addr: "); - DUMP_BUFFER(from_addr.addr.v6, from_addr.is_v6?16:4); - PDEBUG("from_addr: %s\n", inet_ntop(from_addr.is_v6 ? AF_INET6 : AF_INET, from_addr.is_v6 ? (void*)from_addr.addr.v6 : (void*)from_addr.addr.v4.octet, str, sizeof(str))); - PDEBUG("from_port: %hu\n", ntohs(from_port)); + 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)); // WARNING : Est ce que si le client avait envoyé des packets UDP avec resolution DNS dans le socks, // on doit lui filer comme address source pour les packets recu l'addresse de mapping DNS ? Si oui comment - // la retrouver ? -> done in receive_udp_packet() + // la retrouver ? -> done in unsocksify_udp_packet() - int min = (bytes_received > len)?len:bytes_received; - memcpy(buf, tmp_buffer, min); if (src_addr == NULL){ // No need to fill src_addr in this case - return min; + return udp_data_len; } struct sockaddr_in* src_addr_v4; @@ -1885,18 +1923,18 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen // - if(from_addr.is_v6 && is_v4inv6((struct in6_addr*)from_addr.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 = from_port; - memcpy(&(src_addr_v4->sin_addr.s_addr), from_addr.addr.v6+12, 4); + 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(from_addr.is_v6){ + 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"); @@ -1904,8 +1942,8 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, } src_addr_v6 = (struct sockaddr_in6*)src_addr; src_addr_v6->sin6_family = AF_INET6; - src_addr_v6->sin6_port = from_port; - memcpy(src_addr_v6->sin6_addr.s6_addr, from_addr.addr.v6, 16); + 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)){ @@ -1913,14 +1951,14 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, } src_addr_v4 = (struct sockaddr_in*)src_addr; src_addr_v4->sin_family = AF_INET; - src_addr_v4->sin_port = from_port; - src_addr_v4->sin_addr.s_addr = (in_addr_t) from_addr.addr.v4.as_int; + 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); } - - return min; + PDEBUG("Successful recvfrom() hook\n\n"); + return udp_data_len; } HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ From 436f402f1eb3a45f6338ede139a3d3449528a21e Mon Sep 17 00:00:00 2001 From: hugoc Date: Thu, 1 Feb 2024 17:24:36 +0100 Subject: [PATCH 19/35] fix sockaddr / sockaddr_storage confusion --- src/core.c | 14 ++++----- src/core.h | 2 +- src/libproxychains.c | 68 ++++++++++++++++++++++++++------------------ 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/core.c b/src/core.c index 01a7f2a..7edd2b4 100644 --- a/src/core.c +++ b/src/core.c @@ -698,13 +698,13 @@ void cast_socks5addr_v4inv6_to_v4(socks5_addr* addr){ } } -int compare_iptype_sockaddr(ip_type addr1, struct sockaddr addr2){ - if(addr1.is_v6 && (((struct sockaddr_in6 *) &(addr2))->sin6_family == AF_INET6)){ +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)){ + 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); + return ((uint32_t)(((struct sockaddr_in *)addr2)->sin_addr.s_addr) == addr1.addr.v4.as_int); } else { // Not the same address type return 0; @@ -730,10 +730,10 @@ int compare_socks5_addr_iptype(socks5_addr addr1, ip_type addr2){ } } -int is_from_chain_head(udp_relay_chain chain, struct sockaddr src_addr){ +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 (chain.head->bnd_port == ((struct sockaddr_in*)src_addr)->sin_port); } return 0; } diff --git a/src/core.h b/src/core.h index e5705c7..b2c4bec 100644 --- a/src/core.h +++ b/src/core.h @@ -221,7 +221,7 @@ int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, uns 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 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, size_t* udp_data_len); 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); diff --git a/src/libproxychains.c b/src/libproxychains.c index 1deeb40..7343a20 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -708,9 +708,9 @@ HOOKFUNC(int, getpeername, int sockfd, struct sockaddr *restrict addr, socklen_t } PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); - struct sockaddr sock_addr; + struct sockaddr_storage sock_addr; socklen_t sock_addr_len = sizeof(sock_addr); - if(SUCCESS != getsockname(sockfd, &sock_addr, &sock_addr_len )){ + 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); } @@ -1169,19 +1169,23 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ //TODO: check what to do when a UDP socket has been "connected" before and then sendmsg is called with msg->msg_name = NULL ? - struct sockaddr dest_addr; - socklen_t addrlen = sizeof(struct sockaddr); + 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, &dest_addr, &addrlen); + rc = getpeername(sockfd, (struct sockaddr*)&dest_addr, &addrlen); if(rc != SUCCESS){ PDEBUG("error in getpeername(): %d\n", errno); return -1; } } else { - dest_addr = *( (struct sockaddr *) (msg->msg_name)); + 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); } @@ -1358,19 +1362,23 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i // As the call contains multiple message, we only filter on the first one address type :) - struct sockaddr dest_addr; - socklen_t addrlen = sizeof(struct sockaddr); + struct sockaddr_storage dest_addr; + socklen_t addrlen = sizeof(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, &dest_addr, &addrlen); + rc = getpeername(sockfd, (struct sockaddr*)&dest_addr, &addrlen); if(rc != SUCCESS){ PDEBUG("error in getpeername(): %d\n", errno); goto freeAndExit; } } else { - dest_addr = *( (struct sockaddr *) (msgvec[0].msg_hdr.msg_name)); + if(msgvec[0].msg_hdr.msg_namelen > addrlen){ + PDEBUG("msgvec[0].msg_hdr.msg_namelen too long\n"); + return -1; + } addrlen = msgvec[0].msg_hdr.msg_namelen; + memcpy(&dest_addr, msgvec[0].msg_hdr.msg_name, addrlen); } @@ -1421,19 +1429,23 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i - struct sockaddr dest_addr; - socklen_t addrlen = sizeof(struct sockaddr); + struct sockaddr_storage dest_addr; + socklen_t addrlen = sizeof(dest_addr); if(msgvec[i].msg_hdr.msg_name == NULL){ // try to find a peer addr that could have been set with connect() int rc = 0; - rc = getpeername(sockfd, &dest_addr, &addrlen); + rc = getpeername(sockfd, (struct sockaddr*)&dest_addr, &addrlen); if(rc != SUCCESS){ PDEBUG("error in getpeername(): %d\n", errno); goto cleanCurrentLoop; } } else { - dest_addr = *( (struct sockaddr *) (msgvec[i].msg_hdr.msg_name)); + if(msgvec[i].msg_hdr.msg_namelen > addrlen){ + PDEBUG("msgvec[%d].msg_hdr.msg_namelen too long\n", i); + return -1; + } addrlen = msgvec[i].msg_hdr.msg_namelen; + memcpy(&dest_addr, msgvec[i].msg_hdr.msg_name, addrlen); } ip_type dest_ip; @@ -1643,9 +1655,9 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ } PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); - struct sockaddr addr; + struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); - if(SUCCESS != getsockname(sockfd, &addr, &addr_len )){ + 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); } @@ -1669,7 +1681,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 size_t bytes_received; - struct sockaddr from; + struct sockaddr_storage from; @@ -1680,7 +1692,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ struct msghdr tmp_msg; - tmp_msg.msg_name = &from; + tmp_msg.msg_name = (void *)&from; tmp_msg.msg_namelen = sizeof(from); tmp_msg.msg_iov = iov; tmp_msg.msg_iovlen = 1; @@ -1705,7 +1717,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ //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))){ + 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); @@ -1828,9 +1840,9 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, } PDEBUG("sockfd %d is a SOCK_DGRAM socket\n", sockfd); - struct sockaddr addr; + struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); - if(SUCCESS != getsockname(sockfd, &addr, &addr_len )){ + 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); } @@ -1859,9 +1871,9 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, unsigned short src_port; - struct sockaddr from; + struct sockaddr_storage from; socklen_t from_len = sizeof(from); - bytes_received = true_recvfrom(sockfd, tmp_buffer, sizeof(tmp_buffer), 0, &from, &from_len); + bytes_received = true_recvfrom(sockfd, tmp_buffer, sizeof(tmp_buffer), 0, (struct sockaddr*)&from, &from_len); if(-1 == bytes_received){ PDEBUG("true_recvfrom returned -1\n"); return -1; @@ -1873,7 +1885,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, //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, from)){ + 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; @@ -1966,6 +1978,7 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ PFUNC(); // Check if sockfd is a SOCK_DGRAM socket + int socktype = 0; socklen_t optlen = 0; optlen = sizeof(socktype); @@ -1976,9 +1989,10 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ } // Retreive the peer address the socket is connected to, and check it is of AF_INET or AF_INET6 family - struct sockaddr addr; + + struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); - if(SUCCESS != getpeername(sockfd, &addr, &addr_len )){ + 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); } @@ -1990,7 +2004,7 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ } // Call the sendto() hook with the send() parameters and the retrieved peer address - return sendto(sockfd, buf, len, flags, &addr, addr_len); + return sendto(sockfd, buf, len, flags, (struct sockaddr*)&addr, addr_len); } #ifdef MONTEREY_HOOKING From 5660aea02ee1bd73dc1b509caf07ef3c08ad0a9b Mon Sep 17 00:00:00 2001 From: hugoc Date: Thu, 1 Feb 2024 17:53:11 +0100 Subject: [PATCH 20/35] remove send_udp_packet() --- src/core.c | 207 ------------------------------------------- src/libproxychains.c | 46 ++++++++-- 2 files changed, 39 insertions(+), 214 deletions(-) diff --git a/src/core.c b/src/core.c index 7edd2b4..6993ccf 100644 --- a/src/core.c +++ b/src/core.c @@ -944,213 +944,6 @@ int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain cha } -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) { - - PFUNC(); - char send_buffer[65535]; - size_t send_buffer_len = sizeof(send_buffer); - int rc; - - rc = socksify_udp_packet(data, data_len, chain, target_ip, target_port,send_buffer, &send_buffer_len); - if(rc != SUCCESS){ - PDEBUG("error socksify_udp_packet()\n"); - return -1; - } - - // Send the packet - // FIXME: should write_n_bytes be used here instead ? -> No, because we send data on an unconnected socket, so we need to use sendto with an address and not send. - // We thus cannot use write(), which cannot be given an address - - // if(chain.head->bnd_addr.atyp == ATYP_DOM){ - // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); - // goto err; - // } - int v6 = chain.head->bnd_addr.is_v6 == ATYP_V6; - - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = chain.head->bnd_port, - .sin_addr.s_addr = (in_addr_t) chain.head->bnd_addr.addr.v4.as_int, - }; - struct sockaddr_in6 addr6 = { - .sin6_family = AF_INET6, - .sin6_port = chain.head->bnd_port, - }; - if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); - - int 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 != send_buffer_len){ - PDEBUG("true_sendto error\n"); - return -1; - } - - - return data_len; - -} - -// 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) { - -// 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 target_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(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) { -// target_addr.atyp = ATYP_DOM; -// dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name); -// PDEBUG("dnslen: %d\n", dns_len); -// if(!dns_len) goto err; -// else dns_name = target_addr.addr.dom.name; -// target_addr.addr.dom.len = dns_len & 0xFF; -// PDEBUG("dnslen in struct: %d\n", target_addr.addr.dom.len); - -// } else { -// if(target_ip.is_v6){ -// target_addr.atyp = ATYP_V6; -// memcpy(target_addr.addr.v6, target_ip.addr.v6, 16); - -// } else { -// target_addr.atyp = ATYP_V4; -// memcpy(target_addr.addr.v4.octet, target_ip.addr.v4.octet, 4); -// } -// } - -// PDEBUG("host dns %s\n", dns_name ? dns_name : ""); - - - -// // Allocate a new buffer for the packet data and all the headers -// unsigned int headers_size = 0; -// udp_relay_node * tmp = chain.head; -// int len = 0; -// while(tmp->next != NULL){ - -// // switch ((tmp->next)->bnd_addr.atyp) -// // { -// // case ATYP_V4: -// // len = 4; -// // break; -// // case ATYP_V6: -// // len = 6; -// // break; -// // case ATYP_DOM: -// // len = (tmp->next)->bnd_addr.addr.dom.len + 1; -// // break; -// // default: -// // break; -// // } - -// len = (tmp->next)->bnd_addr.is_v6?16:4; - -// headers_size += len + 6; -// tmp = tmp->next; -// } - -// switch (target_addr.atyp) -// { -// case ATYP_V4: -// len = 4; -// break; -// case ATYP_V6: -// len = 6; -// break; -// case ATYP_DOM: -// len = target_addr.addr.dom.len + 1; -// break; -// default: -// break; -// } - -// headers_size += len + 6; - -// char * buff = NULL; -// if (NULL == (buff = (char*)malloc(headers_size+data_len))){ -// PDEBUG("error malloc buffer\n"); -// return -1; -// } - - -// // Append each header to the buffer - -// unsigned int written = 0; -// unsigned int offset = 0; - -// tmp = chain.head; -// while (tmp->next != NULL) -// { - -// 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, buff+offset, headers_size + data_len - offset); -// if (written == -1){ -// PDEBUG("error write_udp_header\n"); -// goto err; -// } -// offset += written; - -// tmp = tmp->next; -// } - -// written = write_udp_header(target_addr, target_port, 0, buff + offset, headers_size + data_len - offset); -// if (written == -1){ -// PDEBUG("error write_udp_header\n"); -// goto err; -// } -// offset += written; - -// // Append data to the buffer -// memcpy(buff + offset, data, data_len); - -// // Send the packet -// // FIXME: should write_n_bytes be used here instead ? - -// // if(chain.head->bnd_addr.atyp == ATYP_DOM){ -// // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); -// // goto err; -// // } -// int v6 = chain.head->bnd_addr.is_v6 == ATYP_V6; - -// struct sockaddr_in addr = { -// .sin_family = AF_INET, -// .sin_port = chain.head->bnd_port, -// .sin_addr.s_addr = (in_addr_t) chain.head->bnd_addr.addr.v4.as_int, -// }; -// struct sockaddr_in6 addr6 = { -// .sin6_family = AF_INET6, -// .sin6_port = chain.head->bnd_port, -// }; -// if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16); - -// int sent = 0; - -// sent = true_sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) ); -// if (sent != offset+data_len){ -// PDEBUG("true_sendto error\n"); -// goto err; -// } - -// return SUCCESS; - -// err: -// free(buff); -// return -1; - - -// } - #define TP " ... " #define DT "Dynamic chain" diff --git a/src/libproxychains.c b/src/libproxychains.c index 7343a20..5463ef4 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1136,15 +1136,47 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, DUMP_RELAY_CHAINS_LIST(relay_chains); memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); - //TODO: is it better to do 'return send_udp_packet' ? - int sent = 0; - sent = send_udp_packet(sockfd, *relay_chain, dest_ip, htons(port),0, buf, len, flags); - if (-1 == sent ){ - PDEBUG("could not send udp packet\n"); - errno = ECONNREFUSED; + + 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"); return -1; } + // Send the packet + // FIXME: should write_n_bytes be used here instead ? -> No, because we send data on an unconnected socket, so we need to use sendto with an address and not send. + // We thus cannot use write(), which cannot be given an address + + // if(chain.head->bnd_addr.atyp == ATYP_DOM){ + // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); + // goto err; + // } + + 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); + + int 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; } @@ -1989,7 +2021,7 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int 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 )){ From 14c35dd7e94c5437e7e9e9eb34c9fab45f2ec587 Mon Sep 17 00:00:00 2001 From: hugoc Date: Thu, 1 Feb 2024 23:16:39 +0100 Subject: [PATCH 21/35] add filtering on send flags --- src/libproxychains.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index 5463ef4..98135ed 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1169,6 +1169,20 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, }; 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; + return -1; + } + int sent = 0; sent = true_sendto(sockfd, send_buffer, send_buffer_len, flags, (struct sockaddr*)(v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr)); @@ -1374,6 +1388,19 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ //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){ @@ -1641,6 +1668,19 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i } + //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){ @@ -1905,7 +1945,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, struct sockaddr_storage from; socklen_t from_len = sizeof(from); - bytes_received = true_recvfrom(sockfd, tmp_buffer, sizeof(tmp_buffer), 0, (struct sockaddr*)&from, &from_len); + bytes_received = true_recvfrom(sockfd, tmp_buffer, sizeof(tmp_buffer), flags, (struct sockaddr*)&from, &from_len); if(-1 == bytes_received){ PDEBUG("true_recvfrom returned -1\n"); return -1; From 81092b1f4b4516d09898be7f705faed9c2195245 Mon Sep 17 00:00:00 2001 From: hugoc Date: Thu, 1 Feb 2024 23:46:21 +0100 Subject: [PATCH 22/35] define RECV_BUFFER_SIZE --- src/libproxychains.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index 98135ed..f1c54bd 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -48,6 +48,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 @@ -1680,7 +1681,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i errno = EOPNOTSUPP; return -1; } - + nmsg = true_sendmmsg(sockfd, tmp_msgvec, vlen, flags); if(nmsg == -1){ @@ -1750,7 +1751,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); - char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535 + char buffer[RECV_BUFFER_SIZE]; //buffer to receive and decapsulate a UDP relay packet size_t bytes_received; struct sockaddr_storage from; @@ -1810,7 +1811,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ int rc; ip_type src_ip; unsigned short src_port; - char udp_data[65535]; + char udp_data[RECV_BUFFER_SIZE]; size_t udp_data_len = sizeof(udp_data); rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, udp_data, &udp_data_len); From a47f9c05767de2e27461e011dc762f47fe1912d9 Mon Sep 17 00:00:00 2001 From: hugoc Date: Fri, 2 Feb 2024 00:08:03 +0100 Subject: [PATCH 23/35] change unsocksify_udp_packet() and decapsulate_udp_packet() signature. Moved udp data copy outside these functions --- src/core.c | 17 +++++++---------- src/core.h | 2 +- src/libproxychains.c | 20 +++++++++++++------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/core.c b/src/core.c index 6993ccf..003e90e 100644 --- a/src/core.c +++ b/src/core.c @@ -740,7 +740,7 @@ int is_from_chain_head(udp_relay_chain chain, struct sockaddr* src_addr){ -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, size_t* udp_data_len){ +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 @@ -793,23 +793,20 @@ int decapsulate_check_udp_packet(void* in_buffer, size_t in_buffer_len, udp_rela printf("WARNING: received UDP packet with frag != 0 while fragmentation is unsupported.\n"); } - - // Copy the UDP data to the provided buffer. If the provided buffer is too small, data is truncated - int min = ((in_buffer_len-read)>*udp_data_len)?*udp_data_len:(in_buffer_len-read); - memcpy(udp_data,in_buffer+read, min); - - // Write back the length of written UDP data in the input/output parameter udp_data_len - *udp_data_len = min; + + // Point udp_data to the position of the UDP data inside in_buffer + *udp_data = in_buffer+read; return 0; } -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, size_t* udp_data_len){ +//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, udp_data_len); + 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; diff --git a/src/core.h b/src/core.h index b2c4bec..88211fc 100644 --- a/src/core.h +++ b/src/core.h @@ -222,7 +222,7 @@ 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, size_t* udp_data_len); +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); diff --git a/src/libproxychains.c b/src/libproxychains.c index f1c54bd..cf2121b 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1811,16 +1811,16 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ int rc; ip_type src_ip; unsigned short src_port; - char udp_data[RECV_BUFFER_SIZE]; - size_t udp_data_len = sizeof(udp_data); + 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, &udp_data_len); + rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); 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]); @@ -1975,23 +1975,29 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, PDEBUG("packet received from the proxy chain's head\n"); int rc; - size_t udp_data_len = len; - rc = unsocksify_udp_packet(tmp_buffer, bytes_received, *relay_chain, &src_ip, &src_port, buf, &udp_data_len); + void* udp_data = NULL; + size_t udp_data_len = 0; + rc = unsocksify_udp_packet(tmp_buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); 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*)tmp_buffer); PDEBUG("received %d bytes through receive_udp_packet()\n", udp_data_len); PDEBUG("data: "); - DUMP_BUFFER(buf, udp_data_len); + 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); // WARNING : Est ce que si le client avait envoyé des packets UDP avec resolution DNS dans le socks, // on doit lui filer comme address source pour les packets recu l'addresse de mapping DNS ? Si oui comment From e379a8af75a2182244f2dd4c5985d6a589daf59f Mon Sep 17 00:00:00 2001 From: hugoc Date: Fri, 2 Feb 2024 16:39:32 +0100 Subject: [PATCH 24/35] implement MSG_TRUNC logic in recvfrom and recvmsg --- src/libproxychains.c | 104 +++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index cf2121b..bb6d040 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -1754,6 +1754,8 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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; @@ -1779,6 +1781,9 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ PDEBUG("true_recvmsg returned -1, errno: %d, %s\n", errno,strerror(errno)); return -1; } + if(RECV_BUFFER_SIZE == bytes_received){ + PDEBUG("UDP PACKET SHOULD NOT BE THAT BIG\n"); + } // Transfer the fields we do not manage @@ -1802,7 +1807,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ msg->msg_namelen = min; } - return written; + 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"); @@ -1884,7 +1889,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ PDEBUG("Successful recvmsg() hook\n\n"); - return udp_data_len; + 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) } @@ -1936,24 +1941,29 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, } PDEBUG("sockfd %d is associated with udp_relay_chain %x\n", sockfd, relay_chain); - // On lance un receive_udp_packet() + - char tmp_buffer[65535]; //maximum theoretical size of a UDP packet. + 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, tmp_buffer, sizeof(tmp_buffer), flags, (struct sockaddr*)&from, &from_len); + bytes_received = true_recvfrom(sockfd, buffer, sizeof(buffer), flags, (struct sockaddr*)&from, &from_len); if(-1 == bytes_received){ PDEBUG("true_recvfrom returned -1\n"); 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(tmp_buffer, bytes_received); + 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 ? @@ -1963,27 +1973,27 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, 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, tmp_buffer, min); + memcpy(buf, buffer, min); if(src_addr != NULL){ //TODO: check that the address copy is done correctly socklen_t min_addr_len = (from_len<*addrlen)?from_len:*addrlen; memcpy(src_addr, &from, min_addr_len); *addrlen = min_addr_len; } - return min; + 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(tmp_buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); + rc = unsocksify_udp_packet(buffer, bytes_received, *relay_chain, &src_ip, &src_port, &udp_data); 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*)tmp_buffer); + udp_data_len = bytes_received - (udp_data - (void*)buffer); @@ -2004,52 +2014,50 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, // la retrouver ? -> done in unsocksify_udp_packet() - if (src_addr == NULL){ // No need to fill src_addr in this case - return udp_data_len; - } - struct sockaddr_in* src_addr_v4; - struct sockaddr_in6* src_addr_v6; + 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; - //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen - // + //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen + // - 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; + 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); } - 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"); + 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); } - 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 udp_data_len; + 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){ From 1c8c231272bd4c584d1279bef29a78211b187ef6 Mon Sep 17 00:00:00 2001 From: hugoc Date: Fri, 2 Feb 2024 16:39:47 +0100 Subject: [PATCH 25/35] adding comments --- src/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core.c b/src/core.c index 003e90e..9ab3786 100644 --- a/src/core.c +++ b/src/core.c @@ -658,6 +658,8 @@ size_t get_iov_total_len(struct iovec* iov, size_t iov_len){ return n; } +//Tries to write buff_len bytes from buff into the scatter-gather location described by iov and iov_len. +//Stops when all iov's buffers are full. Returns the number of bytes written size_t write_buf_to_iov(void* buff, size_t buff_len, struct iovec* iov, size_t iov_len){ size_t written = 0; int i = 0; From b377a2927b53cc7635908fa90b33291dc0815244 Mon Sep 17 00:00:00 2001 From: hugoc Date: Sat, 10 Feb 2024 16:19:49 +0100 Subject: [PATCH 26/35] hook read and write --- src/allocator_thread.c | 6 +++--- src/core.c | 9 +++++---- src/core.h | 4 ++++ src/debug.c | 2 +- src/libproxychains.c | 46 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 66cf7f6..2c3715f 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,7 +350,7 @@ 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]); diff --git a/src/core.c b/src/core.c index 9ab3786..8cedc3c 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; @@ -934,7 +934,8 @@ int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain cha // Append UDP data in the remaining space of the buffer - int min = (udp_data_len>(buffer_len-tmp_buffer_len))?(buffer_len-tmp_buffer_len):udp_data_len; + size_t min = (udp_data_len>(buffer_len-tmp_buffer_len))?(buffer_len-tmp_buffer_len):udp_data_len; + PDEBUG("test, min = %lu\n", min); memcpy(buffer + tmp_buffer_len, udp_data, min); *buffer_len = tmp_buffer_len + min; @@ -1628,7 +1629,7 @@ struct hostent* proxy_gethostbyname_old(const char *name) close(pipe_fd[1]); waitpid(pid, &status, 0); buff[0] = 0; - read(pipe_fd[0],&buff,sizeof(buff)); + true_read(pipe_fd[0],&buff,sizeof(buff)); close(pipe_fd[0]); got_buff: l = strlen(buff); diff --git a/src/core.h b/src/core.h index 88211fc..9014958 100644 --- a/src/core.h +++ b/src/core.h @@ -176,6 +176,8 @@ 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; @@ -192,6 +194,8 @@ 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; struct gethostbyname_data { struct hostent hostent_space; diff --git a/src/debug.c b/src/debug.c index 81ed643..9b6efc5 100644 --- a/src/debug.c +++ b/src/debug.c @@ -24,7 +24,7 @@ void dump_proxy_chain(proxy_data *pchain, unsigned int count) { void dump_buffer(unsigned char * data, size_t len){ printf("buffer_dump["); - for(int i=0; i #include +#include + + + #include "core.h" #include "common.h" @@ -72,6 +76,8 @@ 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; @@ -1080,6 +1086,8 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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); @@ -1184,7 +1192,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, return -1; } - int sent = 0; + 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){ @@ -2094,6 +2102,40 @@ HOOKFUNC(ssize_t, send, int sockfd, const void *buf, size_t len, int flags){ 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 ){ + + PDEBUG("fd : %d, count: %zu, buf: %p\n", fd, count, buf); + DUMP_BUFFER(buf, 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 #define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = &X; } while(0) #define SETUP_SYM_OPTIONAL(X) @@ -2118,6 +2160,8 @@ static void setup_hooks(void) { SETUP_SYM(freeaddrinfo); SETUP_SYM(gethostbyaddr); SETUP_SYM(getnameinfo); + SETUP_SYM(write); + SETUP_SYM(read); #ifdef IS_SOLARIS SETUP_SYM(__xnet_connect); #endif From 803f8a61b4f61720a6fce09d6372c9f2f261ed73 Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 13 Feb 2024 19:51:14 +0100 Subject: [PATCH 27/35] mutex, true_close, fix del_relay_chain --- src/core.c | 32 +++++++------- src/core.h | 3 +- src/debug.c | 4 +- src/libproxychains.c | 99 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 100 insertions(+), 38 deletions(-) diff --git a/src/core.c b/src/core.c index 8cedc3c..a5f2fc3 100644 --- a/src/core.c +++ b/src/core.c @@ -935,7 +935,6 @@ int socksify_udp_packet(void* udp_data, size_t udp_data_len, udp_relay_chain cha // 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; - PDEBUG("test, min = %lu\n", min); memcpy(buffer + tmp_buffer_len, udp_data, min); *buffer_len = tmp_buffer_len + min; @@ -987,7 +986,7 @@ 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); return SOCKET_ERROR; } @@ -1348,7 +1347,7 @@ int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ err: // Ensure new node tcp socket is closed if(new_node->tcp_sockfd != -1){ - close(new_node->tcp_sockfd); + true_close(new_node->tcp_sockfd); } // Remove the new node from the chain @@ -1365,27 +1364,28 @@ int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ return -1; } -int free_relay_chain(udp_relay_chain chain){ - if(NULL != chain.connected_peer_addr){ - free(chain.connected_peer_addr); - chain.connected_peer_addr = NULL; +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){ + if(chain->head == NULL){ return SUCCESS; } - udp_relay_node * current = chain.head; + udp_relay_node * current = chain->head; udp_relay_node * next = NULL; - + while(current != NULL){ next = current->next; - close(current->tcp_sockfd); + true_close(current->tcp_sockfd); free(current); current = next; } + chain->head = NULL; return SUCCESS; } @@ -1447,7 +1447,7 @@ udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, cha error: PDEBUG("error\n"); release_all(pd, proxy_count); - free_relay_chain(*new_chain); + free_relay_chain_contents(new_chain); free(new_chain); errno = ETIMEDOUT; return NULL; @@ -1491,7 +1491,6 @@ void set_connected_peer_addr(udp_relay_chain* chain, struct sockaddr* addr, sock chain->connected_peer_addr = (struct sockaddr*)new_addr; chain->connected_peer_addr_len = sizeof(struct sockaddr_in); } - } @@ -1505,7 +1504,7 @@ void add_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* new_cha new_chain->prev = NULL; } else { // Add the new chain at the end - chains_list->tail->next = new_chain; + (chains_list->tail)->next = new_chain; new_chain->prev = chains_list->tail; chains_list->tail = new_chain; } @@ -1519,17 +1518,18 @@ void del_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* chain){ chains_list->tail = NULL; }else{ chains_list->head = chain->next; + chains_list->head->prev = NULL; free(chain); } - } else if (chain = chains_list->tail){ + } 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){ diff --git a/src/core.h b/src/core.h index 9014958..e810de8 100644 --- a/src/core.h +++ b/src/core.h @@ -196,6 +196,7 @@ 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; struct gethostbyname_data { struct hostent hostent_space; @@ -218,7 +219,7 @@ static int udp_associate(int sock, ip_type * dst_addr, unsigned short dst_port, 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(udp_relay_chain 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 ); diff --git a/src/debug.c b/src/debug.c index 9b6efc5..be1937f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -34,7 +34,7 @@ void dump_relay_chains_list(udp_relay_chain_list list){ udp_relay_chain* current; current = list.head; - PDEBUG("relay chains list dump: \n"); + PDEBUG("relay chains list (head: %x, tail: %x) dump: \n", list.head, list.tail); while(current != NULL){ dump_relay_chain(current); current = current->next; @@ -47,7 +47,7 @@ void dump_relay_chain(udp_relay_chain* chain){ current_node = chain->head; char ip_buf[INET6_ADDRSTRLEN]; char ip_buf2[INET6_ADDRSTRLEN]; - while(current_node ){ + 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) ); diff --git a/src/libproxychains.c b/src/libproxychains.c index c931f90..b7365ca 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -44,6 +44,7 @@ #include "core.h" #include "common.h" #include "rdns.h" +#include "mutex.h" #undef satosin #define satosin(x) ((struct sockaddr_in *) &(x)) @@ -96,6 +97,7 @@ 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; @@ -152,6 +154,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); @@ -609,27 +612,38 @@ HOOKFUNC(int, close, int fd) { /***** UDP STUFF *******/ //PDEBUG("checking if a relay chain is opened for fd %d\n", fd); - udp_relay_chain* chain = NULL; - - chain = get_relay_chain(relay_chains, fd); - if(NULL != chain){ - PDEBUG("fd %d corresponds to chain %x, closing it\n", fd, chain); - free_relay_chain(*chain); - del_relay_chain(&relay_chains, chain); + 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) return true_close(fd); + 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; } @@ -650,6 +664,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; @@ -734,15 +749,20 @@ HOOKFUNC(int, getpeername, int sockfd, struct sockaddr *restrict addr, socklen_t // 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); } @@ -756,6 +776,7 @@ HOOKFUNC(int, getpeername, int sockfd, struct sockaddr *restrict addr, socklen_t *addrlen = min; + MUTEX_UNLOCK(&relay_chains_mutex); return SUCCESS; /* END UDP STUFF */ @@ -786,6 +807,9 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) 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 @@ -793,12 +817,14 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) 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); } - 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(), ... @@ -819,7 +845,8 @@ HOOKFUNC(int, connect, int sock, const struct sockaddr *addr, unsigned int len) .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) ); } @@ -1130,6 +1157,9 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int 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 @@ -1137,12 +1167,14 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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); } - DUMP_RELAY_CHAINS_LIST(relay_chains); + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); @@ -1153,6 +1185,7 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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; } @@ -1189,8 +1222,10 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, 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)); @@ -1328,6 +1363,9 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int 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 @@ -1335,12 +1373,14 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ 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); } - DUMP_RELAY_CHAINS_LIST(relay_chains); + memcpy(dest_ip.addr.v6, v6 ? (void*)p_addr_in6 : (void*)p_addr_in, v6?16:4); @@ -1359,6 +1399,7 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ 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; } @@ -1394,6 +1435,7 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ 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 @@ -1463,6 +1505,9 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i } // 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 @@ -1470,18 +1515,21 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i 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); + 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; } @@ -1510,6 +1558,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i } else { if(msgvec[i].msg_hdr.msg_namelen > addrlen){ PDEBUG("msgvec[%d].msg_hdr.msg_namelen too long\n", i); + MUTEX_UNLOCK(&relay_chains_mutex); return -1; } addrlen = msgvec[i].msg_hdr.msg_namelen; @@ -1672,10 +1721,11 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i 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){ @@ -1750,10 +1800,14 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int 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); @@ -1787,6 +1841,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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){ @@ -1814,7 +1869,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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) } @@ -1828,6 +1883,7 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ 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; @@ -1940,11 +1996,14 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int 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_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); @@ -1964,6 +2023,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, 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){ @@ -1987,7 +2047,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, 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"); @@ -1996,6 +2056,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, 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; @@ -2054,7 +2115,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, *addrlen = sizeof(src_addr_v6); }else { if(addrlen < sizeof(struct sockaddr_in)){ - PDEBUG("addrlen too short for ipv4\n"); + PDEBUG("addrlen too short for ipv4\n"); } src_addr_v4 = (struct sockaddr_in*)src_addr; src_addr_v4->sin_family = AF_INET; From 03228119655e83b71b2145e53cb307787e49e0cd Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 13 Feb 2024 19:51:24 +0100 Subject: [PATCH 28/35] change debug format --- src/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.h b/src/debug.h index 9645f1c..94afa01 100644 --- a/src/debug.h +++ b/src/debug.h @@ -5,7 +5,7 @@ #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) From 12c95244cee98649c6bab430b0c8a2e1a8ccc512 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 20 Mar 2024 14:53:52 +0100 Subject: [PATCH 29/35] remove some debug --- src/libproxychains.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index b7365ca..934c433 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -2184,8 +2184,6 @@ HOOKFUNC(ssize_t, read,int fd, void* buf, size_t count){ HOOKFUNC(ssize_t, write, int fd, const void* buf, size_t count ){ - PDEBUG("fd : %d, count: %zu, buf: %p\n", fd, count, buf); - DUMP_BUFFER(buf, count); // If fd is a socket, call send() with no flags as it is equivalent to write() struct stat statbuf; From 004b19b1fb805cec009497e34358ea780a556456 Mon Sep 17 00:00:00 2001 From: hugoc Date: Wed, 20 Mar 2024 18:22:30 +0100 Subject: [PATCH 30/35] add chain debug --- src/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core.c b/src/core.c index a5f2fc3..d7ad5b3 100644 --- a/src/core.c +++ b/src/core.c @@ -1341,6 +1341,8 @@ int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ 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; From 7e818c14990bb921e90921c3f2948d32f064ae89 Mon Sep 17 00:00:00 2001 From: hugoc Date: Thu, 21 Mar 2024 17:37:25 +0100 Subject: [PATCH 31/35] fix sendmmsg deadlocks --- src/libproxychains.c | 82 ++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/libproxychains.c b/src/libproxychains.c index 934c433..fe15f80 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -719,7 +719,6 @@ HOOKFUNC(int, getpeername, int sockfd, struct sockaddr *restrict addr, socklen_t INIT(); PFUNC(); - int socktype = 0; socklen_t optlen = 0; optlen = sizeof(socktype); @@ -1466,29 +1465,29 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ 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 dest_addr; - socklen_t addrlen = sizeof(dest_addr); + 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*)&dest_addr, &addrlen); + 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 > addrlen){ + if(msgvec[0].msg_hdr.msg_namelen > first_addrlen){ PDEBUG("msgvec[0].msg_hdr.msg_namelen too long\n"); return -1; } - addrlen = msgvec[0].msg_hdr.msg_namelen; - memcpy(&dest_addr, msgvec[0].msg_hdr.msg_name, addrlen); + first_addrlen = msgvec[0].msg_hdr.msg_namelen; + memcpy(&first_dest_addr, msgvec[0].msg_hdr.msg_name, first_addrlen); } @@ -1497,7 +1496,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i int socktype = 0, ret = 0; socklen_t optlen = 0; optlen = sizeof(socktype); - sa_family_t fam = SOCKFAMILY(dest_addr); + 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); @@ -1535,7 +1534,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i - for(int i=0; i addrlen){ - PDEBUG("msgvec[%d].msg_hdr.msg_namelen too long\n", i); + if(msgvec[msg_index].msg_hdr.msg_namelen > addrlen){ + PDEBUG("msgvec[%d].msg_hdr.msg_namelen too long\n", msg_index); MUTEX_UNLOCK(&relay_chains_mutex); return -1; } - addrlen = msgvec[i].msg_hdr.msg_namelen; - memcpy(&dest_addr, msgvec[i].msg_hdr.msg_name, addrlen); + addrlen = msgvec[msg_index].msg_hdr.msg_namelen; + memcpy(&dest_addr, msgvec[msg_index].msg_hdr.msg_name, addrlen); } ip_type dest_ip; @@ -1590,7 +1604,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i goto cleanCurrentLoop; } - PDEBUG("message %d/%d\n", i, vlen); + 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); @@ -1631,7 +1645,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i 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", i, vlen); + PDEBUG("message %d/%d is accessing localnet\n", msg_index, vlen); goto cleanCurrentLoop; } @@ -1649,7 +1663,7 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i char udp_data[65535]; size_t udp_data_len = 65535; - udp_data_len = write_iov_to_buf(udp_data, udp_data_len,msgvec[i].msg_hdr.msg_iov ,msgvec[i].msg_hdr.msg_iovlen); + 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; @@ -1670,16 +1684,16 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i - tmp_msgvec[i].msg_hdr.msg_control = msgvec[i].msg_hdr.msg_control; - tmp_msgvec[i].msg_hdr.msg_controllen = msgvec[i].msg_hdr.msg_controllen; - tmp_msgvec[i].msg_hdr.msg_flags = msgvec[i].msg_hdr.msg_flags; + 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[i].msg_hdr.msg_iov = iov; - tmp_msgvec[i].msg_hdr.msg_iovlen = 1; + 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(!v6){ if(NULL == (pAddr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)))){ PDEBUG("error malloc\n"); @@ -1689,8 +1703,8 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i 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[i].msg_hdr.msg_name = (struct sockaddr*)pAddr; - tmp_msgvec[i].msg_hdr.msg_namelen = sizeof(*pAddr) ; + 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)))){ @@ -1701,8 +1715,8 @@ HOOKFUNC(int, sendmmsg, int sockfd, struct mmsghdr* msgvec, unsigned int vlen, i 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[i].msg_hdr.msg_name = (struct sockaddr*)pAddr6; - tmp_msgvec[i].msg_hdr.msg_namelen = sizeof(*pAddr6); + tmp_msgvec[msg_index].msg_hdr.msg_name = (struct sockaddr*)pAddr6; + tmp_msgvec[msg_index].msg_hdr.msg_namelen = sizeof(*pAddr6); } allocated_len += 1; From 2eb03d371940129ab6c6f779983dbf8877d44f12 Mon Sep 17 00:00:00 2001 From: hugoc Date: Fri, 22 Mar 2024 18:37:48 +0100 Subject: [PATCH 32/35] Changed calls to close, sendto, recvfrom to calls to true_XX calls to avoid some deadlocks --- src/allocator_thread.c | 8 ++++---- src/core.c | 24 ++++++++++++------------ src/rdns.c | 12 ++++++------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 2c3715f..4638b0a 100644 --- a/src/allocator_thread.c +++ b/src/allocator_thread.c @@ -352,9 +352,9 @@ void at_close(void) { const int msg = ATM_EXIT; 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 d7ad5b3..a3ca199 100644 --- a/src/core.c +++ b/src/core.c @@ -1063,7 +1063,7 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { 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); + true_close(ns); return SOCKET_ERROR; } hostname = ip_buf; @@ -1078,12 +1078,12 @@ static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { case BLOCKED: pto->ps = BLOCKED_STATE; proxychains_write_log("<--denied\n"); - close(ns); + true_close(ns); break; case SOCKET_ERROR: pto->ps = DOWN_STATE; proxychains_write_log("<--socket error or timeout!\n"); - close(ns); + true_close(ns); break; } return retcode; @@ -1240,11 +1240,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; @@ -1255,7 +1255,7 @@ 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; } @@ -1612,9 +1612,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); @@ -1622,17 +1622,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; true_read(pipe_fd[0],&buff,sizeof(buff)); - close(pipe_fd[0]); + true_close(pipe_fd[0]); got_buff: l = strlen(buff); if (!l) goto err_dns; 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; } From 65ab050bc2e54490dc8560d1bbb17493c74b761f Mon Sep 17 00:00:00 2001 From: hc Date: Wed, 22 May 2024 17:52:59 +0200 Subject: [PATCH 33/35] add uv_close hook --- src/core.h | 3 +++ src/libproxychains.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/core.h b/src/core.h index e810de8..873b05d 100644 --- a/src/core.h +++ b/src/core.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifndef __CORE_HEADER #define __CORE_HEADER @@ -151,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 int (*freeaddrinfo_t)(struct addrinfo *); @@ -197,6 +199,7 @@ 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; diff --git a/src/libproxychains.c b/src/libproxychains.c index fe15f80..9f7f8f6 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -37,6 +37,7 @@ #include #include +#include @@ -63,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; @@ -647,6 +649,41 @@ HOOKFUNC(int, close, int fd) { 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); } @@ -2240,6 +2277,7 @@ static void setup_hooks(void) { #endif SETUP_SYM(close); SETUP_SYM_OPTIONAL(close_range); + SETUP_SYM_OPTIONAL(uv_close); } #ifdef MONTEREY_HOOKING From 14ba73189c865fd3b9a0a6d3145288f5772257b3 Mon Sep 17 00:00:00 2001 From: hc Date: Thu, 20 Jun 2024 15:40:40 +0200 Subject: [PATCH 34/35] clean some comments --- Makefile | 2 +- src/core.c | 22 --------------------- src/core.h | 2 +- src/libproxychains.c | 47 +++----------------------------------------- 4 files changed, 5 insertions(+), 68 deletions(-) diff --git a/Makefile b/Makefile index 23ba476..3320904 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ LOBJS = src/version.o \ GENH = src/version.h -CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DDEBUG +CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe NO_AS_NEEDED = -Wl,--no-as-needed LDFLAGS = -fPIC $(NO_AS_NEEDED) $(LIBDL) $(PTHREAD) INC = diff --git a/src/core.c b/src/core.c index a3ca199..5caea7e 100644 --- a/src/core.c +++ b/src/core.c @@ -992,8 +992,6 @@ static int start_chain(int *fd, proxy_data * pd, char *begin_mark) { static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) { PFUNC(); - PDEBUG("offset: %d\n", *offset); - PDEBUG("state: %d\n", pd[0].ps); unsigned int i = 0, k = 0; if(*offset >= proxy_count) return NULL; @@ -1260,26 +1258,6 @@ int connect_proxy_chain(int sock, ip_type target_ip, return -1; } -// int connect_to_lastnode(int *sock, udp_relay_chain chain){ - -// udp_relay_node * current_node = chain.head; - -// //First connect to the chain head -// if(SUCCESS != start_chain(sock, &(current_node->pd), UDPC)){ -// PDEBUG("start_chain failed\n"); -// return -1; -// } -// // Connect to the rest of the chain -// while(current_node->next != NULL){ -// if(SUCCESS != chain_step(sock, &(current_node->pd), &(current_node->next->pd))){ -// PDEBUG("chain step failed\n"); -// return -1; -// } -// current_node = current_node->next; -// } - -// return SUCCESS; -// } int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ PFUNC(); diff --git a/src/core.h b/src/core.h index 873b05d..59e4ab1 100644 --- a/src/core.h +++ b/src/core.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include //Needed to hook uv_close() #ifndef __CORE_HEADER #define __CORE_HEADER diff --git a/src/libproxychains.c b/src/libproxychains.c index 9f7f8f6..0ce1745 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -627,8 +627,6 @@ HOOKFUNC(int, close, int fd) { PDEBUG("chain %x corresponding to fd %d closed\n", relay_chain, fd); DUMP_RELAY_CHAINS_LIST(relay_chains); } - - /***** END UDP STUFF *******/ @@ -995,13 +993,10 @@ HOOKFUNC(int, getaddrinfo, const char *node, const char *service, const struct a INIT(); PDEBUG("getaddrinfo: %s %s\n", node ? node : "null", service ? service : "null"); - if(proxychains_resolver != DNSLF_LIBC){ - PDEBUG("using proxy_getaddrinfo()\n"); + if(proxychains_resolver != DNSLF_LIBC) return proxy_getaddrinfo(node, service, hints, res); - } - else{ + else return true_getaddrinfo(node, service, hints, res); - } } HOOKFUNC(void, freeaddrinfo, struct addrinfo *res) { @@ -1226,13 +1221,6 @@ HOOKFUNC(ssize_t, sendto, int sockfd, const void *buf, size_t len, int flags, } // Send the packet - // FIXME: should write_n_bytes be used here instead ? -> No, because we send data on an unconnected socket, so we need to use sendto with an address and not send. - // We thus cannot use write(), which cannot be given an address - - // if(chain.head->bnd_addr.atyp == ATYP_DOM){ - // PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n"); - // goto err; - // } v6 = relay_chain->head->bnd_addr.is_v6; @@ -1279,22 +1267,6 @@ HOOKFUNC(ssize_t, sendmsg, int sockfd, const struct msghdr *msg, int flags){ INIT(); PFUNC(); - //TODO : do we keep this FASTOPEN code from sendto() ? - // if (flags & MSG_FASTOPEN) { - // if (!connect(sockfd, dest_addr, addrlen) && errno != EINPROGRESS) { - // return -1; - // } - // dest_addr = NULL; - // addrlen = 0; - // flags &= ~MSG_FASTOPEN; - - // return true_sendto(sockfd, buf, len, flags, dest_addr, addrlen); - // } - - //TODO hugoc: case of SOCK_DGRAM with AF_INET or AF_INET6 - - //TODO: check what to do when a UDP socket has been "connected" before and then sendmsg is called with msg->msg_name = NULL ? - struct sockaddr_storage dest_addr; socklen_t addrlen = sizeof(dest_addr); @@ -1963,9 +1935,6 @@ HOOKFUNC(ssize_t, recvmsg, int sockfd, struct msghdr *msg, int flags){ struct sockaddr_in* src_addr_v4; struct sockaddr_in6* src_addr_v6; - //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen - // TODO faire une fonction cast_iptype_to_sockaddr() - 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)){ @@ -2021,7 +1990,6 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen){ INIT(); PFUNC(); - //TODO hugoc DEBUGDECL(char str[256]); int socktype = 0; socklen_t optlen = 0; @@ -2093,7 +2061,7 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, int min = (bytes_received <= len)?bytes_received:len; memcpy(buf, buffer, min); - if(src_addr != NULL){ //TODO: check that the address copy is done correctly + 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; @@ -2128,20 +2096,11 @@ HOOKFUNC(ssize_t, recvfrom, int sockfd, void *buf, size_t len, int flags, // 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); - - // WARNING : Est ce que si le client avait envoyé des packets UDP avec resolution DNS dans le socks, - // on doit lui filer comme address source pour les packets recu l'addresse de mapping DNS ? Si oui comment - // la retrouver ? -> done in unsocksify_udp_packet() - - 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; - //TODO bien gérer le controle de la taille de la src_addr fournie et le retour dans addrlen - // - 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)){ From 04f66223a44d5cf24aadfa667056543f036d9912 Mon Sep 17 00:00:00 2001 From: hc-syn Date: Thu, 18 Jul 2024 14:42:52 +0200 Subject: [PATCH 35/35] adapt to chain_step signature change --- src/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core.c b/src/core.c index f8777df..afe26f4 100644 --- a/src/core.c +++ b/src/core.c @@ -986,7 +986,7 @@ 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; @@ -1087,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; } @@ -1310,7 +1310,7 @@ int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){ } // Connect to the rest of the chain while(tmp->next != NULL){ - if(SUCCESS != chain_step(new_node->tcp_sockfd, &(tmp->pd), &(tmp->next->pd))){ + 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;