From: Willy Tarreau Date: Fri, 9 Aug 2024 16:48:14 +0000 (+0200) Subject: MEDIUM: protocol: make abns a custom unix socket address family X-Git-Tag: v3.1-dev11~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=78ac312bbdaa3039f50710886c285ded31744152;p=thirdparty%2Fhaproxy.git 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= srv= 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= srv= 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 --- diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h index 42230acb80..9b3b7f5593 100644 --- a/include/haproxy/protocol-t.h +++ b/include/haproxy/protocol-t.h @@ -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) diff --git a/include/haproxy/sock_unix.h b/include/haproxy/sock_unix.h index 99343417e9..641fd823f3 100644 --- a/include/haproxy/sock_unix.h +++ b/include/haproxy/sock_unix.h @@ -29,6 +29,7 @@ #include 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); diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 0bade0fd19..a8d289e129 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -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; diff --git a/src/cli.c b/src/cli.c index aa3709c19c..c33b1b7264 100644 --- a/src/cli.c +++ b/src/cli.c @@ -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; diff --git a/src/connection.c b/src/connection.c index 2e766c896c..ea895963e8 100644 --- a/src/connection.c +++ b/src/connection.c @@ -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]) { diff --git a/src/extcheck.c b/src/extcheck.c index f01931b9d9..2c04dc7a22 100644 --- a/src/extcheck.c +++ b/src/extcheck.c @@ -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); } diff --git a/src/frontend.c b/src/frontend.c index 22270f2872..690ca1413b 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -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, diff --git a/src/hlua.c b/src/hlua.c index 89c26981c8..c8b42dc819 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -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; diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c index b13856e3d4..21a023828b 100644 --- a/src/hlua_fcn.c +++ b/src/hlua_fcn.c @@ -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); diff --git a/src/log.c b/src/log.c index 42e7663496..4b6c29c195 100644 --- a/src/log.c +++ b/src/log.c @@ -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 diff --git a/src/peers.c b/src/peers.c index 38ce54f08a..5b9390cbca 100644 --- a/src/peers.c +++ b/src/peers.c @@ -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; } diff --git a/src/proto_uxdg.c b/src/proto_uxdg.c index 068cb9e72a..32c9e45e92 100644 --- a/src/proto_uxdg.c +++ b/src/proto_uxdg.c @@ -65,7 +65,39 @@ struct protocol proto_uxdg = { .rx_unbind = sock_unbind, }; +/* Note: must not be declared 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 if the message is at most bytes long diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 51f508c31d..0ae2569b36 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -83,7 +83,48 @@ struct protocol proto_uxst = { .default_iocb = sock_accept_iocb, }; +/* Note: must not be declared 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 diff --git a/src/session.c b/src/session.c index 60cb8bf411..5dbbba8e5c 100644 --- a/src/session.c +++ b/src/session.c @@ -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)); diff --git a/src/sock_unix.c b/src/sock_unix.c index 510b4240b1..13e0c9146d 100644 --- a/src/sock_unix.c +++ b/src/sock_unix.c @@ -29,8 +29,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -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]) diff --git a/src/stats-proxy.c b/src/stats-proxy.c index 76a14fddee..de14e299c8 100644 --- a/src/stats-proxy.c +++ b/src/stats-proxy.c @@ -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: diff --git a/src/stream.c b/src/stream.c index 7eea4ca93f..0e84fab12d 100644 --- a/src/stream.c +++ b/src/stream.c @@ -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, diff --git a/src/tools.c b/src/tools.c index 49c273bb6c..572d12482b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -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;