diff --git a/client.c b/client.c index fa2e24b..4ee8342 100644 --- a/client.c +++ b/client.c @@ -60,18 +60,18 @@ client_t *client_new(int fd, host_t *src, host_t *dst) { void client_close(client_t *client) { client_del(client); close(client->socket); - free(client->src); - free(client->dst); + host_clean(client->src); + host_clean(client->dst); free(client); } -void client_clean() { +void client_clean(int asap) { uint32_t now = (long)time(0); uint32_t diff; client_t *current; client_iter(clients, current) { diff = now - current->lastseen; - if(diff >= MAXAGE) { + if(diff >= MAXAGE || asap) { if(VERBOSE) { fprintf(stderr, "closing socket %s:%d for client %s:%d (aged out after %d seconds)\n", current->src->ip, current->src->port, current->dst->ip, current->dst->port, MAXAGE); diff --git a/client.h b/client.h index 105a439..3158ff6 100644 --- a/client.h +++ b/client.h @@ -48,7 +48,6 @@ struct _client_t { host_t *src; /* client src (ip+port) from incoming socket */ host_t *dst; /* client dst (ip+port) to outgoing socket */ uint64_t lastseen; /* when did we recv last time from it */ - size_t size; /* sockaddr size */ UT_hash_handle hh; }; typedef struct _client_t client_t; @@ -77,7 +76,7 @@ void client_del(client_t *client); void client_add(client_t *client); void client_seen(client_t *client); void client_close(client_t *client); -void client_clean(); +void client_clean(int asap); client_t *client_find_fd(int fd); client_t *client_find_src(host_t *src); diff --git a/host.c b/host.c index b111381..1f50772 100644 --- a/host.c +++ b/host.c @@ -49,6 +49,8 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 host->is_v6 = 1; host->sock = (struct sockaddr*)tmp; host->size = sizeof(struct sockaddr_in6); + host->ip = malloc(INET6_ADDRSTRLEN+1); + memcpy(host->ip, ip, INET6_ADDRSTRLEN); } else { struct sockaddr_in *tmp = malloc(sizeof(struct sockaddr_in)); @@ -58,6 +60,8 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 tmp->sin_port = htons( port ); host->sock = (struct sockaddr*)tmp; host->size = sizeof(struct sockaddr_in); + host->ip = malloc(INET_ADDRSTRLEN+1); + memcpy(host->ip, ip, INET_ADDRSTRLEN); } } else if(v4 != NULL) { @@ -68,6 +72,7 @@ host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 host->port = ntohs(tmp->sin_port); host->sock = (struct sockaddr*)tmp; host->size = sizeof(struct sockaddr_in); + //fprintf(stderr, "%s sock: %p\n", host->ip, tmp); } else if(v6 != NULL) { struct sockaddr_in6 *tmp = malloc(sizeof(struct sockaddr_in6)); @@ -130,3 +135,17 @@ unsigned get_v6_scope(const char *ip){ int is_linklocal(struct in6_addr *a) { return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80)); } + +void host_dump(host_t *host) { + fprintf(stderr, "host - ip: %s\n", host->ip); + fprintf(stderr, " port: %d\n", host->port); + fprintf(stderr, " isv6: %d\n", host->is_v6); + fprintf(stderr, " size: %ld\n", host->size); + fprintf(stderr, " src: %p\n", host->sock); +} + +void host_clean(host_t *host) { + free(host->sock); + free(host->ip); + free(host); +} diff --git a/host.h b/host.h index 0241f51..91c44c0 100644 --- a/host.h +++ b/host.h @@ -50,5 +50,7 @@ unsigned get_v6_scope(const char *ip); int is_linklocal(struct in6_addr *a); host_t *get_host(char *ip, int port, struct sockaddr_in *v4, struct sockaddr_in6 *v6); char *is_v6(char *ip); +void host_dump(host_t *host); +void host_clean(host_t *host); #endif diff --git a/net.c b/net.c index a5b8bea..e698080 100644 --- a/net.c +++ b/net.c @@ -102,6 +102,7 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstp bind_h = get_host("0.0.0.0", 0, NULL, NULL); } + int listen = bindsocket(listen_h); if(listen == -1) @@ -118,13 +119,14 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstp main_loop(listen, listen_h, bind_h, dst_h); + host_clean(bind_h); + host_clean(listen_h); + host_clean(dst_h); + return 0; } -/* handle new or known incoming requests - FIXME: check client handling: - http://long.ccaba.upc.es/long/045Guidelines/eva/ipv6.html#daytimeServer6 -*/ +/* handle new or known incoming requests */ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h) { int len; unsigned char buffer[MAX_BUFFER_SIZE]; @@ -144,6 +146,8 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h) else src_h = get_host(NULL, 0, (struct sockaddr_in *)src, NULL); + free(src); + if(VERBOSE) { fprintf(stderr, "New incomming request from %s:%d with %d bytes\n", src_h->ip, src_h->port, len); @@ -155,7 +159,7 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h) if(client != NULL) { /* yes, we know it, send req out via existing bind socket */ if(VERBOSE) { - fprintf(stderr, "Client %s:%d is known, forwarding data to %s:%d\n", + fprintf(stderr, "Client %s:%d is known, forwarding data to %s:%d ", src_h->ip, src_h->port, dst_h->ip, dst_h->port); } @@ -189,12 +193,14 @@ void handle_inside(int inside, host_t *listen_h, host_t *bind_h, host_t *dst_h) struct sockaddr_in6 *ret = malloc(size); getsockname(output, (struct sockaddr*)ret, (socklen_t *)&size); ret_h = get_host(NULL, 0, NULL, ret); + free(ret); client = client_new(output, src_h, ret_h); } else { struct sockaddr_in *ret = malloc(size); getsockname(output, (struct sockaddr*)ret, (socklen_t *)&size); ret_h = get_host(NULL, 0, ret, NULL); + free(ret); client = client_new(output, src_h, ret_h); } @@ -226,47 +232,81 @@ void handle_outside(int inside, int outside, host_t *outside_h) { src = malloc(size); len = recvfrom( outside, buffer, sizeof( buffer ), 0, (struct sockaddr*)src, (socklen_t *)&size ); + free(src); if(len > 0) { /* do we know it? */ client = client_find_fd(outside); if(client != NULL) { /* yes, we know it */ - if(sendto(inside, buffer, len, 0, (struct sockaddr*)client->src, client->size) < 0) { + /* FIXME: check src vs. client->src ? */ + if(sendto(inside, buffer, len, 0, + (struct sockaddr*)client->src->sock, client->src->size) < 0) { perror("unable to send back to client"); /* FIXME: add src+port */ client_close(client); } } + else { + fprintf(stderr, "weird, no matching client found!\n"); + } + } + else { + fprintf(stderr, "weird, recvfrom returned 0 bytes!\n"); } } +jmp_buf JumpBuffer; + /* runs forever, handles incoming requests on the inside and answers on the outside */ int main_loop(int listensocket, host_t *listen_h, host_t *bind_h, host_t *dst_h) { - int max, sender; - fd_set fds; + int max, sender; + fd_set fds; - for(;;) { - FD_ZERO(&fds); - max = fill_set(&fds); + signal(SIGINT, int_handler); + signal(SIGTERM, int_handler); - FD_SET(listensocket, &fds); - if (listensocket > max) - max = listensocket; - - select(max + 1, &fds, NULL, NULL, NULL); - - if (FD_ISSET(listensocket, &fds)) { - /* incoming client on the inside, get src, bind output fd, add to list - if known, otherwise just handle it */ - handle_inside(listensocket, listen_h, bind_h, dst_h); - } - else { - /* remote answer came in on an output fd, proxy back to the inside */ - sender = get_sender(&fds); - handle_outside(listensocket, sender, dst_h); - } - - /* close old outputs, if any */ - client_clean(); + for(;;) { + if (setjmp(JumpBuffer) == 1) { + break; } + + FD_ZERO(&fds); + max = fill_set(&fds); + + FD_SET(listensocket, &fds); + if (listensocket > max) + max = listensocket; + + select(max + 1, &fds, NULL, NULL, NULL); + + if (FD_ISSET(listensocket, &fds)) { + /* incoming client on the inside, get src, bind output fd, add to list + if known, otherwise just handle it */ + handle_inside(listensocket, listen_h, bind_h, dst_h); + } + else { + /* remote answer came in on an output fd, proxy back to the inside */ + sender = get_sender(&fds); + handle_outside(listensocket, sender, dst_h); + } + + /* close old outputs, if any */ + client_clean(0); + } + + /* we came here via signal handler, + clean up */ + client_t *current = NULL; + client_iter(clients, current) { + close(current->socket); + } + close(listensocket); + client_clean(1); + + return 0; +} + +void int_handler(int sig) { + signal(sig, SIG_IGN); + longjmp(JumpBuffer, 1); } diff --git a/net.h b/net.h index d23e117..b4bc21a 100644 --- a/net.h +++ b/net.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -54,7 +56,7 @@ int start_listener (char *inip, char *inpt, char *srcip, char *dstip, char *dstp int fill_set(fd_set *fds); int get_sender(fd_set *fds); int bindsocket( host_t *sock_h); - +void int_handler(int sig); #define _IS_LINK_LOCAL(a) do { IN6_IS_ADDR_LINKLOCAL(a); } while(0)