make getaddrinfo threadsafe

This commit is contained in:
rofl0r 2012-07-16 01:05:28 +02:00
parent 4b999cdae7
commit 40edf758ee
3 changed files with 59 additions and 51 deletions

View File

@ -33,6 +33,7 @@
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
#ifdef THREAD_SAFE #ifdef THREAD_SAFE
#include <pthread.h> #include <pthread.h>
pthread_mutex_t internal_ips_lock; pthread_mutex_t internal_ips_lock;
@ -736,13 +737,9 @@ int connect_proxy_chain(int sock, ip_type target_ip,
return -1; return -1;
} }
// TODO: all those buffers aren't threadsafe, but since no memory allocation happens there shouldnt be any segfaults
static struct hostent hostent_space;
static in_addr_t resolved_addr;
static char *resolved_addr_p[2];
static char addr_name[1024 * 8];
static const ip_type local_host = { {127, 0, 0, 1} }; static const ip_type local_host = { {127, 0, 0, 1} };
struct hostent *proxy_gethostbyname(const char *name) {
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
char buff[256]; char buff[256];
uint32_t i, hash; uint32_t i, hash;
// yep, new_mem never gets freed. once you passed a fake ip to the client, you can't "retreat" it // yep, new_mem never gets freed. once you passed a fake ip to the client, you can't "retreat" it
@ -751,20 +748,20 @@ struct hostent *proxy_gethostbyname(const char *name) {
struct hostent *hp; struct hostent *hp;
resolved_addr_p[0] = (char *) &resolved_addr; data->resolved_addr_p[0] = (char *) &data->resolved_addr;
resolved_addr_p[1] = NULL; data->resolved_addr_p[1] = NULL;
hostent_space.h_addr_list = resolved_addr_p; data->hostent_space.h_addr_list = data->resolved_addr_p;
resolved_addr = 0; data->resolved_addr = 0;
gethostname(buff, sizeof(buff)); gethostname(buff, sizeof(buff));
if(!strcmp(buff, name)) { if(!strcmp(buff, name)) {
resolved_addr = inet_addr(buff); data->resolved_addr = inet_addr(buff);
if(resolved_addr == (in_addr_t) (-1)) if(data->resolved_addr == (in_addr_t) (-1))
resolved_addr = (in_addr_t) (local_host.as_int); data->resolved_addr = (in_addr_t) (local_host.as_int);
return &hostent_space; return &data->hostent_space;
} }
memset(buff, 0, sizeof(buff)); memset(buff, 0, sizeof(buff));
@ -782,7 +779,7 @@ struct hostent *proxy_gethostbyname(const char *name) {
if(internal_ips.counter) { if(internal_ips.counter) {
for(i = 0; i < internal_ips.counter; i++) { for(i = 0; i < internal_ips.counter; i++) {
if(internal_ips.list[i]->hash == hash && !strcmp(name, internal_ips.list[i]->string)) { if(internal_ips.list[i]->hash == hash && !strcmp(name, internal_ips.list[i]->string)) {
resolved_addr = make_internal_ip(i); data->resolved_addr = make_internal_ip(i);
PDEBUG("got cached ip for %s\n", name); PDEBUG("got cached ip for %s\n", name);
goto have_ip; goto have_ip;
} }
@ -802,8 +799,8 @@ struct hostent *proxy_gethostbyname(const char *name) {
} }
} }
resolved_addr = make_internal_ip(internal_ips.counter); data->resolved_addr = make_internal_ip(internal_ips.counter);
if(resolved_addr == (in_addr_t) - 1) if(data->resolved_addr == (in_addr_t) - 1)
goto err_plus_unlock; goto err_plus_unlock;
l = strlen(name); l = strlen(name);
@ -825,64 +822,69 @@ struct hostent *proxy_gethostbyname(const char *name) {
MUTEX_UNLOCK(&internal_ips_lock); MUTEX_UNLOCK(&internal_ips_lock);
strncpy(addr_name, name, sizeof(addr_name)); strncpy(data->addr_name, name, sizeof(data->addr_name));
hostent_space.h_name = addr_name; data->hostent_space.h_name = data->addr_name;
hostent_space.h_length = sizeof(in_addr_t); data->hostent_space.h_length = sizeof(in_addr_t);
return &hostent_space; return &data->hostent_space;
err_plus_unlock: err_plus_unlock:
MUTEX_UNLOCK(&internal_ips_lock); MUTEX_UNLOCK(&internal_ips_lock);
return NULL; return NULL;
} }
struct addrinfo_data {
struct addrinfo addrinfo_space;
struct sockaddr sockaddr_space;
char addr_name[256];
};
void proxy_freeaddrinfo(struct addrinfo *res) {
free(res);
}
int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
struct gethostbyname_data ghdata;
struct addrinfo_data *space;
struct servent *se = NULL; struct servent *se = NULL;
struct hostent *hp = NULL; struct hostent *hp = NULL;
struct sockaddr *sockaddr_space = NULL;
struct addrinfo *addrinfo_space = NULL;
struct servent se_buf; struct servent se_buf;
char buf[1024]; char buf[1024];
int port; int port;
// printf("proxy_getaddrinfo node %s service %s\n",node,service); // printf("proxy_getaddrinfo node %s service %s\n",node,service);
addrinfo_space = malloc(sizeof(struct addrinfo)); space = calloc(1, sizeof(struct addrinfo_data));
if(!addrinfo_space) if(!space) goto err1;
goto err1;
sockaddr_space = malloc(sizeof(struct sockaddr)); if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) {
if(!sockaddr_space) hp = proxy_gethostbyname(node, &ghdata);
goto err2;
memset(sockaddr_space, 0, sizeof(*sockaddr_space));
memset(addrinfo_space, 0, sizeof(*addrinfo_space));
if(node && !inet_aton(node, &((struct sockaddr_in *) sockaddr_space)->sin_addr)) {
hp = proxy_gethostbyname(node);
if(hp) if(hp)
memcpy(&((struct sockaddr_in *) sockaddr_space)->sin_addr, memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
*(hp->h_addr_list), sizeof(in_addr_t)); *(hp->h_addr_list), sizeof(in_addr_t));
else else
goto err3; goto err2;
} }
if(service) getservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se); if(service) getservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
port = se ? se->s_port : htons(atoi(service ? service : "0")); port = se ? se->s_port : htons(atoi(service ? service : "0"));
((struct sockaddr_in *) sockaddr_space)->sin_port = port; ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port;
*res = addrinfo_space; *res = &space->addrinfo_space;
(*res)->ai_addr = sockaddr_space; assert((size_t)(*res) == (size_t) space);
(*res)->ai_addr = &space->sockaddr_space;
if(node) if(node)
strcpy(addr_name, node); strncpy(space->addr_name, node, sizeof(space->addr_name));
(*res)->ai_canonname = addr_name; (*res)->ai_canonname = space->addr_name;
(*res)->ai_next = NULL; (*res)->ai_next = NULL;
(*res)->ai_family = sockaddr_space->sa_family = AF_INET; (*res)->ai_family = space->sockaddr_space.sa_family = AF_INET;
(*res)->ai_socktype = hints->ai_socktype; (*res)->ai_socktype = hints->ai_socktype;
(*res)->ai_flags = hints->ai_flags; (*res)->ai_flags = hints->ai_flags;
(*res)->ai_protocol = hints->ai_protocol; (*res)->ai_protocol = hints->ai_protocol;
(*res)->ai_addrlen = sizeof(*sockaddr_space); (*res)->ai_addrlen = sizeof(space->sockaddr_space);
goto out; goto out;
err3:
free(sockaddr_space);
err2: err2:
free(addrinfo_space); free(space);
err1: err1:
return 1; return 1;
out: out:

View File

@ -123,11 +123,18 @@ extern freeaddrinfo_t true_freeaddrinfo;
extern getnameinfo_t true_getnameinfo; extern getnameinfo_t true_getnameinfo;
extern gethostbyaddr_t true_gethostbyaddr; extern gethostbyaddr_t true_gethostbyaddr;
struct gethostbyname_data {
struct hostent hostent_space;
in_addr_t resolved_addr;
char *resolved_addr_p[2];
char addr_name[1024 * 8];
};
struct hostent* proxy_gethostbyname(const char *name); struct hostent* proxy_gethostbyname(const char *name, struct gethostbyname_data *data);
int proxy_getaddrinfo(const char *node, const char *service, int proxy_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res); const struct addrinfo *hints, struct addrinfo **res);
void proxy_freeaddrinfo(struct addrinfo *res);
void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes); void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes);

View File

@ -325,13 +325,14 @@ int connect(int sock, const struct sockaddr *addr, unsigned int len) {
return ret; return ret;
} }
static struct gethostbyname_data ghbndata;
struct hostent *gethostbyname(const char *name) { struct hostent *gethostbyname(const char *name) {
INIT(); INIT();
PDEBUG("gethostbyname: %s\n", name); PDEBUG("gethostbyname: %s\n", name);
if(proxychains_resolver) if(proxychains_resolver)
return proxy_gethostbyname(name); return proxy_gethostbyname(name, &ghbndata);
else else
return true_gethostbyname(name); return true_gethostbyname(name);
@ -360,10 +361,8 @@ void freeaddrinfo(struct addrinfo *res) {
if(!proxychains_resolver) if(!proxychains_resolver)
true_freeaddrinfo(res); true_freeaddrinfo(res);
else { else
free(res->ai_addr); proxy_freeaddrinfo(res);
free(res);
}
return; return;
} }