diff --git a/Makefile b/Makefile index 4a5c8fc..45d072c 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ sysconfdir=$(prefix)/etc SRCS = $(sort $(wildcard src/*.c)) OBJS = $(SRCS:.c=.o) -LOBJS = src/core.o src/common.o src/libproxychains.o src/shm.o src/allocator_thread.o +LOBJS = src/core.o src/common.o src/libproxychains.o src/shm.o src/allocator_thread.o src/ip_type.o CFLAGS += -Wall -O0 -g -std=c99 -D_GNU_SOURCE -pipe -DTHREAD_SAFE LDFLAGS = -shared -fPIC -Wl,--no-as-needed -ldl -lpthread diff --git a/src/allocator_thread.c b/src/allocator_thread.c index 7590df0..5fd8500 100644 --- a/src/allocator_thread.c +++ b/src/allocator_thread.c @@ -5,58 +5,266 @@ #include #include #include +#include +#include +#include "allocator_thread.h" #include "shm.h" #include "debug.h" +#include "ip_type.h" +#include "mutex.h" + +struct stringpool mem; +static char *at_dumpstring(char* s, size_t len) { + PFUNC(); + return stringpool_add(&mem, s, len); +} + + +/* stuff for our internal translation table */ + +typedef struct { + uint32_t hash; + char* string; +} string_hash_tuple; + +typedef struct { + uint32_t counter; + uint32_t capa; + string_hash_tuple** list; +} internal_ip_lookup_table; + +pthread_mutex_t internal_ips_lock; +internal_ip_lookup_table *internal_ips = NULL; +internal_ip_lookup_table internal_ips_buf; + +uint32_t dalias_hash(char *s0) { + unsigned char *s = (void *) s0; + uint_fast32_t h = 0; + while(*s) { + h = 16 * h + *s++; + h ^= h >> 24 & 0xf0; + } + return h & 0xfffffff; +} + +uint32_t index_from_internal_ip(ip_type internalip) { + PFUNC(); + ip_type tmp = internalip; + uint32_t ret; + ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); + ret -= 1; + return ret; +} + +char *string_from_internal_ip(ip_type internalip) { + PFUNC(); + char *res = NULL; + uint32_t index = index_from_internal_ip(internalip); + MUTEX_LOCK(&internal_ips_lock); + if(index < internal_ips->counter) + res = internal_ips->list[index]->string; + MUTEX_UNLOCK(&internal_ips_lock); + return res; +} + +extern unsigned int remote_dns_subnet; +ip_type make_internal_ip(uint32_t index) { + ip_type ret; + index++; // so we can start at .0.0.1 + if(index > 0xFFFFFF) + return ip_type_invalid; + ret.octet[0] = remote_dns_subnet & 0xFF; + ret.octet[1] = (index & 0xFF0000) >> 16; + ret.octet[2] = (index & 0xFF00) >> 8; + ret.octet[3] = index & 0xFF; + return ret; +} + +static ip_type ip_from_internal_list(char* name, size_t len) { + uint32_t hash = dalias_hash((char *) name); + size_t i; + ip_type res; + void* new_mem; + + MUTEX_LOCK(&internal_ips_lock); + + // see if we already have this dns entry saved. + 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)) { + res = make_internal_ip(i); + PDEBUG("got cached ip for %s\n", name); + goto have_ip; + } + } + } + // grow list if needed. + if(internal_ips->capa < internal_ips->counter + 1) { + PDEBUG("realloc\n"); + new_mem = realloc(internal_ips->list, (internal_ips->capa + 16) * sizeof(void *)); + if(new_mem) { + internal_ips->capa += 16; + internal_ips->list = new_mem; + } else { + oom: + PDEBUG("out of mem\n"); + goto err_plus_unlock; + } + } + + res = make_internal_ip(internal_ips->counter); + if(res.as_int == ip_type_invalid.as_int) + goto err_plus_unlock; + + string_hash_tuple tmp = { 0 }; + new_mem = at_dumpstring((char*) &tmp, sizeof(string_hash_tuple)); + if(!new_mem) + goto oom; + + PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips->counter, name); + + internal_ips->list[internal_ips->counter] = new_mem; + internal_ips->list[internal_ips->counter]->hash = hash; + + new_mem = at_dumpstring((char*) name, len + 1); + + if(!new_mem) { + internal_ips->list[internal_ips->counter] = 0; + goto oom; + } + internal_ips->list[internal_ips->counter]->string = new_mem; + + internal_ips->counter += 1; + + have_ip: + + MUTEX_UNLOCK(&internal_ips_lock); + + return res; + err_plus_unlock: + + MUTEX_UNLOCK(&internal_ips_lock); + PDEBUG("return err\n"); + return ip_type_invalid; +} + +/* stuff for communication with the allocator thread */ enum at_msgtype { - ATM_REALLOC, - ATM_STRINGDUMP, + ATM_GETIP, + ATM_GETNAME, ATM_EXIT, }; +enum at_direction { + ATD_SERVER = 0, + ATD_CLIENT, + ATD_MAX, +}; + +struct at_msghdr { + enum at_msgtype msgtype; + size_t datalen; +}; + static pthread_t allocator_thread; static pthread_attr_t allocator_thread_attr; static int req_pipefd[2]; static int resp_pipefd[2]; -static size_t *at_oldsize; -static size_t *at_newsize; -static void **at_data; -struct stringpool mem; -static void* threadfunc(void* x) { - (void) x; - int readfd = req_pipefd[0]; - int writefd = resp_pipefd[1]; +static int wait_data(int readfd) { + PFUNC(); fd_set fds; FD_ZERO(&fds); FD_SET(readfd, &fds); int ret; - int msg; - while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) != -1) { - assert(ret); - if(read(readfd, &msg, sizeof(int)) != sizeof(int)) { - perror("read"); - } else { - void *nu; - switch(msg) { - case ATM_REALLOC: - nu = shm_realloc(*at_data, *at_oldsize, *at_newsize); - break; - case ATM_STRINGDUMP: - nu = stringpool_add(&mem, *at_data, *at_newsize); - break; - case ATM_EXIT: - return 0; - default: - abort(); - } - *at_data = nu; - write(writefd, &msg, sizeof(int)); + while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) <= 0) { + if(ret < 0) { + perror("select2"); + return 0; } } + return 1; +} + +static int sendmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) { + static int* destfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[1], [ATD_CLIENT] = &resp_pipefd[1] }; + int ret = write(*destfd[dir], hdr, sizeof *hdr) == sizeof *hdr; + if(ret && hdr->datalen) { + assert(hdr->datalen <= MSG_LEN_MAX); + ret = write(*destfd[dir], data, hdr->datalen) == hdr->datalen; + } + return ret; +} + +static int getmessage(enum at_direction dir, struct at_msghdr *hdr, void* data) { + static int* readfd[ATD_MAX] = { [ATD_SERVER] = &req_pipefd[0], [ATD_CLIENT] = &resp_pipefd[0] }; + int ret; + if((ret = wait_data(*readfd[dir]))) { + ret = read(*readfd[dir], hdr, sizeof *hdr) == sizeof(*hdr); + assert(hdr->datalen <= MSG_LEN_MAX); + if(ret && hdr->datalen) { + ret = read(*readfd[dir], data, hdr->datalen) == hdr->datalen; + } + } + return ret; +} + +static void* threadfunc(void* x) { + (void) x; + int ret; + struct at_msghdr msg; + union { + char host[MSG_LEN_MAX]; + ip_type ip; + } readbuf; + while((ret = getmessage(ATD_SERVER, &msg, &readbuf))) { + switch(msg.msgtype) { + case ATM_GETIP: + /* client wants an ip for a DNS name. iterate our list and check if we have an existing entry. + * if not, create a new one. */ + readbuf.ip = ip_from_internal_list(readbuf.host, msg.datalen - 1); + msg.datalen = sizeof(ip_type); + break; + case ATM_GETNAME: { + char *host = string_from_internal_ip(readbuf.ip); + if(host) { + size_t l = strlen(host); + assert(l < MSG_LEN_MAX); + memcpy(readbuf.host, host, l + 1); + msg.datalen = l + 1; + } + break; + } + case ATM_EXIT: + return 0; + default: + abort(); + } + ret = sendmessage(ATD_CLIENT, &msg, &readbuf); + } return 0; } +ip_type at_get_ip_for_host(char* host, size_t len) { + ip_type readbuf; + if(len > MSG_LEN_MAX) goto inv; + struct at_msghdr msg = {.msgtype = ATM_GETIP, .datalen = len + 1 }; + if(sendmessage(ATD_SERVER, &msg, host) && + getmessage(ATD_CLIENT, &msg, &readbuf)) + return readbuf; + inv: + return ip_type_invalid; +} + +size_t at_get_host_for_ip(ip_type ip, char* readbuf) { + struct at_msghdr msg = {.msgtype = ATM_GETNAME, .datalen = sizeof(ip_type) }; + if(sendmessage(ATD_SERVER, &msg, &ip) && getmessage(ATD_CLIENT, &msg, readbuf)) + return msg.datalen - 1; + return 0; +} + + static void initpipe(int* fds) { if(pipe2(fds, 0/*O_CLOEXEC*/) == -1) { perror("pipe"); @@ -66,13 +274,13 @@ static void initpipe(int* fds) { /* initialize with pointers to shared memory. these will * be used to place responses and arguments */ -void at_init(void **data, size_t *oldsize, size_t *newsize) { +void at_init(void) { PFUNC(); + MUTEX_INIT(&internal_ips_lock); + internal_ips = &internal_ips_buf; + memset(internal_ips, 0, sizeof *internal_ips); initpipe(req_pipefd); initpipe(resp_pipefd); - at_oldsize = oldsize; - at_newsize = newsize; - at_data = data; stringpool_init(&mem); pthread_attr_init(&allocator_thread_attr); pthread_attr_setstacksize(&allocator_thread_attr, 16 * 1024); @@ -88,39 +296,5 @@ void at_close(void) { close(req_pipefd[1]); close(resp_pipefd[0]); close(resp_pipefd[1]); -} - -static int wait_reply(void) { - PFUNC(); - int readfd = resp_pipefd[0]; - fd_set fds; - FD_ZERO(&fds); - FD_SET(readfd, &fds); - int ret; - while((ret = select(readfd+1, &fds, NULL, NULL, NULL)) <= 0) { - if(ret < 0) perror("select2"); - } - read(readfd, &ret, sizeof(int)); - return ret; -} - -void *at_realloc(void* old, size_t oldsize, size_t newsize) { - PFUNC(); - *at_data = old; - *at_oldsize = oldsize; - *at_newsize = newsize; - const int msg = ATM_REALLOC; - write(req_pipefd[1], &msg, sizeof(int)); - assert(wait_reply() == msg); - return *at_data; -} - -char *at_dumpstring(char* s, size_t len) { - PFUNC(); - *at_data = s; - *at_newsize = len; - const int msg = ATM_STRINGDUMP; - write(req_pipefd[1], &msg, sizeof(int)); - assert(wait_reply() == msg); - return *at_data; + MUTEX_DESTROY(&internal_ips_lock); } diff --git a/src/allocator_thread.h b/src/allocator_thread.h index 938d3f7..2099a1a 100644 --- a/src/allocator_thread.h +++ b/src/allocator_thread.h @@ -1,8 +1,15 @@ -#include +#ifndef ALLOCATOR_THREAD_H +#define ALLOCATOR_THREAD_H -void *at_realloc(void* old, size_t oldsize, size_t newsize); -char *at_dumpstring(char* s, size_t len); -void at_init(void **data, size_t *oldsize, size_t *newsize); +#include +#include "ip_type.h" + +#define MSG_LEN_MAX 256 + +void at_init(void); void at_close(void); +size_t at_get_host_for_ip(ip_type ip, char* readbuf); +ip_type at_get_ip_for_host(char* host, size_t len); //RcB: DEP "allocator_thread.c" +#endif \ No newline at end of file diff --git a/src/core.c b/src/core.c index 72718e5..c7ed7b2 100644 --- a/src/core.c +++ b/src/core.c @@ -36,7 +36,6 @@ #include #ifdef THREAD_SAFE #include -pthread_mutex_t internal_ips_lock; pthread_mutex_t hostdb_lock; #endif @@ -50,50 +49,6 @@ extern int tcp_connect_time_out; extern int proxychains_quiet_mode; extern unsigned int remote_dns_subnet; -internal_ip_lookup_table *internal_ips = NULL; - -uint32_t dalias_hash(char *s0) { - unsigned char *s = (void *) s0; - uint_fast32_t h = 0; - while(*s) { - h = 16 * h + *s++; - h ^= h >> 24 & 0xf0; - } - return h & 0xfffffff; -} - -uint32_t index_from_internal_ip(ip_type internalip) { - PFUNC(); - ip_type tmp = internalip; - uint32_t ret; - ret = tmp.octet[3] + (tmp.octet[2] << 8) + (tmp.octet[1] << 16); - ret -= 1; - return ret; -} - -char *string_from_internal_ip(ip_type internalip) { - PFUNC(); - char *res = NULL; - uint32_t index = index_from_internal_ip(internalip); - MUTEX_LOCK(&internal_ips_lock); - if(index < internal_ips->counter) - res = internal_ips->list[index]->string; - MUTEX_UNLOCK(&internal_ips_lock); - return res; -} - -in_addr_t make_internal_ip(uint32_t index) { - ip_type ret; - index++; // so we can start at .0.0.1 - if(index > 0xFFFFFF) - return (in_addr_t) - 1; - ret.octet[0] = remote_dns_subnet & 0xFF; - ret.octet[1] = (index & 0xFF0000) >> 16; - ret.octet[2] = (index & 0xFF00) >> 8; - ret.octet[3] = index & 0xFF; - return (in_addr_t) ret.as_int; -} - // stolen from libulz (C) rofl0r void pc_stringfromipv4(unsigned char *ip_buf_4_bytes, char *outbuf_16_bytes) { unsigned char *p; @@ -262,6 +217,7 @@ static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) { #define INVALID_INDEX 0xFFFFFFFFU static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) { char *dns_name = NULL; + char hostnamebuf[MSG_LEN_MAX]; size_t dns_len = 0; PFUNC(); @@ -271,12 +227,9 @@ static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, c // 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(ip.octet[0] == remote_dns_subnet) { - dns_name = string_from_internal_ip(ip); - if(!dns_name) - goto err; - dns_len = strlen(dns_name); - if(!dns_len) - goto err; + dns_len = at_get_host_for_ip(ip, hostnamebuf); + if(!dns_len) goto err; + else dns_name = hostnamebuf; } PDEBUG("host dns %s\n", dns_name ? dns_name : ""); @@ -539,7 +492,6 @@ static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int p return NULL; switch (how) { case RANDOMLY: - srand(time(NULL)); do { k++; i = 0 + (unsigned int) (proxy_count * 1.0 * rand() / (RAND_MAX + 1.0)); @@ -590,14 +542,14 @@ static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) { static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) { int retcode = -1; char *hostname; + char hostname_buf[MSG_LEN_MAX]; char ip_buf[16]; PFUNC(); if(pto->ip.octet[0] == remote_dns_subnet) { - hostname = string_from_internal_ip(pto->ip); - if(!hostname) - goto usenumericip; + if(!at_get_host_for_ip(pto->ip, hostname_buf)) goto usenumericip; + else hostname = hostname_buf; } else { usenumericip: pc_stringfromipv4(&pto->ip.octet[0], ip_buf); @@ -740,8 +692,6 @@ int connect_proxy_chain(int sock, ip_type target_ip, return -1; } -static const ip_type local_host = { {127, 0, 0, 1} }; - static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) { snprintf(data->addr_name, sizeof(data->addr_name), "%s", name); data->hostent_space.h_name = data->addr_name; @@ -750,10 +700,7 @@ static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) { PFUNC(); 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 - void *new_mem; - size_t l; + size_t l = strlen(name); struct hostent *hp; @@ -773,7 +720,7 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* if(!strcmp(buff, name)) { data->resolved_addr = inet_addr(buff); if(data->resolved_addr == (in_addr_t) (-1)) - data->resolved_addr = (in_addr_t) (local_host.as_int); + data->resolved_addr = (in_addr_t) (ip_type_localhost.as_int); goto retname; } @@ -789,65 +736,9 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* } MUTEX_UNLOCK(&hostdb_lock); - hash = dalias_hash((char *) name); + data->resolved_addr = at_get_ip_for_host((char*) name, l).as_int; + if(data->resolved_addr == (in_addr_t) ip_type_invalid.as_int) return NULL; - MUTEX_LOCK(&internal_ips_lock); - - // see if we already have this dns entry saved. - 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)) { - data->resolved_addr = make_internal_ip(i); - PDEBUG("got cached ip for %s\n", name); - goto have_ip; - } - } - } - // grow list if needed. - if(internal_ips->capa < internal_ips->counter + 1) { - PDEBUG("realloc\n"); - new_mem = at_realloc(internal_ips->list, - internal_ips->capa * sizeof(void *), - (internal_ips->capa + 16) * sizeof(void *)); - if(new_mem) { - internal_ips->capa += 16; - internal_ips->list = new_mem; - } else { - oom: - proxychains_write_log("out of mem\n"); - goto err_plus_unlock; - } - } - - data->resolved_addr = make_internal_ip(internal_ips->counter); - if(data->resolved_addr == (in_addr_t) - 1) - goto err_plus_unlock; - - l = strlen(name); - string_hash_tuple tmp = { 0 }; - new_mem = at_dumpstring((char*) &tmp, sizeof(string_hash_tuple)); - if(!new_mem) - goto oom; - - PDEBUG("creating new entry %d for ip of %s\n", (int) internal_ips->counter, name); - - internal_ips->list[internal_ips->counter] = new_mem; - internal_ips->list[internal_ips->counter]->hash = hash; - - new_mem = at_dumpstring((char*) name, l + 1); - - if(!new_mem) { - internal_ips->list[internal_ips->counter] = 0; - goto oom; - } - internal_ips->list[internal_ips->counter]->string = new_mem; - - internal_ips->counter += 1; - - have_ip: - - MUTEX_UNLOCK(&internal_ips_lock); - retname: gethostbyname_data_setstring(data, (char*) name); @@ -855,11 +746,6 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* PDEBUG("return hostent space\n"); return &data->hostent_space; - - err_plus_unlock: - MUTEX_UNLOCK(&internal_ips_lock); - PDEBUG("return err\n"); - return NULL; } struct addrinfo_data { diff --git a/src/core.h b/src/core.h index 7ddd4cf..d6c088d 100644 --- a/src/core.h +++ b/src/core.h @@ -26,41 +26,11 @@ #define BUFF_SIZE 8*1024 // used to read responses from proxies. #define MAX_LOCALNET 64 -typedef union { - unsigned char octet[4]; - uint32_t as_int; -} ip_type; +#include "ip_type.h" -typedef struct { - uint32_t hash; - char* string; -} string_hash_tuple; - -struct mallocinfo { - void * addr; - size_t oldsz; - size_t newsz; -}; - -typedef struct { - uint32_t counter; - uint32_t capa; - struct mallocinfo mi; - string_hash_tuple** list; -} internal_ip_lookup_table; - -extern internal_ip_lookup_table *internal_ips; #ifdef THREAD_SAFE -#include -extern pthread_mutex_t internal_ips_lock; +#include "mutex.h" extern pthread_mutex_t hostdb_lock; -# define MUTEX_LOCK(x) pthread_mutex_lock(x) -# define MUTEX_UNLOCK(x) pthread_mutex_unlock(x) -# define MUTEX_INIT(x,y) pthread_mutex_init(x, y) -#else -# define MUTEX_LOCK(x) -# define MUTEX_UNLOCK(x) -# define MUTEX_INIT(x,y) #endif /*error codes*/ diff --git a/src/ip_type.c b/src/ip_type.c new file mode 100644 index 000000000..9a6f256 --- /dev/null +++ b/src/ip_type.c @@ -0,0 +1,5 @@ +#include "ip_type.h" + +const ip_type ip_type_invalid = { .as_int = -1 }; +const ip_type ip_type_localhost = { {127, 0, 0, 1} }; + diff --git a/src/ip_type.h b/src/ip_type.h new file mode 100644 index 000000000..62b915e --- /dev/null +++ b/src/ip_type.h @@ -0,0 +1,15 @@ +#ifndef IP_TYPE_H +#define IP_TYPE_H + +#include + +typedef union { + unsigned char octet[4]; + uint32_t as_int; +} ip_type; + +extern const ip_type ip_type_invalid; +extern const ip_type ip_type_localhost; + +//RcB: DEP "ip_type.c" +#endif diff --git a/src/libproxychains.c b/src/libproxychains.c index ed66121..37c1f88 100644 --- a/src/libproxychains.c +++ b/src/libproxychains.c @@ -96,12 +96,9 @@ static void* load_sym(char* symname, void* proxyfunc) { #include "allocator_thread.h" static void do_init(void) { - MUTEX_INIT(&internal_ips_lock, NULL); - MUTEX_INIT(&hostdb_lock, NULL); - internal_ips = shm_realloc(NULL, 0, sizeof(internal_ip_lookup_table)); - assert(internal_ips); - memset(internal_ips, 0, sizeof(internal_ip_lookup_table)); - at_init(&internal_ips->mi.addr, &internal_ips->mi.oldsz, &internal_ips->mi.newsz); + srand(time(NULL)); + MUTEX_INIT(&hostdb_lock); + at_init(); /* read the config file */ get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct); diff --git a/src/mutex.h b/src/mutex.h new file mode 100644 index 000000000..d41550e --- /dev/null +++ b/src/mutex.h @@ -0,0 +1,10 @@ +#ifndef MUTEX_H +#define MUTEX_H + +#include +# define MUTEX_LOCK(x) pthread_mutex_lock(x) +# define MUTEX_UNLOCK(x) pthread_mutex_unlock(x) +# define MUTEX_INIT(x) pthread_mutex_init(x, NULL) +# define MUTEX_DESTROY(x) pthread_mutex_destroy(x) + +#endif diff --git a/src/shm.c b/src/shm.c index 4d10aeb..d51470a 100644 --- a/src/shm.c +++ b/src/shm.c @@ -1,15 +1,19 @@ -#include #include #include -#include -#include #include +#include +#include #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif #include "shm.h" #include "debug.h" +#if 0 +#include +#include +#include + /* allocates shared memory which can be accessed from the parent and its childs */ void *shm_realloc(void* old, size_t old_size, size_t new_size) { //PFUNC(); @@ -22,6 +26,7 @@ void *shm_realloc(void* old, size_t old_size, size_t new_size) { } return nu; } +#endif void stringpool_init(struct stringpool* sp) { PFUNC(); @@ -34,7 +39,7 @@ char* stringpool_add(struct stringpool *sp, char* s, size_t len) { size_t newsz = sp->used + len; size_t inc = PAGE_SIZE - (newsz % PAGE_SIZE); newsz += (inc == PAGE_SIZE) ? 0 : inc; - void* p = shm_realloc(sp->start, sp->alloced, newsz); + void* p = realloc(sp->start, newsz); if(p) { sp->start = p; sp->alloced = newsz;