From: Willy Tarreau Date: Fri, 9 Aug 2024 18:13:10 +0000 (+0200) Subject: MINOR: protocol: add the real address family to the protocol X-Git-Tag: v3.1-dev6~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a799b64b0ca8be08b50afa79c8efc674e49c91e;p=thirdparty%2Fhaproxy.git MINOR: protocol: add the real address family to the protocol For custom families, there's sometimes an underlying real address and it would be nice to be able to directly use the real family in calls to bind() and connect() without having to add explicit checks for exceptions everywhere. Let's add a .real_family field to struct proto_fam for this. For now it's always equal to the family except for non-transferable ones such as rhttp where it's equal to the custom one (anything else could fit). --- diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h index 838c7c31c1..42230acb80 100644 --- a/include/haproxy/protocol-t.h +++ b/include/haproxy/protocol-t.h @@ -74,8 +74,12 @@ enum proto_type { * permanent confusion between domain and family. Here's how it works: * - the domain defines the format of addresses (e.g. sockaddr_in etc), * it is passed as the first argument to socket() - * - the family is part of the address and is stored in receivers, servers - * and everywhere there is an address. It's also a proto_fam selector. + * - the socket family is part of the address and is stored in receivers, + * servers and everywhere there is an address. It's also a proto_fam + * selector. + * - the real family is the one passed to bind() and connect() to map + * custom families to their real equivalent one. + * * Domains are often PF_xxx though man 2 socket on Linux quotes 4.x BSD's man * that says AF_* can be used everywhere. At least it tends to keep the code * clearer about the intent. In HAProxy we're defining new address families @@ -86,6 +90,7 @@ struct proto_fam { char name[PROTO_NAME_LEN]; /* family name, zero-terminated */ int sock_domain; /* socket domain, as passed to socket() */ sa_family_t sock_family; /* socket family, for sockaddr */ + sa_family_t real_family; /* the socket family passed to syscalls */ ushort l3_addrlen; /* layer3 address length, used by hashes */ socklen_t sock_addrlen; /* socket address length, used by bind() */ /* 4-bytes hole here */ diff --git a/include/haproxy/protocol.h b/include/haproxy/protocol.h index a6c50ceb5f..475ac5ebb4 100644 --- a/include/haproxy/protocol.h +++ b/include/haproxy/protocol.h @@ -113,6 +113,17 @@ static inline const struct proto_fam *proto_fam_lookup(int ss_family) return NULL; } +/* returns either the real family when known or AF_UNSPEC for non-existing + * families. Note that real families that contain a custom value will be + * returned as-is. This aims at simplifying address validation tests everywhere. + */ +static inline int real_family(int ss_family) +{ + const struct proto_fam *fam = proto_fam_lookup(ss_family); + + return fam ? fam->real_family : AF_UNSPEC; +} + #endif /* _HAPROXY_PROTOCOL_H */ /* diff --git a/src/proto_rhttp.c b/src/proto_rhttp.c index e831a59365..ccd56cf854 100644 --- a/src/proto_rhttp.c +++ b/src/proto_rhttp.c @@ -24,6 +24,7 @@ struct proto_fam proto_fam_rhttp = { .name = "rhttp", .sock_domain = AF_INET, .sock_family = AF_CUST_RHTTP_SRV, + .real_family = AF_CUST_RHTTP_SRV, .bind = rhttp_bind_receiver, }; diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index 69ab45cfcb..00f817f6a0 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -52,6 +52,7 @@ struct proto_fam proto_fam_sockpair = { .name = "sockpair", .sock_domain = AF_UNIX, .sock_family = AF_CUST_SOCKPAIR, + .real_family = AF_CUST_SOCKPAIR, .sock_addrlen = sizeof(struct sockaddr_un), .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path), .addrcmp = NULL, diff --git a/src/sock_inet.c b/src/sock_inet.c index 028ffaa680..07364f02ae 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -35,6 +35,7 @@ struct proto_fam proto_fam_inet4 = { .name = "inet4", .sock_domain = PF_INET, .sock_family = AF_INET, + .real_family = AF_INET, .sock_addrlen = sizeof(struct sockaddr_in), .l3_addrlen = 32/8, .addrcmp = sock_inet4_addrcmp, @@ -48,6 +49,7 @@ struct proto_fam proto_fam_inet6 = { .name = "inet6", .sock_domain = PF_INET6, .sock_family = AF_INET6, + .real_family = AF_INET6, .sock_addrlen = sizeof(struct sockaddr_in6), .l3_addrlen = 128/8, .addrcmp = sock_inet6_addrcmp, diff --git a/src/sock_unix.c b/src/sock_unix.c index 0f9bc9a38d..510b4240b1 100644 --- a/src/sock_unix.c +++ b/src/sock_unix.c @@ -40,6 +40,7 @@ struct proto_fam proto_fam_unix = { .name = "unix", .sock_domain = PF_UNIX, .sock_family = AF_UNIX, + .real_family = AF_UNIX, .sock_addrlen = sizeof(struct sockaddr_un), .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path), .addrcmp = sock_unix_addrcmp,