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.
This commit is contained in:
Aurelien DARRAGON 2024-10-29 11:38:11 +01:00
parent ae64444303
commit d879bf6600

View 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);
}