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
*/
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;
}
/*
*/
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
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);
}