MEDIUM: protocol: make abns a custom unix socket address family

This is a pre-requisite to adding the abnsz socket address family:

in this patch we make use of protocol API rework started by 732913f
("MINOR: protocol: properly assign the sock_domain and sock_family") in
order to implement a dedicated address family for ABNS sockets (based on
UNIX parent family).

Thanks to this, it will become trivial to implement a new ABNSZ (for abns
zero) family which is essentially the same as ABNS but with a slight
difference when it comes to path handling (ABNS uses the whole sun_path
length, while ABNSZ's path is zero terminated and evaluation stops at 0)

It was verified that this patch doesn't break reg-tests and behaves
properly (tests performed on the CLI with show sess and show fd).

Anywhere relevant, AF_CUST_ABNS is handled alongside AF_UNIX. If no
distinction needs to be made, real_family() is used to fetch the proper
real family type to handle it properly.

Both stream and dgram were converted, so no functional change should be
expected for this "internal" rework, except that proto will be displayed
as "abns_{stream,dgram}" instead of "unix_{stream,dgram}".

Before ("show sess" output):
  0x64c35528aab0: proto=unix_stream src=unix:1 fe=GLOBAL be=<NONE> srv=<none> ts=00 epoch=0 age=0s calls=1 rate=0 cpu=0 lat=0 rq[f=848000h,i=0,an=00h,ax=] rp[f=80008000h,i=0,an=00h,ax=] scf=[8,0h,fd=21,rex=10s,wex=] scb=[8,1h,fd=-1,rex=,wex=] exp=10s rc=0 c_exp=

After:
  0x619da7ad74c0: proto=abns_stream src=unix:1 fe=GLOBAL be=<NONE> srv=<none> ts=00 epoch=0 age=0s calls=1 rate=0 cpu=0 lat=0 rq[f=848000h,i=0,an=00h,ax=] rp[f=80008000h,i=0,an=00h,ax=] scf=[8,0h,fd=22,rex=10s,wex=] scb=[8,1h,fd=-1,rex=,wex=] exp=10s rc=0 c_exp=

Co-authored-by: Aurelien DARRAGON <adarragon@haproxy.com>
This commit is contained in:
Willy Tarreau 2024-08-09 18:48:14 +02:00 committed by Aurelien DARRAGON
parent 596db3ef86
commit 78ac312bbd
18 changed files with 133 additions and 17 deletions

View File

@ -40,7 +40,8 @@ struct connection;
#define AF_CUST_EXISTING_FD (AF_MAX + 1)
#define AF_CUST_SOCKPAIR (AF_MAX + 2)
#define AF_CUST_RHTTP_SRV (AF_MAX + 3)
#define AF_CUST_MAX (AF_MAX + 4)
#define AF_CUST_ABNS (AF_MAX + 4)
#define AF_CUST_MAX (AF_MAX + 5)
/*
* Test in case AF_CUST_MAX overflows the sa_family_t (unsigned int)

View File

@ -29,6 +29,7 @@
#include <haproxy/receiver-t.h>
extern struct proto_fam proto_fam_unix;
extern struct proto_fam proto_fam_abns;
int sock_unix_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
int sock_unix_bind_receiver(struct receiver *rx, char **errmsg);

View File

@ -741,7 +741,10 @@ static inline int is_inet_addr(const struct sockaddr_storage *addr)
*/
static inline int is_addr(const struct sockaddr_storage *addr)
{
if (addr->ss_family == AF_UNIX || addr->ss_family == AF_CUST_SOCKPAIR)
/* WT: ideally we should use real_family(addr->ss_family) here, but we
* have so few custom addresses that it's simple enough to test them all.
*/
if (addr->ss_family == AF_UNIX || addr->ss_family == AF_CUST_ABNS || addr->ss_family == AF_CUST_SOCKPAIR)
return 1;
else
return is_inet_addr(addr);
@ -780,6 +783,7 @@ static inline int get_addr_len(const struct sockaddr_storage *addr)
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_UNIX:
case AF_CUST_ABNS:
return sizeof(struct sockaddr_un);
}
return 0;

View File

@ -655,7 +655,7 @@ int listeners_setenv(struct proxy *frontend, const char *varname)
if (trash->data)
chunk_appendf(trash, ";");
if (l->rx.addr.ss_family == AF_UNIX) {
if (l->rx.addr.ss_family == AF_UNIX || l->rx.addr.ss_family == AF_CUST_ABNS) {
const struct sockaddr_un *un;
un = (struct sockaddr_un *)&l->rx.addr;
@ -1461,6 +1461,7 @@ static int cli_io_handler_show_fd(struct appctx *appctx)
salen = sizeof(sa);
if (getsockname(fd, (struct sockaddr *)&sa, &salen) != -1) {
/* only real address families in .ss_family (as provided by getsockname) */
if (sa.ss_family == AF_INET)
chunk_appendf(&trash, " fam=ipv4 lport=%d", ntohs(((const struct sockaddr_in *)&sa)->sin_port));
else if (sa.ss_family == AF_INET6)
@ -1513,6 +1514,7 @@ static int cli_io_handler_show_fd(struct appctx *appctx)
salen = sizeof(sa);
if (getsockname(fd, (struct sockaddr *)&sa, &salen) != -1) {
/* only real address families in .ss_family (as provided by getsockname) */
if (sa.ss_family == AF_INET)
chunk_appendf(&trash, " fam=ipv4 lport=%d", ntohs(((const struct sockaddr_in *)&sa)->sin_port));
else if (sa.ss_family == AF_INET6)
@ -1582,7 +1584,7 @@ static int cli_io_handler_show_cli_sock(struct appctx *appctx)
char addr[46];
char port[6];
if (l->rx.addr.ss_family == AF_UNIX) {
if (l->rx.addr.ss_family == AF_UNIX || l->rx.addr.ss_family == AF_CUST_ABNS) {
const struct sockaddr_un *un;
un = (struct sockaddr_un *)&l->rx.addr;

View File

@ -2678,6 +2678,7 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
break;
case AF_UNIX:
case AF_CUST_ABNS:
un = (struct sockaddr_un *)ss;
if (un->sun_path[0]) {

View File

@ -304,7 +304,8 @@ int prepare_external_check(struct check *check)
port_to_str(&listener->rx.addr, buf, sizeof(buf));
check->argv[2] = strdup(buf);
}
else if (listener->rx.addr.ss_family == AF_UNIX) {
else if (listener->rx.addr.ss_family == AF_UNIX ||
listener->rx.addr.ss_family == AF_CUST_ABNS) {
const struct sockaddr_un *un;
un = (struct sockaddr_un *)&listener->rx.addr;
@ -412,6 +413,7 @@ static int connect_proc_chk(struct task *t)
extern char **environ;
struct rlimit limit;
int fd;
sa_family_t family;
/* close all FDs. Keep stdin/stdout/stderr in verbose mode */
fd = (global.mode & (MODE_QUIET|MODE_VERBOSE)) == MODE_QUIET ? 0 : 3;
@ -436,14 +438,15 @@ static int connect_proc_chk(struct task *t)
/* Update some environment variables and command args: curconn, server addr and server port */
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_CURCONN, ultoa_r(s->cur_sess, buf, sizeof(buf)), fail);
if (s->addr.ss_family == AF_UNIX) {
family = real_family(s->addr.ss_family);
if (family == AF_UNIX) {
const struct sockaddr_un *un = (struct sockaddr_un *)&s->addr;
strlcpy2(check->argv[3], un->sun_path, EXTCHK_SIZE_ADDR);
memcpy(check->argv[4], "NOT_USED", 9);
} else {
addr_to_str(&s->addr, check->argv[3], EXTCHK_SIZE_ADDR);
*check->argv[4] = 0; // just in case the address family changed
if (s->addr.ss_family == AF_INET || s->addr.ss_family == AF_INET6)
if (family == AF_INET || family == AF_INET6)
snprintf(check->argv[4], EXTCHK_SIZE_UINT, "%u", s->svc_port);
}

View File

@ -91,6 +91,7 @@ int frontend_accept(struct stream *s)
fe->id, (fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
break;
case AF_UNIX:
case AF_CUST_ABNS:
/* UNIX socket, only the destination is known */
send_log(fe, LOG_INFO, "Connect to unix:%d (%s/%s)\n",
l->luid,
@ -131,6 +132,7 @@ int frontend_accept(struct stream *s)
pn, get_host_port(src), alpn);
break;
case AF_UNIX:
case AF_CUST_ABNS:
/* UNIX socket, only the destination is known */
chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [unix:%d] ALPN=%s\n",
s->uniq_id, fe->id, (unsigned short)l->rx.fd, (unsigned short)conn->handle.fd,

View File

@ -3259,6 +3259,8 @@ __LJMP static inline int hlua_socket_info(struct lua_State *L, const struct sock
return 1;
}
ret = real_family(ret);
if (ret == AF_UNIX) {
lua_pushstring(L, buffer+1);
return 1;

View File

@ -1250,7 +1250,7 @@ int hlua_server_get_addr(lua_State *L)
luaL_buffinit(L, &b);
switch (srv->addr.ss_family) {
switch (real_family(srv->addr.ss_family)) {
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *)&srv->addr)->sin_addr,
addr, INET_ADDRSTRLEN);

View File

@ -2728,7 +2728,7 @@ static inline void __do_send_log(struct log_target *target, struct log_header hd
/* the socket's address is a file descriptor */
plogfd = (int *)&((struct sockaddr_in *)target->addr)->sin_addr.s_addr;
}
else if (target->addr->ss_family == AF_UNIX)
else if (real_family(target->addr->ss_family) == AF_UNIX)
plogfd = &logfdunix;
else
plogfd = &logfdinet;
@ -4168,7 +4168,7 @@ int sess_build_logline_orig(struct session *sess, struct stream *s,
addr = (s ? sc_src(s->scf) : sess_src(sess));
if (addr) {
/* sess->listener is always defined when the session's owner is an inbound connections */
if (addr->ss_family == AF_UNIX)
if (real_family(addr->ss_family) == AF_UNIX)
ret = lf_int(tmplog, dst + maxsize - tmplog,
sess->listener->luid, ctx, LF_INT_LTOA);
else
@ -4198,7 +4198,7 @@ int sess_build_logline_orig(struct session *sess, struct stream *s,
addr = (s ? sc_dst(s->scf) : sess_dst(sess));
if (addr) {
/* sess->listener is always defined when the session's owner is an inbound connections */
if (addr->ss_family == AF_UNIX)
if (real_family(addr->ss_family) == AF_UNIX)
ret = lf_int(tmplog, dst + maxsize - tmplog,
sess->listener->luid, ctx, LF_INT_LTOA);
else

View File

@ -4067,6 +4067,7 @@ static int peers_dump_peer(struct buffer *msg, struct appctx *appctx, struct pee
chunk_appendf(&trash, " src=%s:%d", pn, get_host_port(conn->src));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(&trash, " src=unix:%d", strm_li(peer_s)->luid);
break;
}
@ -4077,6 +4078,7 @@ static int peers_dump_peer(struct buffer *msg, struct appctx *appctx, struct pee
chunk_appendf(&trash, " addr=%s:%d", pn, get_host_port(conn->dst));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(&trash, " addr=unix:%d", strm_li(peer_s)->luid);
break;
}

View File

@ -65,7 +65,39 @@ struct protocol proto_uxdg = {
.rx_unbind = sock_unbind,
};
/* Note: must not be declared <const> as its list will be overwritten */
struct protocol proto_abns_dgram = {
.name = "abns_dgram",
/* connection layer */
.xprt_type = PROTO_TYPE_DGRAM,
.listen = uxdg_bind_listener,
.enable = uxdg_enable_listener,
.disable = uxdg_disable_listener,
.add = default_add_listener,
.unbind = default_unbind_listener,
.suspend = default_suspend_listener,
.resume = default_resume_listener,
/* binding layer */
.rx_suspend = uxdg_suspend_receiver,
/* address family */
.fam = &proto_fam_abns,
/* socket layer */
.proto_type = PROTO_TYPE_DGRAM,
.sock_type = SOCK_DGRAM,
.sock_prot = 0,
.rx_enable = sock_enable,
.rx_disable = sock_disable,
.rx_unbind = sock_unbind,
.receivers = LIST_HEAD_INIT(proto_abns_dgram.receivers),
.nb_receivers = 0,
};
INITCALL1(STG_REGISTER, protocol_register, &proto_uxdg);
INITCALL1(STG_REGISTER, protocol_register, &proto_abns_dgram);
/* This function tries to bind dgram unix socket listener. It may return a warning or
* an error message in <errmsg> if the message is at most <errlen> bytes long

View File

@ -83,7 +83,48 @@ struct protocol proto_uxst = {
.default_iocb = sock_accept_iocb,
};
/* Note: must not be declared <const> as its list will be overwritten */
struct protocol proto_abns_stream = {
.name = "abns_stream",
/* connection layer */
.xprt_type = PROTO_TYPE_STREAM,
.listen = uxst_bind_listener,
.enable = uxst_enable_listener,
.disable = uxst_disable_listener,
.add = default_add_listener,
.unbind = default_unbind_listener,
.suspend = default_suspend_listener,
.resume = default_resume_listener,
.accept_conn = sock_accept_conn,
.ctrl_init = sock_conn_ctrl_init,
.ctrl_close = sock_conn_ctrl_close,
.connect = uxst_connect_server,
.drain = sock_drain,
.check_events = sock_check_events,
.ignore_events = sock_ignore_events,
/* binding layer */
.rx_suspend = uxst_suspend_receiver,
/* address family */
.fam = &proto_fam_abns,
/* socket layer */
.proto_type = PROTO_TYPE_STREAM,
.sock_type = SOCK_STREAM,
.sock_prot = 0,
.rx_enable = sock_enable,
.rx_disable = sock_disable,
.rx_unbind = sock_unbind,
.rx_listening = sock_accepting_conn,
.default_iocb = sock_accept_iocb,
.nb_receivers = 0,
};
INITCALL1(STG_REGISTER, protocol_register, &proto_uxst);
INITCALL1(STG_REGISTER, protocol_register, &proto_abns_stream);
/********************************
* 1) low-level socket functions

View File

@ -395,7 +395,7 @@ static void session_prepare_log_prefix(struct session *sess, struct buffer *out)
ret = (src ? addr_to_str(src, pn, sizeof(pn)) : 0);
if (ret <= 0)
chunk_printf(out, "unknown [");
else if (ret == AF_UNIX)
else if (real_family(ret) == AF_UNIX)
chunk_printf(out, "%s:%d [", pn, sess->listener->luid);
else
chunk_printf(out, "%s:%d [", pn, get_host_port(src));

View File

@ -29,8 +29,9 @@
#include <haproxy/fd.h>
#include <haproxy/global.h>
#include <haproxy/listener.h>
#include <haproxy/receiver-t.h>
#include <haproxy/namespace.h>
#include <haproxy/protocol.h>
#include <haproxy/receiver-t.h>
#include <haproxy/sock.h>
#include <haproxy/sock_unix.h>
#include <haproxy/tools.h>
@ -49,6 +50,19 @@ struct proto_fam proto_fam_unix = {
.get_dst = sock_get_dst,
};
struct proto_fam proto_fam_abns = {
.name = "abns",
.sock_domain = AF_UNIX,
.sock_family = AF_CUST_ABNS,
.real_family = AF_UNIX,
.sock_addrlen = sizeof(struct sockaddr_un),
.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),
.addrcmp = sock_unix_addrcmp,
.bind = sock_unix_bind_receiver,
.get_src = sock_get_src,
.get_dst = sock_get_dst,
};
/* PLEASE NOTE for functions below:
*
* The address family SHOULD always be checked. In some cases a function will
@ -71,10 +85,10 @@ int sock_unix_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_st
const struct sockaddr_un *bu = (const struct sockaddr_un *)b;
int idx, dot, idx2;
if (a->ss_family != b->ss_family)
if (real_family(a->ss_family) != real_family(b->ss_family))
return -1;
if (a->ss_family != AF_UNIX)
if (real_family(a->ss_family) != AF_UNIX)
return -1;
if (au->sun_path[0] != bu->sun_path[0])

View File

@ -570,6 +570,7 @@ int stats_fill_li_line(struct proxy *px, struct listener *l, int flags,
chunk_appendf(out, "[%s]:%d", str, port);
break;
case AF_UNIX:
case AF_CUST_ABNS:
field = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
break;
case -1:
@ -1002,6 +1003,7 @@ int stats_fill_sv_line(struct proxy *px, struct server *sv, int flags,
chunk_appendf(out, "[%s]:%d", str, sv->svc_port);
break;
case AF_UNIX:
case AF_CUST_ABNS:
field = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
break;
case -1:

View File

@ -3294,6 +3294,7 @@ void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const ch
HA_ANON_STR(anon_key, pn), get_host_port(conn->src));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(buf, " source=unix:%d\n", strm_li(strm)->luid);
break;
default:
@ -3328,6 +3329,7 @@ void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const ch
HA_ANON_STR(anon_key, pn), get_host_port(conn->dst));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(buf, " addr=unix:%d\n", strm_li(strm)->luid);
break;
default:
@ -3352,6 +3354,7 @@ void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const ch
HA_ANON_STR(anon_key, pn), get_host_port(conn->src));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(buf, " addr=unix\n");
break;
default:
@ -3375,6 +3378,7 @@ void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const ch
HA_ANON_STR(anon_key, pn), get_host_port(conn->dst));
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(buf, " addr=unix\n");
break;
default:
@ -3809,6 +3813,7 @@ static int cli_io_handler_dump_sess(struct appctx *appctx)
);
break;
case AF_UNIX:
case AF_CUST_ABNS:
chunk_appendf(&trash,
" src=unix:%d fe=%s be=%s srv=%s",
strm_li(curr_strm)->luid,

View File

@ -1056,7 +1056,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
else if (strncmp(str2, "abns@", 5) == 0) {
str2 += 5;
abstract = 1;
ss.ss_family = AF_UNIX;
ss.ss_family = AF_CUST_ABNS;
}
else if (strncmp(str2, "ip@", 3) == 0) {
str2 += 3;
@ -1223,7 +1223,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int
goto out;
}
}
else if (ss.ss_family == AF_UNIX) {
else if (ss.ss_family == AF_UNIX || ss.ss_family == AF_CUST_ABNS) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
int prefix_path_len;
int max_path_len;
@ -1474,6 +1474,7 @@ char * sa2str(const struct sockaddr_storage *addr, int port, int map_ports)
ptr = &((struct sockaddr_in6 *)addr)->sin6_addr;
break;
case AF_UNIX:
case AF_CUST_ABNS:
path = ((struct sockaddr_un *)addr)->sun_path;
if (path[0] == '\0') {
const int max_length = sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path) - 1;
@ -1921,6 +1922,7 @@ int addr_to_str(const struct sockaddr_storage *addr, char *str, int size)
ptr = &((struct sockaddr_in6 *)addr)->sin6_addr;
break;
case AF_UNIX:
case AF_CUST_ABNS:
memcpy(str, "unix", 5);
return addr->ss_family;
default:
@ -1958,6 +1960,7 @@ int port_to_str(const struct sockaddr_storage *addr, char *str, int size)
port = ((struct sockaddr_in6 *)addr)->sin6_port;
break;
case AF_UNIX:
case AF_CUST_ABNS:
memcpy(str, "unix", 5);
return addr->ss_family;
default:
@ -6418,6 +6421,7 @@ const char *hash_ipanon(uint32_t scramble, char *ipstring, int hasport)
break;
case AF_UNIX:
case AF_CUST_ABNS:
return HA_ANON_STR(scramble, ipstring);
break;