Skip to content

Commit 18582ed

Browse files
Tristan971Darlelet
andcommitted
MEDIUM: socket: add zero-terminated ABNS alternative
When an abstract unix socket is bound by HAProxy (using "abns@" prefix), NUL bytes are appended at the end of its path until sun_path is filled (for a total of 108 characters). Here we add an alternative to pass only the non-NUL length of that path to connect/bind calls, such that the effective path of the socket's name is as humanly written. This may be useful to interconnect with existing softwares that implement abstract sockets with this logic instead of the default haproxy one. This is achieved by implementing the "abnsz" socket prefix (instead of "abns"), which stands for "zero-terminated ABNS". "abnsz" prefix may be used anywhere "abns" is. Internally, haproxy uses the custom socket family (AF_CUST_ABNS vs AF_CUST_ABNSZ) to differentiate default abns sockets from zero-terminated ones. Documentation was updated and regtest was added. Fixes GH issues #977 and #2479 Co-authored-by: Aurelien DARRAGON <[email protected]>
1 parent 43861e3 commit 18582ed

File tree

5 files changed

+84
-13
lines changed

5 files changed

+84
-13
lines changed

doc/configuration.txt

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6073,6 +6073,11 @@ bind /<path> [, ...] [param*]
60736073
only in log-forward sections.
60746074
- 'unix@' -> address is a path to a local unix socket
60756075
- 'abns@' -> address is in abstract namespace (Linux only).
6076+
- 'abnsz@' -> address is in abstract namespace (Linux only)
6077+
but it is explicitly zero-terminated. This means no \0
6078+
padding is used to complete sun_path. It is useful to
6079+
interconnect with programs that don't implement the
6080+
default abns naming logic that haproxy uses.
60766081
- 'fd@<n>' -> use file descriptor <n> inherited from the
60776082
parent. The fd must be bound and may or may not already
60786083
be listening.
@@ -6165,11 +6170,12 @@ bind /<path> [, ...] [param*]
61656170
listen h3_quic_proxy
61666171
bind [email protected]:8888 ssl crt /etc/mycrt
61676172

6168-
Note: regarding Linux's abstract namespace sockets, HAProxy uses the whole
6169-
sun_path length is used for the address length. Some other programs
6170-
such as socat use the string length only by default. Pass the option
6171-
",unix-tightsocklen=0" to any abstract socket definition in socat to
6172-
make it compatible with HAProxy's.
6173+
Note: regarding Linux's abstract namespace sockets, "abns" HAProxy sockets
6174+
uses the whole sun_path length is used for the address length. Some
6175+
other programs such as socat use the string length only by default.
6176+
Pass the option ",unix-tightsocklen=0" to any abstract socket
6177+
definition in socat to make it compatible with HAProxy's, or use the
6178+
"abnsz" HAProxy socket family instead.
61736179

61746180
See also : "source", "option forwardfor", "unix-bind" and the PROXY protocol
61756181
documentation, and section 5 about bind options.
@@ -11586,6 +11592,11 @@ server <name> <address>[:[port]] [param*]
1158611592
- 'ipv6@' -> address is always IPv6
1158711593
- 'unix@' -> address is a path to a local unix socket
1158811594
- 'abns@' -> address is in abstract namespace (Linux only)
11595+
- 'abnsz@' -> address is in abstract namespace (Linux only)
11596+
but it is explicitly zero-terminated. This means no \0
11597+
padding is used to complete sun_path. It is useful to
11598+
interconnect with programs that don't implement the
11599+
default abns naming logic that haproxy uses.
1158911600
- 'sockpair@' -> address is the FD of a connected unix
1159011601
socket or of a socketpair. During a connection, the
1159111602
backend creates a pair of connected sockets, and passes
@@ -11620,11 +11631,12 @@ server <name> <address>[:[port]] [param*]
1162011631
server www1_dc1 "${LAN_DC1}.101:80"
1162111632
server www1_dc2 "${LAN_DC2}.101:80"
1162211633

11623-
Note: regarding Linux's abstract namespace sockets, HAProxy uses the whole
11624-
sun_path length is used for the address length. Some other programs
11625-
such as socat use the string length only by default. Pass the option
11626-
",unix-tightsocklen=0" to any abstract socket definition in socat to
11627-
make it compatible with HAProxy's.
11634+
Note: regarding Linux's abstract namespace sockets, "abns" HAProxy sockets
11635+
uses the whole sun_path length is used for the address length. Some
11636+
other programs such as socat use the string length only by default.
11637+
Pass the option ",unix-tightsocklen=0" to any abstract socket
11638+
definition in socat to make it compatible with HAProxy's, or use the
11639+
"abnsz" HAProxy socket family instead.
1162811640

1162911641
See also: "default-server", "http-send-name-header" and section 5 about
1163011642
server options
@@ -11721,6 +11733,9 @@ source <addr>[:<port>] [interface <name>]
1172111733
- 'ipv6@' -> address is always IPv6
1172211734
- 'unix@' -> address is a path to a local unix socket
1172311735
- 'abns@' -> address is in abstract namespace (Linux only)
11736+
- 'abnsz@' -> address is in zero-terminated abstract namespace
11737+
(Linux only)
11738+
1172411739
You may want to reference some environment variables in the
1172511740
address parameter, see section 2.3 about environment variables.
1172611741

@@ -28564,6 +28579,9 @@ socket type and the transport method.
2856428579

2856528580
'abns@<name>' following <name> is an abstract namespace (Linux only).
2856628581

28582+
'abnsz@<name>' following <name> is a zero-terminated abstract namespace
28583+
(Linux only).
28584+
2856728585
'fd@<n>' following address is a file descriptor <n> inherited from the
2856828586
parent. The fd must be bound and may or may not already be
2856928587
listening.

include/haproxy/tools.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,8 +785,15 @@ static inline int get_addr_len(const struct sockaddr_storage *addr)
785785
return sizeof(struct sockaddr_in6);
786786
case AF_UNIX:
787787
case AF_CUST_ABNS:
788-
case AF_CUST_ABNSZ:
789788
return sizeof(struct sockaddr_un);
789+
case AF_CUST_ABNSZ:
790+
{
791+
const struct sockaddr_un *un = (struct sockaddr_un *)addr;
792+
793+
/* stop at first NULL-byte */
794+
return offsetof(struct sockaddr_un, sun_path) + 1 +
795+
strnlen2(un->sun_path + 1, sizeof(un->sun_path) - 1);
796+
}
790797
}
791798
return 0;
792799
}

reg-tests/server/abnsz.vtc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
varnishtest "Abstract unix socket - zero terminated"
2+
feature ignore_unknown_macro
3+
feature cmd "command -v curl"
4+
5+
# abns@ sockets are not available on freebsd
6+
#EXCLUDE_TARGETS=freebsd,osx,generic
7+
#REGTEST_TYPE=devel
8+
9+
haproxy h1 -W -S -conf {
10+
global
11+
stats socket "${tmpdir}/h1/stats" level admin expose-fd listeners
12+
13+
defaults
14+
mode http
15+
log global
16+
option httplog
17+
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
18+
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
19+
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
20+
21+
listen testme
22+
bind "fd@${testme}"
23+
server f2 abnsz@hap-f2
24+
25+
frontend f2
26+
bind abnsz@hap-f2
27+
http-request return status 200 content-type text/plain string "ok"
28+
} -start
29+
30+
client c1 -connect ${h1_testme_sock} {
31+
txreq -url "/"
32+
rxresp
33+
} -run
34+
35+
shell {
36+
curl -sfS --abstract-unix-socket hap-f2 "http://host/" | grep "ok"
37+
}

src/connection.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2684,13 +2684,22 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
26842684
break;
26852685

26862686
case AF_CUST_ABNS:
2687-
case AF_CUST_ABNSZ:
26882687
conn_hash_update(hash,
26892688
&((struct sockaddr_un *)ss)->sun_path,
26902689
sizeof(((struct sockaddr_un *)ss)->sun_path),
26912690
hash_flags, param_type_addr);
26922691
break;
26932692

2693+
case AF_CUST_ABNSZ:
2694+
{
2695+
const struct sockaddr_un *un = (struct sockaddr_un *)ss;
2696+
conn_hash_update(hash,
2697+
&un->sun_path,
2698+
1 + strnlen2(un->sun_path + 1, sizeof(un->sun_path) - 1),
2699+
hash_flags, param_type_addr);
2700+
break;
2701+
}
2702+
26942703
case AF_CUST_SOCKPAIR:
26952704
/* simply hash the fd */
26962705
conn_hash_update(hash,

src/sock_unix.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ int sock_unix_bind_receiver(struct receiver *rx, char **errmsg)
362362
goto bind_close_return;
363363
}
364364

365-
if (!ext && bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
365+
if (!ext && bind(fd, (struct sockaddr *)&addr, get_addr_len(&rx->addr)) < 0) {
366366
/* note that bind() creates the socket <tempname> on the file system */
367367
if (errno == EADDRINUSE) {
368368
/* the old process might still own it, let's retry */

0 commit comments

Comments
 (0)