From: Mats Erik Andersson Date: Wed, 26 May 2010 17:31:34 +0000 (+0200) Subject: Making the webserver IPv6 capable. X-Git-Tag: 3.0.714~91 X-Git-Url: https://unix4lyfe.org/gitweb/darkstat/commitdiff_plain/d0fabd45b8c905493257ed2eeaa2dc506de09ee1?ds=sidebyside Making the webserver IPv6 capable. Options like -b 0.0.0.0 -b 127.0.0.1 -b :: -b ::1 -b bug.me.local are now usable. --- diff --git a/darkstat.c b/darkstat.c index 6b393c7..ca28b94 100644 --- a/darkstat.c +++ b/darkstat.c @@ -22,6 +22,7 @@ #include "err.h" #include +#include #include #include #include @@ -98,12 +99,21 @@ static void cb_no_lastseen(const char *arg _unused_) { want_lastseen = 0; } unsigned short bindport = 667; static void cb_port(const char *arg) { bindport = parsenum(arg, 65536); } -in_addr_t bindaddr = INADDR_ANY; +char * bindaddr = NULL; static void cb_bindaddr(const char *arg) { - bindaddr = inet_addr(arg); - if (bindaddr == (in_addr_t)INADDR_NONE) + struct addrinfo hints, *ai; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(arg, NULL, &hints, &ai)) errx(1, "malformed address \"%s\"", arg); + + freeaddrinfo(ai); + bindaddr = strdup(arg); } const char *filter = NULL; diff --git a/http.c b/http.c index 1c40898..b9d8c58 100644 --- a/http.c +++ b/http.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -53,7 +55,7 @@ struct connection { LIST_ENTRY(connection) entries; int socket; - in_addr_t client; + struct sockaddr_storage client; time_t last_active; enum { RECV_REQUEST, /* receiving request */ @@ -257,7 +259,7 @@ static struct connection *new_connection(void) struct connection *conn = xmalloc(sizeof(*conn)); conn->socket = -1; - conn->client = INADDR_ANY; + memset(&conn->client, '\0', sizeof(conn->client)); conn->last_active = now; conn->request = NULL; conn->request_length = 0; @@ -295,12 +297,13 @@ static struct connection *new_connection(void) */ static void accept_connection(void) { - struct sockaddr_in addrin; + struct sockaddr_storage addrin; socklen_t sin_size; struct connection *conn; + char ipaddr[INET6_ADDRSTRLEN], portstr[12]; int sock; - sin_size = (socklen_t)sizeof(struct sockaddr); + sin_size = (socklen_t)sizeof(addrin); sock = accept(sockin, (struct sockaddr *)&addrin, &sin_size); if (sock == -1) { @@ -318,12 +321,13 @@ static void accept_connection(void) conn = new_connection(); conn->socket = sock; conn->state = RECV_REQUEST; - conn->client = addrin.sin_addr.s_addr; + memcpy(&conn->client, &addrin, sizeof(conn->client)); LIST_INSERT_HEAD(&connlist, conn, entries); - verbosef("accepted connection from %s:%u", - inet_ntoa(addrin.sin_addr), - ntohs(addrin.sin_port) ); + getnameinfo((struct sockaddr *) &addrin, sizeof(addrin), + ipaddr, sizeof(ipaddr), portstr, sizeof(portstr), + NI_NUMERICHOST | NI_NUMERICSERV); + verbosef("accepted connection from %s:%u", ipaddr, portstr); } @@ -858,36 +862,64 @@ static void poll_send_reply(struct connection *conn) * Initialize the sockin global. This is the socket that we accept * connections from. Pass -1 as max_conn for system limit. */ -void http_init(const in_addr_t bindaddr, const unsigned short bindport, +void http_init(const char *bindaddr, const unsigned short bindport, const int max_conn) { - struct sockaddr_in addrin; - int sockopt; - - /* create incoming socket */ - sockin = socket(PF_INET, SOCK_STREAM, 0); - if (sockin == -1) err(1, "socket()"); - - /* reuse address */ - sockopt = 1; - if (setsockopt(sockin, SOL_SOCKET, SO_REUSEADDR, - &sockopt, sizeof(sockopt)) == -1) - err(1, "setsockopt(SO_REUSEADDR)"); - - /* bind socket */ - addrin.sin_family = (u_char)PF_INET; - addrin.sin_port = htons(bindport); - addrin.sin_addr.s_addr = bindaddr; - memset(&(addrin.sin_zero), 0, 8); - if (bind(sockin, (struct sockaddr *)&addrin, - sizeof(struct sockaddr)) == -1) - err(1, "bind(%s:%u)", inet_ntoa(addrin.sin_addr), bindport); - - verbosef("listening on %s:%u", inet_ntoa(addrin.sin_addr), bindport); - - /* listen on socket */ - if (listen(sockin, max_conn) == -1) - err(1, "listen()"); + struct sockaddr_storage addrin; + struct addrinfo hints, *ai, *aiptr; + char ipaddr[INET6_ADDRSTRLEN], portstr[12]; + int sockopt, ret; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + snprintf(portstr, sizeof(portstr), "%u", bindport); + + if (ret = getaddrinfo(bindaddr, portstr, &hints, &aiptr)) + err(1, "getaddrinfo(): %s", gai_strerror(ret)); + + for (ai = aiptr; ai; ai = ai->ai_next) { + /* create incoming socket */ + sockin = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockin == -1) + continue; + + /* reuse address */ + sockopt = 1; + if (setsockopt(sockin, SOL_SOCKET, SO_REUSEADDR, + &sockopt, sizeof(sockopt)) == -1) { + close(sockin); + continue; + } + + /* Recover address and port strings. */ + getnameinfo(ai->ai_addr, ai->ai_addrlen, ipaddr, sizeof(ipaddr), + NULL, 0, NI_NUMERICHOST); + + /* bind socket */ + memcpy(&addrin, ai->ai_addr, ai->ai_addrlen); + if (bind(sockin, (struct sockaddr *)&addrin, + sizeof(addrin)) == -1) { + close(sockin); + continue; + } + + verbosef("listening on %s:%u", ipaddr, bindport); + + /* listen on socket */ + if (listen(sockin, max_conn) >= 0) + /* Successfully bound and now listening. */ + break; + + /* Next candidate. */ + continue; + } + + freeaddrinfo(aiptr); + + if (ai == NULL) + err(1, "getaddrinfo() unable to locate address"); /* ignore SIGPIPE */ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) @@ -918,11 +950,11 @@ http_fd_set(fd_set *recv_set, fd_set *send_set, int *max_fd, /* Time out dead connections. */ if (idlefor >= idletime) { - struct sockaddr_in addrin; - addrin.sin_addr.s_addr = conn->client; + char ipaddr[INET6_ADDRSTRLEN]; + getnameinfo((struct sockaddr *) &conn->client, sizeof(conn->client), + ipaddr, sizeof(ipaddr), NULL, 0, NI_NUMERICHOST); verbosef("http socket timeout from %s (fd %d)", - inet_ntoa(addrin.sin_addr), - conn->socket); + ipaddr, conn->socket); conn->state = DONE; } diff --git a/http.h b/http.h index 01d9405..f366d5b 100644 --- a/http.h +++ b/http.h @@ -8,7 +8,7 @@ #include #include -void http_init(const in_addr_t bindaddr, const unsigned short bindport, +void http_init(const char * bindaddr, const unsigned short bindport, const int max_conn); void http_fd_set(fd_set *recv_set, fd_set *send_set, int *max_fd, struct timeval *timeout, int *need_timeout);