From: Aurelien DARRAGON Date: Tue, 29 Oct 2024 10:38:11 +0000 (+0100) Subject: MEDIUM: sock: also restore effective unix family in get_{src,dst}() X-Git-Tag: v3.1-dev11~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d879bf6600f4518f974766340e0d55ae83484f1e;p=thirdparty%2Fhaproxy.git MEDIUM: sock: also restore effective unix family in get_{src,dst}() As in previous commit, let's push the logic a bit further in order to properly restore the effective UNIX socket type when leveraging get_src() and get_dst() sock functions, since they rely on getpeername() and getsockname() under the hood, both of which will actually loose the effective family and return AF_UNIX for all our custom UNIX sockets. To do this, add sock_restore_unix_family() helper function from the logic implemented in the previous commit, and call this function from get_src() and get_dst() in case of unix socket prior to returning. --- diff --git a/src/sock.c b/src/sock.c index 423a92534d..203e3a0e2c 100644 --- a/src/sock.c +++ b/src/sock.c @@ -385,6 +385,28 @@ void sock_unbind(struct receiver *rx) rx->fd = -1; } +/* restore effective family for UNIX type sockets if needed. Indeed since + * kernel doesn't know about custom UNIX families (internal to HAproxy), + * they lost when leveraging syscalls such as getsockname() or getpeername(). + * + * This function guesses the effective family by analyzing address and address + * length as returned by getsockname() and getpeername() calls. + */ +static void sock_restore_unix_family(struct sockaddr_un *un, socklen_t socklen) +{ + BUG_ON(un->sun_family != AF_UNIX); + + if (un->sun_path[0]); // regular UNIX socket, not a custom family + else if (socklen == sizeof(*un)) + un->sun_family = AF_CUST_ABNS; + else { + /* not all struct sockaddr_un space is used.. + * (sun_path is partially filled) + */ + un->sun_family = AF_CUST_ABNSZ; + } +} + /* * Retrieves the source address for the socket , with indicating * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of @@ -393,10 +415,19 @@ void sock_unbind(struct receiver *rx) */ int sock_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir) { + int ret; + if (dir) - return getsockname(fd, sa, &salen); + ret = getsockname(fd, sa, &salen); else - return getpeername(fd, sa, &salen); + ret = getpeername(fd, sa, &salen); + + if (ret) + return ret; + if (sa->sa_family == AF_UNIX) + sock_restore_unix_family((struct sockaddr_un *)sa, salen); + + return ret; } /* @@ -407,10 +438,19 @@ int sock_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir) */ int sock_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) { + int ret; + if (dir) - return getpeername(fd, sa, &salen); + ret = getpeername(fd, sa, &salen); else - return getsockname(fd, sa, &salen); + ret = getsockname(fd, sa, &salen); + + if (ret) + return ret; + if (sa->sa_family == AF_UNIX) + sock_restore_unix_family((struct sockaddr_un *)sa, salen); + + return ret; } /* Try to retrieve exported sockets from worker at CLI . These @@ -601,20 +641,10 @@ int sock_get_old_sockets(const char *unixsocket) continue; } if (xfer_sock->addr.ss_family == AF_UNIX) { - const struct sockaddr_un *un = (const struct sockaddr_un *)&xfer_sock->addr; - /* restore effective family if needed, because getsockname() * only knows about real families: */ - if (un->sun_path[0]); // regular UNIX socket, not a custom family - else if (socklen == sizeof(*un)) - xfer_sock->addr.ss_family = AF_CUST_ABNS; - else { - /* not all struct sockaddr_un space is used.. - * (sun_path is partially filled) - */ - xfer_sock->addr.ss_family = AF_CUST_ABNSZ; - } + sock_restore_unix_family((struct sockaddr_un *)&xfer_sock->addr, socklen); }