From 23c9654cf84c783a28d2faf406e3f492572c2b9d Mon Sep 17 00:00:00 2001 From: hugoc Date: Tue, 16 Jan 2024 16:00:30 +0100 Subject: [PATCH] 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);