From 50ec7439e80bd6a77346dc6482895e481d8cd43a Mon Sep 17 00:00:00 2001 From: Antoine Catton <acatton@tiolive.com> Date: Tue, 10 Jan 2012 18:30:20 +0100 Subject: [PATCH] Switch to IPv6 --- libhttp/http.h | 4 ++-- libhttp/httpconnection.c | 11 ++++++++++- libhttp/server.c | 33 +++++++++++++++++++-------------- libhttp/server.h | 6 +++--- shellinabox/shellinaboxd.c | 14 +++++++------- 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/libhttp/http.h b/libhttp/http.h index e7840fa..5cd61e3 100644 --- a/libhttp/http.h +++ b/libhttp/http.h @@ -66,8 +66,8 @@ typedef struct ServerConnection ServerConnection; typedef struct Server Server; typedef struct URL URL; -Server *newCGIServer(int localhostOnly, int portMin, int portMax, int timeout); -Server *newServer(int localhostOnly, int port); +Server *newCGIServer(char *ipv6, int portMin, int portMax, int timeout); +Server *newServer(char *ipv6, int port); void deleteServer(Server *server); int serverGetListeningPort(Server *server); int serverGetFd(Server *server); diff --git a/libhttp/httpconnection.c b/libhttp/httpconnection.c index c8e69f6..cae467f 100644 --- a/libhttp/httpconnection.c +++ b/libhttp/httpconnection.c @@ -823,8 +823,17 @@ static int httpHandleCommand(struct HttpConnection *http, const char *host = getFromHashMap(&http->header, "host"); if (host) { + int brackets = 0; // For IPv6 hosts for (char ch; (ch = *host) != '\000'; host++) { - if (ch == ':') { + if (ch == '[') { + brackets = 1; + break; + } + if (ch == ']') { + brackets = 0; + break; + } + if (!brackets && ch == ':') { *(char *)host = '\000'; break; } diff --git a/libhttp/server.c b/libhttp/server.c index f52a269..2c30bd8 100644 --- a/libhttp/server.c +++ b/libhttp/server.c @@ -170,19 +170,19 @@ static int serverQuitHandler(struct HttpConnection *http, void *arg) { return HTTP_DONE; } -struct Server *newCGIServer(int localhostOnly, int portMin, int portMax, +struct Server *newCGIServer(char *ipv6, int portMin, int portMax, int timeout) { struct Server *server; check(server = malloc(sizeof(struct Server))); - initServer(server, localhostOnly, portMin, portMax, timeout); + initServer(server, ipv6, portMin, portMax, timeout); return server; } -struct Server *newServer(int localhostOnly, int port) { - return newCGIServer(localhostOnly, port, port, -1); +struct Server *newServer(char *ipv6, int port) { + return newCGIServer(ipv6, port, port, -1); } -void initServer(struct Server *server, int localhostOnly, int portMin, +void initServer(struct Server *server, char *ipv6, int portMin, int portMax, int timeout) { server->looping = 0; server->exitAll = 0; @@ -192,14 +192,19 @@ void initServer(struct Server *server, int localhostOnly, int portMin, server->numConnections = 0; int true = 1; - server->serverFd = socket(PF_INET, SOCK_STREAM, 0); + server->serverFd = socket(PF_INET6, SOCK_STREAM, 0); check(server->serverFd >= 0); check(!setsockopt(server->serverFd, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(true))); - struct sockaddr_in serverAddr = { 0 }; - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = htonl(localhostOnly - ? INADDR_LOOPBACK : INADDR_ANY); + struct sockaddr_in6 serverAddr = { 0 }; + serverAddr.sin6_family = AF_INET6; + if (ipv6 != NULL) { + if (!inet_pton(AF_INET6, ipv6, serverAddr.sin6_addr.s6_addr)) { + fatal("Bad ipv6 address"); + } + } else { + serverAddr.sin6_addr = in6addr_any; + } // Linux unlike BSD does not have support for picking a local port range. // So, we have to randomly pick a port from our allowed port range, and then @@ -214,14 +219,14 @@ void initServer(struct Server *server, int localhostOnly, int portMin, int portStart = rand() % (portMax - portMin + 1) + portMin; for (int p = 0; p <= portMax-portMin; p++) { int port = (p+portStart)%(portMax-portMin+1)+ portMin; - serverAddr.sin_port = htons(port); + serverAddr.sin6_port = htons(port); if (!bind(server->serverFd, (struct sockaddr *)&serverAddr, sizeof(serverAddr))) { break; } - serverAddr.sin_port = 0; + serverAddr.sin6_port = 0; } - if (!serverAddr.sin_port) { + if (!serverAddr.sin6_port) { fatal("Failed to find any available port"); } } @@ -231,7 +236,7 @@ void initServer(struct Server *server, int localhostOnly, int portMin, check(!getsockname(server->serverFd, (struct sockaddr *)&serverAddr, &socklen)); check(socklen == sizeof(serverAddr)); - server->port = ntohs(serverAddr.sin_port); + server->port = ntohs(serverAddr.sin6_port); info("Listening on port %d", server->port); check(server->pollFds = malloc(sizeof(struct pollfd))); diff --git a/libhttp/server.h b/libhttp/server.h index bb879fb..5ffb698 100644 --- a/libhttp/server.h +++ b/libhttp/server.h @@ -78,10 +78,10 @@ struct Server { struct SSLSupport ssl; }; -struct Server *newCGIServer(int localhostOnly, int portMin, int portMax, +struct Server *newCGIServer(char *ipv6, int portMin, int portMax, int timeout); -struct Server *newServer(int localhostOnly, int port); -void initServer(struct Server *server, int localhostOnly, int portMin, +struct Server *newServer(char *ipv6, int port); +void initServer(struct Server *server, char *ipv6, int portMin, int portMax, int timeout); void destroyServer(struct Server *server); void deleteServer(struct Server *server); diff --git a/shellinabox/shellinaboxd.c b/shellinabox/shellinaboxd.c index dcf05ff..2d1d758 100644 --- a/shellinabox/shellinaboxd.c +++ b/shellinabox/shellinaboxd.c @@ -80,7 +80,7 @@ static int port; static int portMin; static int portMax; -static int localhostOnly = 0; +static char *ipv6 = NULL; static int noBeep = 0; static int numericHosts = 0; static int enableSSL = 1; @@ -747,7 +747,7 @@ static void usage(void) { " -g, --group=GID switch to this group (default: %s)\n" " -h, --help print this message\n" " --linkify=[none|normal|agressive] default is \"normal\"\n" - " --localhost-only only listen on 127.0.0.1\n" + " --ipv6 listen on a specific ipv6\n" " --no-beep suppress all audio output\n" " -n, --numeric do not resolve hostnames\n" " -p, --port=PORT select a port (default: %d)\n" @@ -839,7 +839,7 @@ static void parseArgs(int argc, char * const argv[]) { { "static-file", 1, 0, 'f' }, { "group", 1, 0, 'g' }, { "linkify", 1, 0, 0 }, - { "localhost-only", 0, 0, 0 }, + { "ipv6", 1, 0, 0 }, { "no-beep", 0, 0, 0 }, { "numeric", 0, 0, 'n' }, { "port", 1, 0, 'p' }, @@ -1001,8 +1001,8 @@ static void parseArgs(int argc, char * const argv[]) { "\"none\", \"normal\", or \"aggressive\"."); } } else if (!idx--) { - // Localhost Only - localhostOnly = 1; + // IPv6 + ipv6 = optarg; } else if (!idx--) { // No Beep noBeep = 1; @@ -1197,7 +1197,7 @@ int main(int argc, char * const argv[]) { // Create a new web server Server *server; if (port) { - check(server = newServer(localhostOnly, port)); + check(server = newServer(ipv6, port)); dropPrivileges(); setUpSSL(server); } else { @@ -1217,7 +1217,7 @@ int main(int argc, char * const argv[]) { _exit(0); } check(!NOINTR(close(fds[0]))); - check(server = newCGIServer(localhostOnly, portMin, portMax, + check(server = newCGIServer(ipv6, portMin, portMax, AJAX_TIMEOUT)); cgiServer = server; setUpSSL(server); -- 1.7.6.5