1
0
mirror of https://github.com/rofl0r/proxychains-ng synced 2025-01-23 01:12:59 +08:00

implements udp reception and fixes

This commit is contained in:
hugoc 2023-12-10 16:05:19 +01:00
parent 48422d4c07
commit 4c75e059d9
3 changed files with 298 additions and 41 deletions

View File

@ -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,

View File

@ -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

View File

@ -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){