diff --git a/doc/configuration.txt b/doc/configuration.txt index 3a63798bf..68777b2b8 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6073,6 +6073,11 @@ bind / [, ...] [param*] only in log-forward sections. - 'unix@' -> address is a path to a local unix socket - 'abns@' -> address is in abstract namespace (Linux only). + - 'abnsz@' -> address is in abstract namespace (Linux only) + but it is explicitly zero-terminated. This means no \0 + padding is used to complete sun_path. It is useful to + interconnect with programs that don't implement the + default abns naming logic that haproxy uses. - 'fd@' -> use file descriptor inherited from the parent. The fd must be bound and may or may not already be listening. @@ -6165,11 +6170,12 @@ bind / [, ...] [param*] listen h3_quic_proxy bind quic4@10.0.0.1:8888 ssl crt /etc/mycrt - Note: regarding Linux's abstract namespace sockets, HAProxy uses the whole - sun_path length is used for the address length. Some other programs - such as socat use the string length only by default. Pass the option - ",unix-tightsocklen=0" to any abstract socket definition in socat to - make it compatible with HAProxy's. + Note: regarding Linux's abstract namespace sockets, "abns" HAProxy sockets + uses the whole sun_path length is used for the address length. Some + other programs such as socat use the string length only by default. + Pass the option ",unix-tightsocklen=0" to any abstract socket + definition in socat to make it compatible with HAProxy's, or use the + "abnsz" HAProxy socket family instead. See also : "source", "option forwardfor", "unix-bind" and the PROXY protocol documentation, and section 5 about bind options. @@ -11586,6 +11592,11 @@ server
[:[port]] [param*] - 'ipv6@' -> address is always IPv6 - 'unix@' -> address is a path to a local unix socket - 'abns@' -> address is in abstract namespace (Linux only) + - 'abnsz@' -> address is in abstract namespace (Linux only) + but it is explicitly zero-terminated. This means no \0 + padding is used to complete sun_path. It is useful to + interconnect with programs that don't implement the + default abns naming logic that haproxy uses. - 'sockpair@' -> address is the FD of a connected unix socket or of a socketpair. During a connection, the backend creates a pair of connected sockets, and passes @@ -11620,11 +11631,12 @@ server
[:[port]] [param*] server www1_dc1 "${LAN_DC1}.101:80" server www1_dc2 "${LAN_DC2}.101:80" - Note: regarding Linux's abstract namespace sockets, HAProxy uses the whole - sun_path length is used for the address length. Some other programs - such as socat use the string length only by default. Pass the option - ",unix-tightsocklen=0" to any abstract socket definition in socat to - make it compatible with HAProxy's. + Note: regarding Linux's abstract namespace sockets, "abns" HAProxy sockets + uses the whole sun_path length is used for the address length. Some + other programs such as socat use the string length only by default. + Pass the option ",unix-tightsocklen=0" to any abstract socket + definition in socat to make it compatible with HAProxy's, or use the + "abnsz" HAProxy socket family instead. See also: "default-server", "http-send-name-header" and section 5 about server options @@ -11721,6 +11733,9 @@ source [:] [interface ] - 'ipv6@' -> address is always IPv6 - 'unix@' -> address is a path to a local unix socket - 'abns@' -> address is in abstract namespace (Linux only) + - 'abnsz@' -> address is in zero-terminated abstract namespace + (Linux only) + You may want to reference some environment variables in the address parameter, see section 2.3 about environment variables. @@ -28564,6 +28579,9 @@ socket type and the transport method. 'abns@' following is an abstract namespace (Linux only). +'abnsz@' following is a zero-terminated abstract namespace + (Linux only). + 'fd@' following address is a file descriptor inherited from the parent. The fd must be bound and may or may not already be listening. diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index c47e5cd1f..8e29d38cc 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -785,8 +785,15 @@ static inline int get_addr_len(const struct sockaddr_storage *addr) return sizeof(struct sockaddr_in6); case AF_UNIX: case AF_CUST_ABNS: - case AF_CUST_ABNSZ: return sizeof(struct sockaddr_un); + case AF_CUST_ABNSZ: + { + const struct sockaddr_un *un = (struct sockaddr_un *)addr; + + /* stop at first NULL-byte */ + return offsetof(struct sockaddr_un, sun_path) + 1 + + strnlen2(un->sun_path + 1, sizeof(un->sun_path) - 1); + } } return 0; } diff --git a/reg-tests/server/abnsz.vtc b/reg-tests/server/abnsz.vtc new file mode 100644 index 000000000..072cba98a --- /dev/null +++ b/reg-tests/server/abnsz.vtc @@ -0,0 +1,37 @@ +varnishtest "Abstract unix socket - zero terminated" +feature ignore_unknown_macro +feature cmd "command -v curl" + +# abns@ sockets are not available on freebsd +#EXCLUDE_TARGETS=freebsd,osx,generic +#REGTEST_TYPE=devel + +haproxy h1 -W -S -conf { + global + stats socket "${tmpdir}/h1/stats" level admin expose-fd listeners + + defaults + mode http + log global + option httplog + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + + listen testme + bind "fd@${testme}" + server f2 abnsz@hap-f2 + + frontend f2 + bind abnsz@hap-f2 + http-request return status 200 content-type text/plain string "ok" +} -start + +client c1 -connect ${h1_testme_sock} { + txreq -url "/" + rxresp +} -run + +shell { + curl -sfS --abstract-unix-socket hap-f2 "http://host/" | grep "ok" +} diff --git a/src/connection.c b/src/connection.c index 07655934b..1b644b0be 100644 --- a/src/connection.c +++ b/src/connection.c @@ -2684,13 +2684,22 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss, break; case AF_CUST_ABNS: - case AF_CUST_ABNSZ: conn_hash_update(hash, &((struct sockaddr_un *)ss)->sun_path, sizeof(((struct sockaddr_un *)ss)->sun_path), hash_flags, param_type_addr); break; + case AF_CUST_ABNSZ: + { + const struct sockaddr_un *un = (struct sockaddr_un *)ss; + conn_hash_update(hash, + &un->sun_path, + 1 + strnlen2(un->sun_path + 1, sizeof(un->sun_path) - 1), + hash_flags, param_type_addr); + break; + } + case AF_CUST_SOCKPAIR: /* simply hash the fd */ conn_hash_update(hash, diff --git a/src/sock_unix.c b/src/sock_unix.c index 22ab862f5..0d00a15a4 100644 --- a/src/sock_unix.c +++ b/src/sock_unix.c @@ -362,7 +362,7 @@ int sock_unix_bind_receiver(struct receiver *rx, char **errmsg) goto bind_close_return; } - if (!ext && bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (!ext && bind(fd, (struct sockaddr *)&addr, get_addr_len(&rx->addr)) < 0) { /* note that bind() creates the socket on the file system */ if (errno == EADDRINUSE) { /* the old process might still own it, let's retry */