Download raw body.
gotwebd: socket_conf address list
On Fri, Aug 19, 2022 at 05:29:32PM +0200, Stefan Sperling wrote:
> Unless I am missing smoething, the address list in struct socket_conf
> serves no purpose. This struct should be storing a single address only.
> Note how the loop in sockets_create_socket() maps all addresses on this
> list into a single file descriptor, leaking any fd apart from the one
> opened during the final loop iteration. Which means only the final element
> on the list is actually being used.
>
> Mapping each address to one struct socket_conf makes more sense to me.
> So instead of looping over all server addresses in sockets_conf_new_socket(),
> we now loop over all server addresses in sockets_parse_sockets(), and we
> create one socket config per address. Makes sense?
>
> While here, fix some fd leaks on error in sockets_create_socket().
>
> ok?
Looks good and works. Thanks! ok.
>
> diff 85f2c2e0132ed34974446382474602b11d336f3a f1061a5ba3b809ed0122c1d06d688a56030948ac
> commit - 85f2c2e0132ed34974446382474602b11d336f3a
> commit + f1061a5ba3b809ed0122c1d06d688a56030948ac
> blob - 71be6a49025d52f2768a5f9a8f625964d6a23e38
> blob + 023b44fecc6121825c91a6a6112a07a7abdedeb6
> --- gotwebd/gotwebd.h
> +++ gotwebd/gotwebd.h
> @@ -289,7 +289,7 @@ enum client_action {
> };
>
> struct socket_conf {
> - struct addresslist al;
> + struct address addr;
>
> char name[GOTWEBD_MAXTEXT];
> char srv_name[GOTWEBD_MAXTEXT];
> blob - bde51dbff1e8cbc18fd20d36fe3701aa4ab66e53
> blob + 836377578903d72f44f5cc1ae1fecf1e440af00c
> --- gotwebd/sockets.c
> +++ gotwebd/sockets.c
> @@ -73,12 +73,14 @@ void sockets_rlimit(int);
>
> int sockets_dispatch_gotwebd(int, struct privsep_proc *, struct imsg *);
> int sockets_unix_socket_listen(struct privsep *, struct socket *);
> -int sockets_create_socket(struct addresslist *, in_port_t);
> +int sockets_create_socket(struct address *, in_port_t);
> int sockets_accept_reserve(int, struct sockaddr *, socklen_t *, int,
> volatile int *);
>
> -struct socket *sockets_conf_new_socket(struct gotwebd *, struct server *,
> - int, int);
> +struct socket *sockets_conf_new_socket_unix(struct gotwebd *, struct server *,
> + int);
> +struct socket *sockets_conf_new_socket_fcgi(struct gotwebd *, struct server *,
> + int, struct address *);
>
> int cgi_inflight = 0;
>
> @@ -117,73 +119,95 @@ void
> sockets_parse_sockets(struct gotwebd *env)
> {
> struct server *srv;
> + struct address *a;
> struct socket *new_sock = NULL;
> - int sock_id = 0, ipv4 = 0, ipv6 = 0;
> + int sock_id = 1;
>
> TAILQ_FOREACH(srv, &env->servers, entry) {
> if (srv->unix_socket) {
> - sock_id++;
> - new_sock = sockets_conf_new_socket(env, srv,
> - 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,
> - AF_INET);
> + new_sock = sockets_conf_new_socket_unix(env, srv,
> + sock_id);
> if (new_sock) {
> + sock_id++;
> TAILQ_INSERT_TAIL(&env->sockets, new_sock,
> entry);
> - ipv4 = 1;
> - sock_id++;
> }
> + }
>
> - 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;
> + if (srv->fcgi_socket) {
> + if (TAILQ_EMPTY(&srv->al)) {
> + fatalx("%s: server %s has no IP addresses to "
> + "listen for FCGI connections", __func__,
> + srv->name);
> }
> -
> - if (ipv4 == 0 && ipv6 == 0) {
> - fatalx("%s: have no IP addresses to listen "
> - "for FCGI connections", __func__);
> + TAILQ_FOREACH(a, &srv->al, entry) {
> + if (a->ss.ss_family != AF_INET &&
> + a->ss.ss_family != AF_INET6)
> + continue;
> + new_sock = sockets_conf_new_socket_fcgi(env,
> + srv, sock_id, a);
> + if (new_sock) {
> + sock_id++;
> + TAILQ_INSERT_TAIL(&env->sockets,
> + new_sock, 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 af_type)
> +sockets_conf_new_socket_unix(struct gotwebd *env, struct server *srv, int id)
> {
> struct socket *sock;
> - struct address *a, *acp;
> int n;
>
> if ((sock = calloc(1, sizeof(*sock))) == NULL)
> fatalx("%s: calloc", __func__);
>
> - TAILQ_INIT(&sock->conf.al);
> -
> sock->conf.id = id;
> sock->fd = -1;
> - sock->conf.af_type = af_type;
> + sock->conf.af_type = AF_UNIX;
>
> - if (af_type == AF_UNIX) {
> - if (strlcpy(sock->conf.unix_socket_name,
> - srv->unix_socket_name,
> - sizeof(sock->conf.unix_socket_name)) >=
> - sizeof(sock->conf.unix_socket_name)) {
> - free(sock);
> - fatalx("%s: strlcpy", __func__);
> - }
> + if (strlcpy(sock->conf.unix_socket_name,
> + srv->unix_socket_name,
> + sizeof(sock->conf.unix_socket_name)) >=
> + sizeof(sock->conf.unix_socket_name)) {
> + free(sock);
> + fatalx("%s: strlcpy", __func__);
> }
>
> + n = snprintf(sock->conf.name, GOTWEBD_MAXTEXT, "%s_parent",
> + srv->name);
> + if (n < 0 || (size_t)n >= GOTWEBD_MAXTEXT) {
> + free(sock);
> + fatalx("%s: snprintf", __func__);
> + }
> +
> + if (strlcpy(sock->conf.srv_name, srv->name,
> + sizeof(sock->conf.srv_name)) >= sizeof(sock->conf.srv_name)) {
> + free(sock);
> + fatalx("%s: strlcpy", __func__);
> + }
> +
> + return sock;
> +}
> +
> +struct socket *
> +sockets_conf_new_socket_fcgi(struct gotwebd *env, struct server *srv, int id,
> + struct address *a)
> +{
> + struct socket *sock;
> + struct address *acp;
> + int n;
> +
> + if ((sock = calloc(1, sizeof(*sock))) == NULL)
> + fatalx("%s: calloc", __func__);
> +
> + sock->conf.id = id;
> + sock->fd = -1;
> + sock->conf.af_type = a->ss.ss_family;
> +
> sock->conf.fcgi_socket_port = srv->fcgi_socket_port;
>
> n = snprintf(sock->conf.name, GOTWEBD_MAXTEXT, "%s_parent",
> @@ -199,35 +223,20 @@ sockets_conf_new_socket(struct gotwebd *env, struct se
> fatalx("%s: strlcpy", __func__);
> }
>
> - TAILQ_FOREACH(a, &srv->al, entry) {
> - if (a->ss.ss_family != af_type)
> - continue;
> + acp = &sock->conf.addr;
>
> - if ((acp = calloc(1, sizeof(*acp))) == NULL) {
> - free(sock);
> - 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__);
> }
> - 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__);
> - }
> - }
> -
> - TAILQ_INSERT_TAIL(&sock->conf.al, acp, entry);
> }
>
> - if ((af_type == AF_INET || af_type == AF_INET6) &&
> - TAILQ_EMPTY(&sock->conf.al)) {
> - free(sock);
> - return NULL;
> - }
> -
> return (sock);
> }
>
> @@ -378,10 +387,10 @@ sockets_privinit(struct gotwebd *env, struct socket *s
> 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->fd = sockets_create_socket(&sock->conf.addr,
> sock->conf.fcgi_socket_port);
> if (sock->fd == -1) {
> - log_warnx("%s: create unix socket failed", __func__);
> + log_warnx("%s: create FCGI socket failed", __func__);
> return -1;
> }
> }
> @@ -465,10 +474,9 @@ sockets_unix_socket_listen(struct privsep *ps, struct
> }
>
> int
> -sockets_create_socket(struct addresslist *al, in_port_t port)
> +sockets_create_socket(struct address *a, in_port_t port)
> {
> struct addrinfo hints;
> - struct address *a;
> int fd = -1, o_val = 1, flags;
>
> memset(&hints, 0, sizeof(hints));
> @@ -476,53 +484,55 @@ sockets_create_socket(struct addresslist *al, in_port_
> hints.ai_socktype = SOCK_STREAM;
> hints.ai_flags |= AI_PASSIVE;
>
> - TAILQ_FOREACH(a, al, entry) {
> - switch (a->ss.ss_family) {
> - case AF_INET:
> - ((struct sockaddr_in *)(&a->ss))->sin_port = port;
> - break;
> - case AF_INET6:
> - ((struct sockaddr_in6 *)(&a->ss))->sin6_port = port;
> - break;
> - default:
> - log_warnx("%s: unknown address family", __func__);
> - goto fail;
> - }
> + switch (a->ss.ss_family) {
> + case AF_INET:
> + ((struct sockaddr_in *)(&a->ss))->sin_port = port;
> + break;
> + case AF_INET6:
> + ((struct sockaddr_in6 *)(&a->ss))->sin6_port = port;
> + break;
> + default:
> + log_warnx("%s: unknown address family", __func__);
> + return -1;
> + }
>
> - fd = socket(a->ss.ss_family, hints.ai_socktype,
> - a->ipproto);
> - log_debug("%s: opening socket (%d) for %s", __func__,
> - fd, a->ifname);
> + fd = socket(a->ss.ss_family, hints.ai_socktype, a->ipproto);
> + if (fd == -1)
> + return -1;
>
> - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &o_val,
> - sizeof(int)) == -1) {
> - log_warn("%s: setsockopt error", __func__);
> - return -1;
> - }
> + log_debug("%s: opened socket (%d) for %s", __func__,
> + fd, a->ifname);
>
> - /* non-blocking */
> - flags = fcntl(fd, F_GETFL);
> - flags |= O_NONBLOCK;
> - fcntl(fd, F_SETFL, flags);
> + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &o_val,
> + sizeof(int)) == -1) {
> + log_warn("%s: setsockopt error", __func__);
> + close(fd);
> + return -1;
> + }
>
> - if (bind(fd, (struct sockaddr *)&a->ss, a->ss.ss_len) == -1) {
> - close(fd);
> - log_info("%s: can't bind to port %d", __func__,
> - ntohs(port));
> - goto fail;
> - }
> + /* non-blocking */
> + flags = fcntl(fd, F_GETFL);
> + flags |= O_NONBLOCK;
> + if (fcntl(fd, F_SETFL, flags) == -1) {
> + log_info("%s: could not enable non-blocking I/O", __func__);
> + close(fd);
> + return -1;
> + }
>
> - if (listen(fd, SOMAXCONN) == -1) {
> - log_warn("%s, unable to listen on socket", __func__);
> - goto fail;
> - }
> + if (bind(fd, (struct sockaddr *)&a->ss, a->ss.ss_len) == -1) {
> + close(fd);
> + log_info("%s: can't bind to port %d", __func__,
> + ntohs(port));
> + return -1;
> }
>
> - free(a);
> + if (listen(fd, SOMAXCONN) == -1) {
> + log_warn("%s, unable to listen on socket", __func__);
> + close(fd);
> + return -1;
> + }
> +
> return (fd);
> -fail:
> - free(a);
> - return -1;
> }
>
> int
>
--
Tracey Emery
gotwebd: socket_conf address list