]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: sock: also restore effective unix family in get_{src,dst}()
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 29 Oct 2024 10:38:11 +0000 (11:38 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Tue, 29 Oct 2024 11:15:03 +0000 (12:15 +0100)
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.

src/sock.c

index 423a92534ddca19f1d4b61a7c32be37f984e939f..203e3a0e2cdebe3a8d2fb56a861bfa860a10da02 100644 (file)
@@ -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 <fd>, with <dir> 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 <unixsocket>. 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);
                }