diff --git a/darkhttpd.c b/darkhttpd.c index a29a45a..c53ae8e 100644 --- a/darkhttpd.c +++ b/darkhttpd.c @@ -204,7 +204,11 @@ struct connection { LIST_ENTRY(connection) entries; int socket; +#ifdef HAVE_INET6 + struct in6_addr client; +#else in_addr_t client; +#endif time_t last_active; enum { RECV_REQUEST, /* receiving request */ @@ -268,13 +272,14 @@ static time_t now; #define MAX_REQUEST_LENGTH 4000 /* Defaults can be overridden on the command-line */ -static in_addr_t bindaddr = INADDR_ANY; +static const char *bindaddr; static uint16_t bindport = 8080; /* or 80 if running as root */ static int max_connections = -1; /* kern.ipc.somaxconn */ static const char *index_name = "index.html"; static int no_listing = 0; static int sockin = -1; /* socket to accept connections from */ +static int inet6 = 0; /* whether the socket uses inet6 */ static char *wwwroot = NULL; /* a path name */ static char *logfile_name = NULL; /* NULL = no logging */ static FILE *logfile = NULL; @@ -796,16 +801,47 @@ static const char *url_content_type(const char *url) { return default_mimetype; } +static const char *get_address_text(const void *addr) { + if (inet6) { +#ifdef HAVE_INET6 + static char text_addr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, (struct in6_addr *)addr, text_addr, + INET6_ADDRSTRLEN); + return text_addr; +#endif + } else { + return inet_ntoa(*(struct in_addr *)addr); + } +} + /* Initialize the sockin global. This is the socket that we accept * connections from. */ static void init_sockin(void) { struct sockaddr_in addrin; +#ifdef HAVE_INET6 + struct sockaddr_in6 addrin6; +#endif socklen_t addrin_len; int sockopt; - /* create incoming socket */ - sockin = socket(PF_INET, SOCK_STREAM, 0); + if (inet6) { +#ifdef HAVE_INET6 + memset(&addrin6, 0, sizeof(addrin6)); + if (inet_pton(AF_INET6, bindaddr ? bindaddr : "::", + &addrin6.sin6_addr) == -1) { + errx(1, "malformed --addr argument"); + } + sockin = socket(PF_INET6, SOCK_STREAM, 0); +#endif + } else { + memset(&addrin, 0, sizeof(addrin)); + addrin.sin_addr.s_addr = bindaddr ? inet_addr(bindaddr) : INADDR_ANY; + if (addrin.sin_addr.s_addr == (in_addr_t)INADDR_NONE) + errx(1, "malformed --addr argument"); + sockin = socket(PF_INET, SOCK_STREAM, 0); + } + if (sockin == -1) err(1, "socket()"); @@ -834,20 +870,38 @@ static void init_sockin(void) { #endif /* 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(port %u)", bindport); + if (inet6) { +#ifdef HAVE_INET6 + addrin6.sin6_family = AF_INET6; + addrin6.sin6_port = htons(bindport); + if (bind(sockin, (struct sockaddr *)&addrin6, + sizeof(struct sockaddr_in6)) == -1) + err(1, "bind(port %u)", bindport); + + addrin_len = sizeof(addrin6); +#endif + } else { + addrin.sin_family = (u_char)PF_INET; + addrin.sin_port = htons(bindport); + if (bind(sockin, (struct sockaddr *)&addrin, + sizeof(struct sockaddr_in)) == -1) + err(1, "bind(port %u)", bindport); + + addrin_len = sizeof(addrin); + } - addrin_len = sizeof(addrin); if (getsockname(sockin, (struct sockaddr *)&addrin, &addrin_len) == -1) err(1, "getsockname()"); - printf("listening on: http://%s:%u/\n", - inet_ntoa(addrin.sin_addr), ntohs(addrin.sin_port)); + if (inet6) { +#ifdef HAVE_INET6 + printf("listening on: http://[%s]:%u/\n", + get_address_text(&addrin6.sin6_addr), bindport); +#endif + } else { + printf("listening on: http://%s:%u/\n", + get_address_text(&addrin.sin_addr), bindport); + } /* listen on socket */ if (listen(sockin, max_connections) == -1) @@ -918,6 +972,10 @@ static void usage(const char *argv0) { printf("\t--no-server-id\n" "\t\tDon't identify the server type in headers\n" "\t\tor directory listings.\n"); +#ifdef HAVE_INET6 + printf("\t--ipv6\n" + "\t\tListen on IPv6 address.\n"); +#endif } /* Returns 1 if string is a number, 0 otherwise. Set num to NULL if @@ -979,9 +1037,7 @@ static void parse_commandline(const int argc, char *argv[]) { else if (strcmp(argv[i], "--addr") == 0) { if (++i >= argc) errx(1, "missing ip after --addr"); - bindaddr = inet_addr(argv[i]); - if (bindaddr == (in_addr_t)INADDR_NONE) - errx(1, "malformed --addr argument"); + bindaddr = argv[i]; } else if (strcmp(argv[i], "--maxconn") == 0) { if (++i >= argc) @@ -1071,6 +1127,11 @@ static void parse_commandline(const int argc, char *argv[]) { else if (strcmp(argv[i], "--no-server-id") == 0) { want_server_id = 0; } +#ifdef HAVE_INET6 + else if (strcmp(argv[i], "--ipv6") == 0) { + inet6 = 1; + } +#endif else errx(1, "unknown argument `%s'", argv[i]); } @@ -1081,7 +1142,7 @@ static struct connection *new_connection(void) { struct connection *conn = xmalloc(sizeof(struct connection)); 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; @@ -1119,22 +1180,41 @@ static struct connection *new_connection(void) { /* Accept a connection from sockin and add it to the connection queue. */ static void accept_connection(void) { struct sockaddr_in addrin; +#ifdef HAVE_INET6 + struct sockaddr_in6 addrin6; +#endif socklen_t sin_size; struct connection *conn; /* allocate and initialise struct connection */ conn = new_connection(); - sin_size = sizeof(addrin); - memset(&addrin, 0, sin_size); - conn->socket = accept(sockin, (struct sockaddr *)&addrin, &sin_size); + if (inet6) { +#ifdef HAVE_INET6 + sin_size = sizeof(addrin6); + memset(&addrin6, 0, sin_size); + conn->socket = accept(sockin, (struct sockaddr *)&addrin6, &sin_size); +#endif + } else { + sin_size = sizeof(addrin); + memset(&addrin, 0, sin_size); + conn->socket = accept(sockin, (struct sockaddr *)&addrin, &sin_size); + } + if (conn->socket == -1) err(1, "accept()"); nonblock_socket(conn->socket); conn->state = RECV_REQUEST; - conn->client = addrin.sin_addr.s_addr; + + if (inet6) { +#ifdef HAVE_INET6 + conn->client = addrin6.sin6_addr; +#endif + } else { + *(in_addr_t *)&conn->client = addrin.sin_addr.s_addr; + } LIST_INSERT_HEAD(&connlist, conn, entries); if (debug) @@ -1173,7 +1253,6 @@ static void logencode(const char *src, char *dest) { /* Add a connection's details to the logfile. */ static void log_connection(const struct connection *conn) { - struct in_addr inaddr; char *safe_method, *safe_url, *safe_referer, *safe_user_agent; if (logfile == NULL) @@ -1183,8 +1262,6 @@ static void log_connection(const struct connection *conn) { if (conn->method == NULL) return; /* invalid - didn't parse - maybe too long */ - inaddr.s_addr = conn->client; - #define make_safe(x) \ if (conn->x) { \ safe_##x = xmalloc(strlen(conn->x)*3 + 1); \ @@ -1202,7 +1279,7 @@ static void log_connection(const struct connection *conn) { fprintf(logfile, "%lu %s \"%s %s\" %d %llu \"%s\" \"%s\"\n", (unsigned long int)now, - inet_ntoa(inaddr), + get_address_text(&conn->client), use_safe(method), use_safe(url), conn->http_code, @@ -1393,7 +1470,7 @@ static void default_reply(struct connection *conn, "Accept-Ranges: bytes\r\n" "%s" /* keep-alive */ "Content-Length: %llu\r\n" - "Content-Type: text/html\r\n" + "Content-Type: text/html; charset=utf-8\r\n" "\r\n", errcode, errname, date, server_hdr, keep_alive(conn), llu(conn->reply_length)); @@ -1432,7 +1509,7 @@ static void redirect(struct connection *conn, const char *format, ...) { "Location: %s\r\n" "%s" /* keep-alive */ "Content-Length: %llu\r\n" - "Content-Type: text/html\r\n" + "Content-Type: text/html; charset=utf-8\r\n" "\r\n", date, server_hdr, where, keep_alive(conn), llu(conn->reply_length)); @@ -1787,7 +1864,7 @@ static void generate_dir_listing(struct connection *conn, const char *path) { "Accept-Ranges: bytes\r\n" "%s" /* keep-alive */ "Content-Length: %llu\r\n" - "Content-Type: text/html\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" "\r\n", date, server_hdr, keep_alive(conn), llu(conn->reply_length));