From: Stefan Sperling Subject: gotwebd: initialize IPv4 and IPv6 sockets in the same way To: gameoftrees@openbsd.org Date: Tue, 16 Aug 2022 18:45:27 +0200 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) {