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).
This commit is contained in:
Willy Tarreau 2024-08-09 20:13:10 +02:00
parent d592ebdbeb
commit 2a799b64b0
6 changed files with 23 additions and 2 deletions

View File

@ -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 */

View File

@ -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 */
/*

View File

@ -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,
};

View File

@ -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,

View File

@ -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,

View File

@ -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,