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 <sys/time.h>
#include <stdarg.h>
#include <assert.h>
#ifdef THREAD_SAFE
#include <pthread.h>
pthread_mutex_t internal_ips_lock;
@ -736,13 +737,9 @@ int connect_proxy_chain(int sock, ip_type target_ip,
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} };
struct hostent *proxy_gethostbyname(const char *name) {
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
char buff[256];
uint32_t i, hash;
// 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;
resolved_addr_p[0] = (char *) &resolved_addr;
resolved_addr_p[1] = NULL;
data->resolved_addr_p[0] = (char *) &data->resolved_addr;
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));
if(!strcmp(buff, name)) {
resolved_addr = inet_addr(buff);
if(resolved_addr == (in_addr_t) (-1))
resolved_addr = (in_addr_t) (local_host.as_int);
return &hostent_space;
data->resolved_addr = inet_addr(buff);
if(data->resolved_addr == (in_addr_t) (-1))
data->resolved_addr = (in_addr_t) (local_host.as_int);
return &data->hostent_space;
}
memset(buff, 0, sizeof(buff));
@ -782,7 +779,7 @@ struct hostent *proxy_gethostbyname(const char *name) {
if(internal_ips.counter) {
for(i = 0; i < internal_ips.counter; i++) {
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);
goto have_ip;
}
@ -802,8 +799,8 @@ struct hostent *proxy_gethostbyname(const char *name) {
}
}
resolved_addr = make_internal_ip(internal_ips.counter);
if(resolved_addr == (in_addr_t) - 1)
data->resolved_addr = make_internal_ip(internal_ips.counter);
if(data->resolved_addr == (in_addr_t) - 1)
goto err_plus_unlock;
l = strlen(name);
@ -825,64 +822,69 @@ struct hostent *proxy_gethostbyname(const char *name) {
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;
hostent_space.h_length = sizeof(in_addr_t);
return &hostent_space;
data->hostent_space.h_name = data->addr_name;
data->hostent_space.h_length = sizeof(in_addr_t);
return &data->hostent_space;
err_plus_unlock:
MUTEX_UNLOCK(&internal_ips_lock);
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) {
struct gethostbyname_data ghdata;
struct addrinfo_data *space;
struct servent *se = NULL;
struct hostent *hp = NULL;
struct sockaddr *sockaddr_space = NULL;
struct addrinfo *addrinfo_space = NULL;
struct servent se_buf;
char buf[1024];
int port;
// printf("proxy_getaddrinfo node %s service %s\n",node,service);
addrinfo_space = malloc(sizeof(struct addrinfo));
if(!addrinfo_space)
goto err1;
sockaddr_space = malloc(sizeof(struct sockaddr));
if(!sockaddr_space)
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);
space = calloc(1, sizeof(struct addrinfo_data));
if(!space) goto err1;
if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) {
hp = proxy_gethostbyname(node, &ghdata);
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));
else
goto err3;
goto err2;
}
if(service) getservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
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)->ai_addr = sockaddr_space;
*res = &space->addrinfo_space;
assert((size_t)(*res) == (size_t) space);
(*res)->ai_addr = &space->sockaddr_space;
if(node)
strcpy(addr_name, node);
(*res)->ai_canonname = addr_name;
strncpy(space->addr_name, node, sizeof(space->addr_name));
(*res)->ai_canonname = space->addr_name;
(*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_flags = hints->ai_flags;
(*res)->ai_protocol = hints->ai_protocol;
(*res)->ai_addrlen = sizeof(*sockaddr_space);
(*res)->ai_addrlen = sizeof(space->sockaddr_space);
goto out;
err3:
free(sockaddr_space);
err2:
free(addrinfo_space);
free(space);
err1:
return 1;
out:

View File

@ -123,11 +123,18 @@ extern freeaddrinfo_t true_freeaddrinfo;
extern getnameinfo_t true_getnameinfo;
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,
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);

View File

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