Download raw body.
gotwebd: initialize IPv4 and IPv6 sockets in the same way
On Tue, Aug 16, 2022 at 06:45:27PM +0200, Stefan Sperling wrote:
> 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?
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) {
>
--
Tracey Emery
gotwebd: initialize IPv4 and IPv6 sockets in the same way