Actually, it wasn't much more work to get all the failing tests to
pass.  Version 2 of the patches attached.

J.

From 1f6b8e55807794c2466603116ae8ba9e6a50919a Mon Sep 17 00:00:00 2001
From: Jeremy Sowden <jer...@azazel.net>
Date: Sun, 26 Mar 2023 14:49:09 +0100
Subject: [PATCH v2 1/2] Use ipv6 lookback address if ipv4 is not available

Note that the `bind_local` parameter of `spawn_server_addr` is now
ignored.  It wasn't actually possible to set `hn_addr`, so passing `0`
would never have worked anyway.
---
 test/common/child.c | 160 +++++++++++++++++++++++++++++++++++++-------
 test/common/child.h |   4 ++
 test/utils.c        |   5 +-
 3 files changed, 143 insertions(+), 26 deletions(-)

diff --git a/test/common/child.c b/test/common/child.c
index 872fbdaddf4f..5c480def6c44 100644
--- a/test/common/child.c
+++ b/test/common/child.c
@@ -43,6 +43,10 @@
 #include <netdb.h>
 #include <signal.h>
 
+#include <ifaddrs.h>
+#include <sys/types.h>
+#include <string.h>
+
 #include "ne_socket.h"
 #include "ne_utils.h"
 #include "ne_string.h"
@@ -50,14 +54,23 @@
 #include "tests.h"
 #include "child.h"
 
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+
 static pid_t child = 0;
 
 int clength;
 
-static struct in_addr lh_addr, hn_addr;
-
 static int have_lh_addr;
 
+static union {
+	struct sockaddr_in  in;
+	struct sockaddr_in6 in6;
+} lh_sockaddr;
+static int  lh_family = AF_UNSPEC;
+static char lh_name[NI_MAXHOST];
+
 const char *want_header = NULL;
 got_header_fn got_header = NULL;
 char *local_hostname = NULL;
@@ -72,13 +85,98 @@ char *local_hostname = NULL;
 
 int lookup_localhost(void)
 {
-    /* this will break if a system is set up so that `localhost' does
-     * not resolve to 127.0.0.1, but... */
-    lh_addr.s_addr = inet_addr("127.0.0.1");
+    struct ifaddrs *ifaddr;
+
+    if (have_lh_addr)
+        return OK;
+
+    if (getifaddrs(&ifaddr) == -1)
+        goto err_use_ipv4;
+
+    for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr == NULL)
+            continue;
+
+        if (strcmp(ifa->ifa_name, "lo") != 0)
+            continue;
+
+        if (ifa->ifa_addr->sa_family != AF_INET &&
+            ifa->ifa_addr->sa_family != AF_INET6)
+            continue;
+
+        if (getnameinfo(ifa->ifa_addr,
+                        ifa->ifa_addr->sa_family == AF_INET
+                            ? sizeof(struct sockaddr_in)
+                            : sizeof(struct sockaddr_in6),
+                        lh_name, sizeof lh_name,
+                        NULL, 0,
+                        NI_NUMERICHOST))
+            continue;
+
+        memcpy(&lh_sockaddr, ifa->ifa_addr,
+               ifa->ifa_addr->sa_family == AF_INET
+                   ? sizeof(lh_sockaddr.in)
+                   : sizeof(lh_sockaddr.in6));
+
+        lh_family = ifa->ifa_addr->sa_family;
+
+        if (lh_family == AF_INET)
+            break;
+    }
+
+    freeifaddrs(ifaddr);
+
+err_use_ipv4:
+
+    if (lh_family == AF_UNSPEC) {
+        lh_family = AF_INET;
+        strcpy(lh_name, "127.0.0.1");
+        lh_sockaddr.in.sin_family = lh_family;
+        lh_sockaddr.in.sin_addr.s_addr = inet_addr(lh_name);
+    }
+
     have_lh_addr = 1;
     return OK;
 }
 
+int
+get_lh_family(void)
+{
+    if (!have_lh_addr)
+        lookup_localhost();
+
+    return lh_family;
+}
+
+const char *
+get_lh_addr(void)
+{
+    if (!have_lh_addr)
+        lookup_localhost();
+
+    return lh_name;
+}
+
+ne_inet_addr *
+get_lh_inet_addr(void)
+{
+    ne_iaddr_type type;
+    unsigned char *raw;
+
+    if (!have_lh_addr)
+        lookup_localhost();
+
+    if (lh_family == AF_INET) {
+        type = ne_iaddr_ipv4;
+        raw = (unsigned char *) &lh_sockaddr.in.sin_addr.s_addr;
+    } else {
+        type = ne_iaddr_ipv6;
+        raw = lh_sockaddr.in6.sin6_addr.s6_addr;
+    }
+
+    return ne_iaddr_make(type, raw);
+}
+
 int lookup_hostname(void)
 {
     char buf[BUFSIZ];
@@ -101,19 +199,26 @@ int lookup_hostname(void)
     return OK;
 }
 
-static int do_listen(struct in_addr addr, int port)
+static int do_listen(int port)
 {
-    int ls = socket(AF_INET, SOCK_STREAM, 0);
-    struct sockaddr_in saddr = {0};
+    int ls = socket(lh_family, SOCK_STREAM, 0);
+    struct sockaddr *saddr;
+    socklen_t saddrlen;
     int val = 1;
 
     setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int));
-    
-    saddr.sin_addr = addr;
-    saddr.sin_port = htons(port);
-    saddr.sin_family = AF_INET;
 
-    if (bind(ls, (struct sockaddr *)&saddr, sizeof(saddr))) {
+    if (lh_family == AF_INET) {
+	    lh_sockaddr.in.sin_port = htons(port);
+	    saddr = (struct sockaddr *) &lh_sockaddr.in;
+	    saddrlen = sizeof(lh_sockaddr.in);
+    } else {
+	    lh_sockaddr.in6.sin6_port = htons(port);
+	    saddr = (struct sockaddr *) &lh_sockaddr.in6;
+	    saddrlen = sizeof(lh_sockaddr.in6);
+    }
+
+    if (bind(ls, saddr, saddrlen)) {
 	printf("bind failed: %s\n", strerror(errno));
 	return -1;
     }
@@ -171,7 +276,7 @@ static int close_socket(ne_socket *sock)
 }
 
 /* This runs as the child process. */
-static int server_child(int readyfd, struct in_addr addr, int port,
+static int server_child(int readyfd, int port,
 			server_fn callback, void *userdata)
 {
     ne_socket *s = ne_sock_create();
@@ -179,7 +284,7 @@ static int server_child(int readyfd, struct in_addr addr, int port,
 
     in_child();
 
-    listener = do_listen(addr, port);
+    listener = do_listen(port);
     if (listener < 0)
 	return FAIL;
 
@@ -205,9 +310,8 @@ int spawn_server(int port, server_fn fn, void *ud)
 int spawn_server_addr(int bind_local, int port, server_fn fn, void *ud)
 {
     int fds[2];
-    struct in_addr addr;
 
-    addr = bind_local?lh_addr:hn_addr;
+    (void) bind_local;
 
 #ifdef USE_PIPE
     if (pipe(fds)) {
@@ -227,7 +331,7 @@ int spawn_server_addr(int bind_local, int port, server_fn fn, void *ud)
 	/* this is the child. */
 	int ret;
 
-	ret = server_child(fds[1], addr, port, fn, ud);
+	ret = server_child(fds[1], port, fn, ud);
 
 #ifdef USE_PIPE
 	close(fds[0]);
@@ -276,22 +380,30 @@ int new_spawn_server(int count, server_fn fn, void *userdata,
 int new_spawn_server2(int count, server_fn fn, void *userdata,
                       ne_inet_addr **addr, unsigned int *port)
 {
-    struct sockaddr_in sa;
+    static union {
+	struct sockaddr_in  in;
+	struct sockaddr_in6 in6;
+    } sa;
     socklen_t salen = sizeof sa;
     int ls;
     
     if (!have_lh_addr)
         lookup_localhost();
 
-    ls = do_listen(lh_addr, 0);
+    ls = do_listen(0);
     ONN("could not bind/listen fd for server", ls < 0);
 
-    ONV(getsockname(ls, &sa, &salen) != 0,
+    ONV(getsockname(ls, (struct sockaddr *) &sa, &salen) != 0,
         ("could not get socket name for listening fd: %s",
          strerror(errno)));
-    
-    *port = ntohs(sa.sin_port);
-    *addr = ne_iaddr_make(ne_iaddr_ipv4, (unsigned char *)&lh_addr.s_addr);
+
+    if (salen == sizeof(sa.in)) {
+	*port = ntohs(sa.in.sin_port);
+	*addr = ne_iaddr_make(ne_iaddr_ipv4, (void *) &sa.in.sin_addr.s_addr);
+    } else {
+	*port = ntohs(sa.in6.sin6_port);
+	*addr = ne_iaddr_make(ne_iaddr_ipv6, (void *) sa.in6.sin6_addr.s6_addr);
+    }
 
     NE_DEBUG(NE_DBG_SOCKET, "child using port %u\n", *port);
     
diff --git a/test/common/child.h b/test/common/child.h
index e34ff3b7877b..0fe66829251f 100644
--- a/test/common/child.h
+++ b/test/common/child.h
@@ -34,6 +34,10 @@
  * named test. */
 int lookup_localhost(void);
 
+int get_lh_family(void);
+const char *get_lh_addr(void);
+ne_inet_addr *get_lh_inet_addr(void);
+
 /* Test which looks up real local hostname. */
 int lookup_hostname(void);
 
diff --git a/test/utils.c b/test/utils.c
index 2bf8228d88e6..8b037ec6843c 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -204,7 +204,8 @@ int multi_session_server(ne_session **sess,
 
 int session_server(ne_session **sess, server_fn fn, void *userdata)
 {
-    return multi_session_server(sess, "http", "127.0.0.1", 1, fn, userdata);
+    return multi_session_server(sess, "http", get_lh_addr(), 1,
+				fn, userdata);
 }
 
 int proxied_session_server(ne_session **sess, const char *scheme,
@@ -219,7 +220,7 @@ int proxied_session_server(ne_session **sess, const char *scheme,
 
     NE_DEBUG(NE_DBG_HTTP, "test: Using proxied session to port %u.\n", port);
 
-    ne_session_proxy(*sess, "127.0.0.1", port);
+    ne_session_proxy(*sess, get_lh_addr(), port);
 
     return OK;
 }
-- 
2.39.2

From 876d887c4166f0e4a0a640f3e653d6fde7c00d95 Mon Sep 17 00:00:00 2001
From: Jeremy Sowden <jer...@azazel.net>
Date: Sun, 26 Mar 2023 14:49:28 +0100
Subject: [PATCH v2 2/2] Fix ipv4-related test failures

Update some tests which use 127.0.0.1 and skip others where the ipv4
assumptions are not so easily fixed.
---
 test/request.c | 26 ++++++++++++++------------
 test/socket.c  |  6 +++---
 test/ssl.c     |  4 ++--
 3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/test/request.c b/test/request.c
index e663d6dc557f..ddb0491af43c 100644
--- a/test/request.c
+++ b/test/request.c
@@ -2049,17 +2049,19 @@ static int status(void)
 {
     ne_session *sess;
     ne_buffer *buf = ne_buffer_create();
+    const char *lh_addr = get_lh_addr();
     char expect[1024];
 
     ne_snprintf(expect, sizeof expect,
-                "lookup(127.0.0.1)-"
-                "connecting(127.0.0.1,127.0.0.1)-"
-                "connected(127.0.0.1)-"
+                "lookup(%s)-"
+                "connecting(%s,%s)-"
+                "connected(%s)-"
                 "send(0,5000)-"
                 "send(5000,5000)-"
                 "recv(0,5)-"
                 "recv(5,5)-"
-                "disconnected(127.0.0.1)-");
+                "disconnected(%s)-",
+                lh_addr, lh_addr, lh_addr, lh_addr, lh_addr);
 
     CALL(make_session(&sess, single_serve_string, RESP200
                       "Content-Length: 5\r\n\r\n" "abcde"));
@@ -2084,14 +2086,15 @@ static int status_chunked(void)
 {
     ne_session *sess;
     ne_buffer *buf = ne_buffer_create();
+    const char *lh_addr = get_lh_addr();
     char expect[1024];
 
     /* This sequence is not exactly guaranteed by the API, but it's
      * what the current implementation should do. */
     ne_snprintf(expect, sizeof expect,
-                "lookup(127.0.0.1)-"
-                "connecting(127.0.0.1,127.0.0.1)-"
-                "connected(127.0.0.1)-"
+                "lookup(%s)-"
+                "connecting(%s,%s)-"
+                "connected(%s)-"
                 "send(0,5000)-"
                 "send(5000,5000)-"
                 "recv(0,-1)-"
@@ -2100,7 +2103,8 @@ static int status_chunked(void)
                 "recv(3,-1)-"
                 "recv(4,-1)-"
                 "recv(5,-1)-"
-                "disconnected(127.0.0.1)-");
+                "disconnected(%s)-",
+                lh_addr, lh_addr, lh_addr, lh_addr, lh_addr);
 
     CALL(make_session(&sess, single_serve_string, 
                       RESP200 TE_CHUNKED "\r\n" ABCDE_CHUNKS));
@@ -2121,12 +2125,10 @@ static int status_chunked(void)
     return OK;
 }
 
-static const unsigned char raw_127[4] = "\x7f\0\0\01"; /* 127.0.0.1 */
-
 static int local_addr(void)
 {
     ne_session *sess;
-    ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);
+    ne_inet_addr *ia = get_lh_inet_addr();
 
     CALL(make_session(&sess, single_serve_string, RESP200 
                       "Connection: close\r\n\r\n"));
@@ -2160,7 +2162,7 @@ static int dereg_progress(void)
 static int addrlist(void)
 {
     ne_session *sess;
-    ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);
+    ne_inet_addr *ia = get_lh_inet_addr();
     const ne_inet_addr *ial[1];
     unsigned int port;
 
diff --git a/test/socket.c b/test/socket.c
index 566cbe156f2d..0484a46e368b 100644
--- a/test/socket.c
+++ b/test/socket.c
@@ -453,7 +453,7 @@ static int addr_connect(void)
     ne_inet_addr *ia;
     unsigned int port;
 
-    ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);
+    ia = get_lh_inet_addr();
     ONN("ne_iaddr_make returned NULL", ia == NULL);
     
     CALL(new_spawn_server(1, serve_close, NULL, &port));
@@ -470,7 +470,7 @@ static int addr_peer(void)
     unsigned int port = 9999, realport;
     int ret;
 
-    ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);
+    ia = get_lh_inet_addr();
     ONN("ne_iaddr_make returned NULL", ia == NULL);
     
     CALL(new_spawn_server(1, serve_close, NULL, &realport));
@@ -1331,7 +1331,7 @@ static int try_prebind(int addr, int port)
     char buf[128], line[256];
     unsigned int srvport;
 
-    ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);
+    ia = get_lh_inet_addr();
     ONN("ne_iaddr_make returned NULL", ia == NULL);
     
     CALL(new_spawn_server(1, serve_ppeer, NULL, &srvport));
diff --git a/test/ssl.c b/test/ssl.c
index 470521e1d29a..fc5e1bff81ab 100644
--- a/test/ssl.c
+++ b/test/ssl.c
@@ -971,7 +971,7 @@ static int fail_missing_CN(void)
 /* test for a bad ipAddress altname */
 static int fail_bad_ipaltname(void)
 {
-    return fail_ssl_request("altname6.cert", CA_CERT, "127.0.0.1",
+    return fail_ssl_request("altname6.cert", CA_CERT, get_lh_addr(),
                             "bad IP altname cert", NE_SSL_IDMISMATCH);
 }
 
@@ -997,7 +997,7 @@ static int fail_wildcard(void)
 
 static int fail_wildcard_ip(void)
 {
-    return fail_ssl_request("wildip.cert", CA_CERT, "127.0.0.1",
+    return fail_ssl_request("wildip.cert", CA_CERT, get_lh_addr(),
                             "wildcard IP", NE_SSL_IDMISMATCH);
 }
 
-- 
2.39.2

Attachment: signature.asc
Description: PGP signature

Reply via email to