Add IPv6 support for listening sockets
This commit is contained in:
parent
3370e83f55
commit
2456039df1
10
src/Makefile
10
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
|
||||
|
|
170
src/server.c
170
src/server.c
|
@ -25,6 +25,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
|
@ -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; i<s_nb_server_sockets; i++)
|
||||
shutdown(s_server_sockets[i], SHUT_RDWR);
|
||||
}
|
||||
|
||||
static int check_request(request_t* req)
|
||||
|
@ -400,53 +408,90 @@ static void fill_new_socket(struct gengetopt_args_info* params, int socket)
|
|||
|
||||
int daemonize(struct gengetopt_args_info* params)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_in sockaddr;
|
||||
int ret, i;
|
||||
struct sockaddr_in6 sockaddr;
|
||||
socklen_t sockaddr_len;
|
||||
int new_socket;
|
||||
void* thread_ret;
|
||||
|
||||
// Should have both ipv4 & ipv6
|
||||
s_server_socket = socket(AF_INET, SOCK_STREAM, 0); // Should have both TCP & UDP
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result, *rp;
|
||||
char buffer[64];
|
||||
int on;
|
||||
struct pollfd pollfds[MAX_LISTENING_SOCKETS];
|
||||
|
||||
if (!s_server_socket)
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
|
||||
hints.ai_flags = (params->bind_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; i<s_nb_server_sockets; i++)
|
||||
{
|
||||
if (pollfds[i].revents & POLL_ERR_MASK)
|
||||
{
|
||||
if (!s_stop)
|
||||
syslog(LOG_ERR, "Error with main socket %d (%m)", s_server_sockets[i]);
|
||||
close (s_server_sockets[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pollfds[i].revents & POLLIN)) continue;
|
||||
|
||||
sockaddr_len = sizeof(sockaddr);
|
||||
new_socket = accept(s_server_sockets[i], (struct sockaddr *) &sockaddr, &sockaddr_len);
|
||||
if (new_socket < 0)
|
||||
{
|
||||
if (!s_stop)
|
||||
syslog(LOG_ERR, "accept error (%m), exiting");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!params->quiet_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<s_nb_server_sockets; i++)
|
||||
close(s_server_sockets[i]);
|
||||
|
||||
while (s_last_thread)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user