From 7d35683707b627fbfee14620a3cb90d577c0f0d0 Mon Sep 17 00:00:00 2001 From: Henrich Hartzer Date: Wed, 28 Feb 2024 19:33:22 +0000 Subject: [PATCH] Listen to IPv4 and IPv6 at the same time when --ipv6 is passed This could have already been the default behavior on your OS, but now it will be consistently utilized. Prior to this, to support IPv4 and IPv6 you would have to run two servers or set the relevant sysctl. Also fixes incorrect inet_pton() usage. Closes: #37 --- darkhttpd.c | 16 ++++++++++++++-- devel/run-tests | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/darkhttpd.c b/darkhttpd.c index 4a22ae2..cd16708 100644 --- a/darkhttpd.c +++ b/darkhttpd.c @@ -794,7 +794,7 @@ static const char *get_address_text(const void *addr) { } } -/* Initialize the sockin global. This is the socket that we accept +/* Initialize the sockin global. This is the socket that we accept * connections from. */ static void init_sockin(void) { @@ -809,7 +809,7 @@ static void init_sockin(void) { if (inet6) { memset(&addrin6, 0, sizeof(addrin6)); if (inet_pton(AF_INET6, bindaddr ? bindaddr : "::", - &addrin6.sin6_addr) == -1) { + &addrin6.sin6_addr) != 1) { errx(1, "malformed --addr argument"); } sockin = socket(PF_INET6, SOCK_STREAM, 0); @@ -838,6 +838,18 @@ static void init_sockin(void) { &sockopt, sizeof(sockopt)) == -1) err(1, "setsockopt(TCP_NODELAY)"); +#ifdef HAVE_INET6 + if (inet6) { + /* Listen on IPv4 and IPv6 on the same socket. */ + /* Only relevant if listening on ::, but behaves normally if */ + /* listening on a specific address. */ + sockopt = 0; + if (setsockopt(sockin, IPPROTO_IPV6, IPV6_V6ONLY, + &sockopt, sizeof (sockopt)) < 0) + err(1, "setsockopt (IPV6_V6ONLY)"); + } +#endif + #ifdef TORTURE /* torture: cripple the kernel-side send buffer so we can only squeeze out * one byte at a time (this is for debugging) diff --git a/devel/run-tests b/devel/run-tests index 5cc6e40..412c549 100755 --- a/devel/run-tests +++ b/devel/run-tests @@ -44,6 +44,20 @@ runtests() { # Early exit if we can't even survive usage. ./a.out >/dev/null 2>>test.out.stderr || exit 1 + echo "===> run test for binding to bogus address (IPv4)" + # Should exit immediately. + # Error is "Can't assign requested adddress" on FreeBSD and "Cannot assign requested address" on Linux. + ./a.out $DIR --port $PORT --addr 8.8.8.8 2>&1 | grep -F "t assign requested address" > /dev/null || exit 1 + + echo "===> run test for binding to bogus address (IPv6)" + # Should exit immediately. + # Error is "Can't assign requested adddress" on FreeBSD and "Cannot assign requested address" on Linux. + ./a.out $DIR --port $PORT --ipv6 --addr ::8888 2>&1 | grep -F "t assign requested address" > /dev/null || exit 1 + + echo "===> run test for binding to IPv4 when IPv6 requested" + # Should exit immediately. + ./a.out $DIR --port $PORT --ipv6 --addr 127.0.0.1 2>&1 | grep -F "malformed --addr argument" > /dev/null || exit 1 + echo "===> run tests against a basic instance (generates darkhttpd.gcda)" ./a.out $DIR --port $PORT --log test.out.log \ >>test.out.stdout 2>>test.out.stderr &