From 2456039df1ee518705bdeec8a7157b1257bc2011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Wed, 17 Feb 2016 18:15:04 +0100 Subject: [PATCH] Add IPv6 support for listening sockets --- src/Makefile | 10 +-- src/server.c | 170 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 132 insertions(+), 48 deletions(-) diff --git a/src/Makefile b/src/Makefile index 95fd6b9..adfced0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,9 +1,9 @@ -BIN_DIR=../bin -SRCS = ip_to_geo.c test.c cmdline.c server.c -TARGET = $(BIN_DIR)/ip_to_geo -CFLAGS = -Wall -LDFLAGS= -lpthread +BIN_DIR =../bin +SRCS = ip_to_geo.c test.c cmdline.c server.c +TARGET = $(BIN_DIR)/ip_to_geo +CFLAGS = -Wall +LDFLAGS = -lpthread ifneq ($(DEBUG),) CFLAGS += -ggdb -O0 diff --git a/src/server.c b/src/server.c index f838142..9e39764 100644 --- a/src/server.c +++ b/src/server.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ #define WAIT_TIME 100 #define MAX_WAIT_TIME 500 +#define MAX_LISTENING_SOCKETS 16 + typedef struct { int socket; time_t timeout; // in µs @@ -69,14 +72,19 @@ typedef struct thread_ctx_s{ static pthread_mutex_t s_fastmutex = PTHREAD_MUTEX_INITIALIZER; static thread_ctx_t* s_last_thread = NULL; -static int s_server_socket = -1; +static int s_server_sockets[MAX_LISTENING_SOCKETS]; +static int s_nb_server_sockets = 0; static int s_stop = 0; void sigint(int sig) { + int i; + syslog(LOG_WARNING, "signal received, stopping threads"); s_stop = 1; - shutdown(s_server_socket, SHUT_RDWR); + + for (i=0; ibind_ip_given)?0:AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + + snprintf(buffer, sizeof(buffer), "%d", params->port_arg); + + ret = getaddrinfo(params->bind_ip_arg, buffer, &hints, &result); + if (ret) { - if (!params->quiet_flag) - fprintf(stderr, "Unable to create socket (%m)\n"); + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); return -1; } - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; // Should detect interface type (v4 or v6) - sockaddr.sin_port = htons(params->port_arg); - if (params->bind_ip_given) + for (rp=result; rp && s_nb_server_sockets < MAX_LISTENING_SOCKETS; + rp=rp->ai_next, s_nb_server_sockets++) { - ret = inet_aton(params->bind_ip_arg, &sockaddr.sin_addr); + new_socket = socket(rp->ai_family, + rp->ai_socktype, + rp->ai_protocol); // Should have both TCP & UDP + + if (!new_socket) + { + if (!params->quiet_flag) + fprintf(stderr, "Unable to create socket (%m)\n"); + return -1; + } + + s_server_sockets[s_nb_server_sockets] = new_socket; + pollfds[s_nb_server_sockets].fd = new_socket; + pollfds[s_nb_server_sockets].events = POLLIN|POLL_ERR_MASK; + + on=1; setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (rp->ai_family == AF_INET6) + { + on=1; setsockopt(new_socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + } + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = rp->ai_family; // Should detect interface type (v4 or v6) + sockaddr.sin6_port = htons(params->port_arg); + if (params->bind_ip_given) + { + ret = inet_pton(rp->ai_family, params->bind_ip_arg, &sockaddr.sin6_addr); + if (ret) + { + if (!params->quiet_flag) + fprintf(stderr, "Error with bind address %s (%m)\n", params->bind_ip_arg); + return -1; + } + } + else + sockaddr.sin6_addr = in6addr_any; + + ret = bind(new_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret) { if (!params->quiet_flag) - fprintf(stderr, "Error with bind address %s (%m)\n", params->bind_ip_arg); - return -1; + fprintf(stderr, "Unable to bind (%m)\n"); + return -2; + } + + ret = listen(new_socket, 0); + if (ret) + { + if (!params->quiet_flag) + fprintf(stderr, "Unable to listen (%m)\n"); + return -3; } } - else - sockaddr.sin_addr.s_addr = INADDR_ANY; - ret = bind(s_server_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); - if (ret) - { - if (!params->quiet_flag) - fprintf(stderr, "Unable to bind (%m)\n"); - return -2; - } - - ret = listen(s_server_socket, 0); - if (ret) - { - if (!params->quiet_flag) - fprintf(stderr, "Unable to listen (%m)\n"); - return -3; - } + if (rp) + fprintf(stderr, "Warning, max listening sockets reached !!\n"); if (!params->no_background_flag) { @@ -497,6 +542,7 @@ int daemonize(struct gengetopt_args_info* params) seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0); seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); + seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); seccomp_rule_add(seccomp_ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0); @@ -513,21 +559,59 @@ int daemonize(struct gengetopt_args_info* params) while (!s_stop) { - sockaddr_len = sizeof(sockaddr); - new_socket = accept(s_server_socket, (struct sockaddr *) &sockaddr, &sockaddr_len); - if (new_socket < 0) + ret = poll(pollfds, s_nb_server_sockets, 1000); + + if (ret < 0) { if (!s_stop) - syslog(LOG_ERR, "accept error (%m), exiting"); + syslog(LOG_ERR, "main poll err %d", ret); break; } - if (!params->quiet_flag) - syslog(LOG_INFO, "new connection from %s, socket %d", - inet_ntoa(sockaddr.sin_addr), new_socket); - fill_new_socket(params, new_socket); + + if (ret == 0) continue; // timeout + + for (i=0; iquiet_flag) + { + switch(sockaddr.sin6_family) + { + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in *)&sockaddr)->sin_addr, buffer, sizeof(buffer)); + break; + case AF_INET6: + inet_ntop(AF_INET6, &sockaddr.sin6_addr, buffer, sizeof(buffer)); + break; + } + /* inet_ntop(sockaddr.sin6_family, &sockaddr.sin6_addr, buffer, sockaddr_len); */ + syslog(LOG_INFO, "new connection from %s, socket %d", buffer, new_socket); + } + fill_new_socket(params, new_socket); + } } - close(s_server_socket); +end: + for (i=0; i