There are a number of places where we want to handle either a sockaddr_in or a sockaddr_in6. In some of those we use a void *, which works ok and matches some standard library interfaces, but doesn't give a signature level hint that we're dealing with only sockaddr_in or sockaddr_in6, not (say) sockaddr_un or another type of socket address. Other places we use a sockaddr_storage, which also works, but has the same problem in addition to allocating more on the stack than we need to. Introduce union sockaddr_inany to explictly handle this case: it has variants for sockaddr_in and sockaddr_in6. Use it in a number of places where it's easy to do so. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- icmp.c | 18 ++++++------------ inany.h | 33 +++++++++++++++++++++------------ tcp.c | 11 +++++------ tcp_splice.c | 2 +- tcp_splice.h | 3 ++- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/icmp.c b/icmp.c index faa38c81..fb2fcafc 100644 --- a/icmp.c +++ b/icmp.c @@ -36,6 +36,8 @@ #include "passt.h" #include "tap.h" #include "log.h" +#include "siphash.h" +#include "inany.h" #include "icmp.h" #define ICMP_ECHO_TIMEOUT 60 /* s, timeout for ICMP socket activity */ @@ -67,13 +69,9 @@ void icmp_sock_handler(const struct ctx *c, sa_family_t af, union epoll_ref ref) struct icmp_id_sock *const id_sock = af == AF_INET ? &icmp_id_map[V4][ref.icmp.id] : &icmp_id_map[V6][ref.icmp.id]; const char *const pname = af == AF_INET ? "ICMP" : "ICMPv6"; - char buf[USHRT_MAX]; - union { - struct sockaddr sa; - struct sockaddr_in sa4; - struct sockaddr_in6 sa6; - } sr; + union sockaddr_inany sr; socklen_t sl = sizeof(sr); + char buf[USHRT_MAX]; uint16_t seq; ssize_t n; @@ -86,7 +84,7 @@ void icmp_sock_handler(const struct ctx *c, sa_family_t af, union epoll_ref ref) pname, strerror(errno)); return; } - if (sr.sa.sa_family != af) + if (sr.sa_family != af) goto unexpected; if (af == AF_INET) { @@ -214,11 +212,7 @@ int icmp_tap_handler(const struct ctx *c, uint8_t pif, sa_family_t af, const struct pool *p, const struct timespec *now) { const char *const pname = af == AF_INET ? "ICMP" : "ICMPv6"; - union { - struct sockaddr sa; - struct sockaddr_in sa4; - struct sockaddr_in6 sa6; - } sa = { .sa.sa_family = af }; + union sockaddr_inany sa = { .sa_family = af }; const socklen_t sl = af == AF_INET ? sizeof(sa.sa4) : sizeof(sa.sa6); struct icmp_id_sock *id_sock; uint16_t id, seq; diff --git a/inany.h b/inany.h index 4c4b36c3..ae6d9b25 100644 --- a/inany.h +++ b/inany.h @@ -9,6 +9,8 @@ #ifndef INANY_H #define INANY_H +struct siphash_state; + /** union inany_addr - Represents either an IPv4 or IPv6 address * @a6: Address as an IPv6 address, may be IPv4-mapped * @v4mapped.zero: All zero-bits for an IPv4 address @@ -41,6 +43,19 @@ extern const union inany_addr inany_any4; #define in4addr_loopback (inany_loopback4.v4mapped.a4) #define in4addr_any (inany_any4.v4mapped.a4) +/** union sockaddr_inany - Either a sockaddr_in or a sockaddr_in6 + * @sa_family: Address family, AF_INET or AF_INET6 + * @sa: Plain struct sockaddr (useful to avoid casts) + * @sa4: IPv4 socket address, valid if sa_family == AF_INET + * @sa6: IPv6 socket address, valid if sa_family == AF_INET6 + */ +union sockaddr_inany { + sa_family_t sa_family; + struct sockaddr sa; + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; +}; + /** inany_v4 - Extract IPv4 address, if present, from IPv[46] address * @addr: IPv4 or IPv6 address * @@ -137,23 +152,17 @@ static inline void inany_from_af(union inany_addr *aa, /** inany_from_sockaddr - Extract IPv[46] address and port number from sockaddr * @aa: Pointer to store IPv[46] address * @port: Pointer to store port number, host order - * @addr: struct sockaddr_in (IPv4) or struct sockaddr_in6 (IPv6) + * @addr: AF_INET or AF_INET6 socket address */ static inline void inany_from_sockaddr(union inany_addr *aa, in_port_t *port, - const void *addr) + const union sockaddr_inany *sa) { - const struct sockaddr *sa = (const struct sockaddr *)addr; - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; - - inany_from_af(aa, AF_INET6, &sa6->sin6_addr); - *port = ntohs(sa6->sin6_port); + inany_from_af(aa, AF_INET6, &sa->sa6.sin6_addr); + *port = ntohs(sa->sa6.sin6_port); } else if (sa->sa_family == AF_INET) { - struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; - - inany_from_af(aa, AF_INET, &sa4->sin_addr); - *port = ntohs(sa4->sin_port); + inany_from_af(aa, AF_INET, &sa->sa4.sin_addr); + *port = ntohs(sa->sa4.sin_port); } else { /* Not valid to call with other address families */ ASSERT(0); diff --git a/tcp.c b/tcp.c index 79b7b4d5..2bba3000 100644 --- a/tcp.c +++ b/tcp.c @@ -2666,7 +2666,7 @@ static void tcp_snat_inbound(const struct ctx *c, union inany_addr *addr) static void tcp_tap_conn_from_sock(struct ctx *c, union tcp_listen_epoll_ref ref, struct tcp_tap_conn *conn, int s, - const struct sockaddr *sa, + const union sockaddr_inany *sa, const struct timespec *now) { conn->f.type = FLOW_TCP; @@ -2702,7 +2702,7 @@ static void tcp_tap_conn_from_sock(struct ctx *c, void tcp_listen_handler(struct ctx *c, union epoll_ref ref, const struct timespec *now) { - struct sockaddr_storage sa; + union sockaddr_inany sa; socklen_t sl = sizeof(sa); union flow *flow; int s; @@ -2710,17 +2710,16 @@ void tcp_listen_handler(struct ctx *c, union epoll_ref ref, if (c->no_tcp || !(flow = flow_alloc())) return; - s = accept4(ref.fd, (struct sockaddr *)&sa, &sl, SOCK_NONBLOCK); + s = accept4(ref.fd, &sa.sa, &sl, SOCK_NONBLOCK); if (s < 0) goto cancel; if (c->mode == MODE_PASTA && tcp_splice_conn_from_sock(c, ref.tcp_listen, &flow->tcp_splice, - s, (struct sockaddr *)&sa)) + s, &sa)) return; - tcp_tap_conn_from_sock(c, ref.tcp_listen, &flow->tcp, s, - (struct sockaddr *)&sa, now); + tcp_tap_conn_from_sock(c, ref.tcp_listen, &flow->tcp, s, &sa, now); return; cancel: diff --git a/tcp_splice.c b/tcp_splice.c index 4ecc178b..9fd49412 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -438,7 +438,7 @@ static int tcp_splice_new(const struct ctx *c, struct tcp_splice_conn *conn, bool tcp_splice_conn_from_sock(const struct ctx *c, union tcp_listen_epoll_ref ref, struct tcp_splice_conn *conn, int s, - const struct sockaddr *sa) + const union sockaddr_inany *sa) { union inany_addr aany; in_port_t port; diff --git a/tcp_splice.h b/tcp_splice.h index 18193e4e..20f41b39 100644 --- a/tcp_splice.h +++ b/tcp_splice.h @@ -7,13 +7,14 @@ #define TCP_SPLICE_H struct tcp_splice_conn; +union sockaddr_inany; void tcp_splice_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events); bool tcp_splice_conn_from_sock(const struct ctx *c, union tcp_listen_epoll_ref ref, struct tcp_splice_conn *conn, int s, - const struct sockaddr *sa); + const union sockaddr_inany *sa); void tcp_splice_init(struct ctx *c); #endif /* TCP_SPLICE_H */ -- 2.43.0