"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
gotwebd: initialize IPv4 and IPv6 sockets in the same way
To:
gameoftrees@openbsd.org
Date:
Tue, 16 Aug 2022 18:45:27 +0200

Download raw body.

Thread
Simplify gotwebd's socket initialization code.

There is no reason to treat IPv6 differently, it's just another address
family. We might have a dual-stack setup, or IPv4-only, or IPv6-only,
and all these cases ought to work.

At present, the configuration file accepts only one "listen on" statement
per server. Which means the only way to run dual-stack is to specify the
name of an interface which has both IPv4 and IPv6 addresses configured,
instead of specifying a set of IP addresses.
This patch is a first step towards lifting this limitation.

Ok?
 
diff 73ffdfc038e3a5f5bf130d7c5754428ff92f69e4 4419b431948d0a7a36543168bce3b3e253ae08ec
commit - 73ffdfc038e3a5f5bf130d7c5754428ff92f69e4
commit + 4419b431948d0a7a36543168bce3b3e253ae08ec
blob - 2ff6fae01c54ac33ce96e4a1a48f018b553cdc75
blob + 29bdf6301687d8ed6e4ae5f52d25ea757efd3176
--- gotwebd/config.c
+++ gotwebd/config.c
@@ -212,11 +212,11 @@ config_getsock(struct gotwebd *env, struct imsg *imsg)
 		sock->pack_fds[i] = -1;
 
 	/* log new socket info */
-	log_debug("%s: name=%s id=%d server=%s child_id=%d parent_id=%d "
-	    "type=%s ipv4=%d ipv6=%d socket_path=%s",
+	log_debug("%s: name=%s id=%d server=%s af_type=%s socket_path=%s",
 	    __func__, sock->conf.name, sock->conf.id, sock->conf.srv_name,
-	    sock->conf.child_id, sock->conf.parent_id, sock->conf.type ?
-	    "fcgi" : "unix", sock->conf.ipv4, sock->conf.ipv6,
+	    sock->conf.af_type == AF_UNIX ? "unix" :
+	    (sock->conf.af_type == AF_INET ? "inet" :
+	    (sock->conf.af_type == AF_INET6 ? "inet6" : "unknown")),
 	    strlen(sock->conf.unix_socket_name) ?
 	    sock->conf.unix_socket_name : "none");
 
blob - 0f238f4dcbdecd4cd7a5224cea8dd35c9bd25215
blob + 71be6a49025d52f2768a5f9a8f625964d6a23e38
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -288,11 +288,6 @@ enum client_action {
 	CLIENT_DISCONNECT,
 };
 
-enum sock_type {
-	UNIX,
-	FCGI,
-};
-
 struct socket_conf {
 	struct addresslist	al;
 
@@ -300,13 +295,7 @@ struct socket_conf {
 	char		 srv_name[GOTWEBD_MAXTEXT];
 
 	int		 id;
-	int		 child_id;
-	int		 parent_id;
-
-	int		 ipv4;
-	int		 ipv6;
-
-	int		 type;
+	int		 af_type;
 	char		 unix_socket_name[PATH_MAX];
 	in_port_t	 fcgi_socket_port;
 };
blob - a8601823f7e0c6d8d1c751a2980c6b4976f7003e
blob + bde51dbff1e8cbc18fd20d36fe3701aa4ab66e53
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
@@ -68,7 +68,6 @@ void	 sockets_run(struct privsep *, struct privsep_pro
 void	 sockets_launch(void);
 void	 sockets_purge(struct gotwebd *);
 void	 sockets_accept_paused(int, short, void *);
-void	 sockets_dup_new_socket(struct socket *, struct socket *);
 void	 sockets_rlimit(int);
 
 
@@ -78,9 +77,8 @@ int	 sockets_create_socket(struct addresslist *, in_po
 int	 sockets_accept_reserve(int, struct sockaddr *, socklen_t *, int,
 	    volatile int *);
 
-struct socket
-	*sockets_conf_new_socket(struct gotwebd *, struct server *, int, int,
-	    int);
+struct socket *sockets_conf_new_socket(struct gotwebd *, struct server *,
+    int, int);
 
 int cgi_inflight = 0;
 
@@ -119,97 +117,49 @@ void
 sockets_parse_sockets(struct gotwebd *env)
 {
 	struct server *srv;
-	struct socket *sock, *new_sock = NULL;
-	struct address *a;
+	struct socket *new_sock = NULL;
 	int sock_id = 0, ipv4 = 0, ipv6 = 0;
 
 	TAILQ_FOREACH(srv, &env->servers, entry) {
 		if (srv->unix_socket) {
 			sock_id++;
 			new_sock = sockets_conf_new_socket(env, srv,
-			    sock_id, UNIX, 0);
+			    sock_id, AF_UNIX);
+			/* Should always succeed. */
 			TAILQ_INSERT_TAIL(&env->sockets, new_sock, entry);
 		}
 
 		if (srv->fcgi_socket) {
 			sock_id++;
-			new_sock = sockets_conf_new_socket(env, srv,
-			    sock_id, FCGI, 0);
-			TAILQ_INSERT_TAIL(&env->sockets, new_sock, entry);
+			new_sock = sockets_conf_new_socket(env, srv, sock_id,
+			    AF_INET);
+			if (new_sock) {
+				TAILQ_INSERT_TAIL(&env->sockets, new_sock,
+				    entry);
+				ipv4 = 1;
+				sock_id++;
+			}
 
-			/* add ipv6 children */
-			TAILQ_FOREACH(sock, &env->sockets, entry) {
-				ipv4 = ipv6 = 0;
-
-				TAILQ_FOREACH(a, &sock->conf.al, entry) {
-					if (a->ss.ss_family == AF_INET)
-						ipv4 = 1;
-					if (a->ss.ss_family == AF_INET6)
-						ipv6 = 1;
-				}
-
-				/* create ipv6 sock */
-				if (ipv4 == 1 && ipv6 == 1) {
-					sock_id++;
-					sock->conf.child_id = sock_id;
-					new_sock = sockets_conf_new_socket(env,
-					    srv, sock_id, FCGI, 1);
-					sockets_dup_new_socket(sock, new_sock);
-					TAILQ_INSERT_TAIL(&env->sockets,
-					    new_sock, entry);
-					continue;
-				}
+			new_sock = sockets_conf_new_socket(env, srv, sock_id,
+			    AF_INET6);
+			if (new_sock) {
+				TAILQ_INSERT_TAIL(&env->sockets,
+				    new_sock, entry);
+				ipv6 = 1;
 			}
-		}
-	}
-}
 
-void
-sockets_dup_new_socket(struct socket *p_sock, struct socket *sock)
-{
-	struct address *a, *acp;
-	int n;
-
-	sock->conf.parent_id = p_sock->conf.id;
-	sock->conf.ipv4 = 0;
-	sock->conf.ipv6 = 1;
-
-	memcpy(&sock->conf.srv_name, p_sock->conf.srv_name,
-	    sizeof(sock->conf.srv_name));
-
-	n = snprintf(sock->conf.name, GOTWEBD_MAXTEXT, "%s_child",
-	    p_sock->conf.srv_name);
-	if (n < 0 || (size_t)n >= GOTWEBD_MAXTEXT) {
-		free(p_sock);
-		free(sock);
-		fatalx("%s: snprintf", __func__);
-	}
-
-	TAILQ_FOREACH(a, &p_sock->conf.al, entry) {
-		if (a->ss.ss_family == AF_INET)
-			continue;
-
-		if ((acp = calloc(1, sizeof(*acp))) == NULL)
-			fatal("%s: calloc", __func__);
-		memcpy(&acp->ss, &a->ss, sizeof(acp->ss));
-		acp->ipproto = a->ipproto;
-		acp->prefixlen = a->prefixlen;
-		acp->port = a->port;
-		if (strlen(a->ifname) != 0) {
-			if (strlcpy(acp->ifname, a->ifname,
-			    sizeof(acp->ifname)) >= sizeof(acp->ifname)) {
-				fatalx("%s: interface name truncated",
-				    __func__);
+			if (ipv4 == 0 && ipv6 == 0) {
+				fatalx("%s: have no IP addresses to listen "
+				    "for FCGI connections", __func__);
 			}
 		}
-
-		TAILQ_INSERT_TAIL(&sock->conf.al, acp, entry);
 	}
 }
 
+/* Returns NULL if no addresses in the requested family are configured. */
 struct socket *
 sockets_conf_new_socket(struct gotwebd *env, struct server *srv, int id,
-    int type, int is_dup)
+    int af_type)
 {
 	struct socket *sock;
 	struct address *a, *acp;
@@ -220,14 +170,11 @@ sockets_conf_new_socket(struct gotwebd *env, struct se
 
 	TAILQ_INIT(&sock->conf.al);
 
-	sock->conf.parent_id = 0;
 	sock->conf.id = id;
-
 	sock->fd = -1;
+	sock->conf.af_type = af_type;
 
-	sock->conf.type = type;
-
-	if (type == UNIX) {
+	if (af_type == AF_UNIX) {
 		if (strlcpy(sock->conf.unix_socket_name,
 		    srv->unix_socket_name,
 		    sizeof(sock->conf.unix_socket_name)) >=
@@ -235,14 +182,10 @@ sockets_conf_new_socket(struct gotwebd *env, struct se
 			free(sock);
 			fatalx("%s: strlcpy", __func__);
 		}
-	} else
-		sock->conf.ipv4 = 1;
+	}
 
 	sock->conf.fcgi_socket_port = srv->fcgi_socket_port;
 
-	if (is_dup)
-		goto done;
-
 	n = snprintf(sock->conf.name, GOTWEBD_MAXTEXT, "%s_parent",
 	    srv->name);
 	if (n < 0 || (size_t)n >= GOTWEBD_MAXTEXT) {
@@ -257,6 +200,9 @@ sockets_conf_new_socket(struct gotwebd *env, struct se
 	}
 
 	TAILQ_FOREACH(a, &srv->al, entry) {
+		if (a->ss.ss_family != af_type)
+			continue;
+
 		if ((acp = calloc(1, sizeof(*acp))) == NULL) {
 			free(sock);
 			fatal("%s: calloc", __func__);
@@ -275,7 +221,13 @@ sockets_conf_new_socket(struct gotwebd *env, struct se
 
 		TAILQ_INSERT_TAIL(&sock->conf.al, acp, entry);
 	}
-done:
+
+	if ((af_type == AF_INET || af_type == AF_INET6) &&
+	    TAILQ_EMPTY(&sock->conf.al)) {
+		free(sock);
+		return NULL;
+	}
+
 	return (sock);
 }
 
@@ -412,7 +364,7 @@ sockets_privinit(struct gotwebd *env, struct socket *s
 {
 	struct privsep *ps = env->gotwebd_ps;
 
-	if (sock->conf.type == UNIX) {
+	if (sock->conf.af_type == AF_UNIX) {
 		log_debug("%s: initializing unix socket %s", __func__,
 		    sock->conf.unix_socket_name);
 		sock->fd = sockets_unix_socket_listen(ps, sock);
@@ -422,9 +374,10 @@ sockets_privinit(struct gotwebd *env, struct socket *s
 		}
 	}
 
-	if (sock->conf.type == FCGI) {
-		log_debug("%s: initializing fcgi socket for %s", __func__,
-		    sock->conf.name);
+	if (sock->conf.af_type == AF_INET || sock->conf.af_type == AF_INET6) {
+		log_debug("%s: initializing %s FCGI socket on port %d for %s",
+		    __func__, sock->conf.af_type == AF_INET ? "inet" : "inet6",
+		    sock->conf.fcgi_socket_port, sock->conf.name);
 		sock->fd = sockets_create_socket(&sock->conf.al,
 		    sock->conf.fcgi_socket_port);
 		if (sock->fd == -1) {