diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2025-12-02 15:02:05 +1100 |
|---|---|---|
| committer | Stefano Brivio <sbrivio@redhat.com> | 2025-12-02 23:07:14 +0100 |
| commit | b0523f6b0629358024e95b5d01dc81512cfa8e10 (patch) | |
| tree | 0b388c33fbbe187b93bac45b5976a4cfa979090c | |
| parent | 484dcfaa4057b43a262453de18b5e127a4920eb1 (diff) | |
| download | passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar.gz passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar.bz2 passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar.lz passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar.xz passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.tar.zst passt-b0523f6b0629358024e95b5d01dc81512cfa8e10.zip | |
inany: Let length of sockaddr_inany be implicit from the family
sockaddr_inany can contain either an IPv4 or IPv6 socket address, so the
relevant length for bind() or connect() can vary. In pif_sockaddr() we
return that length, and in sock_l4_sa() we take it as an extra parameter.
However, sockaddr_inany always contains exactly a sockaddr_in or a
sockaddr_in6 each with a fixed size. Therefore we can derive the relevant
length from the family, and don't need to pass it around separately.
Make a tiny helper to get the relevant address length, and update all
interfaces to use that approach instead.
In the process, fix a buglet in tcp_flow_repair_bind(): we passed
sizeof(union sockaddr_inany) to bind() instead of the specific length for
the address family. Since the sizeof() is always longer than the specific
length, this is probably fine, but not theoretically correct.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
| -rw-r--r-- | flow.c | 21 | ||||
| -rw-r--r-- | icmp.c | 3 | ||||
| -rw-r--r-- | inany.h | 17 | ||||
| -rw-r--r-- | pif.c | 15 | ||||
| -rw-r--r-- | pif.h | 2 | ||||
| -rw-r--r-- | tcp.c | 20 | ||||
| -rw-r--r-- | tcp_splice.c | 5 | ||||
| -rw-r--r-- | udp.c | 8 | ||||
| -rw-r--r-- | util.c | 8 | ||||
| -rw-r--r-- | util.h | 4 |
10 files changed, 52 insertions, 51 deletions
@@ -163,15 +163,13 @@ static void flowside_from_af(struct flowside *side, sa_family_t af, * @err: Filled in with errno if something failed * @type: Socket epoll type * @sa: Socket address - * @sl: Length of @sa */ struct flowside_sock_args { const struct ctx *c; int fd; int err; enum epoll_type type; - const struct sockaddr *sa; - socklen_t sl; + const union sockaddr_inany *sa; }; /** flowside_sock_splice() - Create and bind socket for PIF_SPLICE based on flowside @@ -185,8 +183,8 @@ static int flowside_sock_splice(void *arg) ns_enter(a->c); - a->fd = sock_l4_sa(a->c, a->type, a->sa, a->sl, NULL, - a->sa->sa_family == AF_INET6); + a->fd = sock_l4_sa(a->c, a->type, a->sa, NULL, + a->sa->sa_family == AF_INET6); a->err = errno; return 0; @@ -207,11 +205,10 @@ int flowside_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif, { const char *ifname = NULL; union sockaddr_inany sa; - socklen_t sl; ASSERT(pif_is_socket(pif)); - pif_sockaddr(c, &sa, &sl, pif, &tgt->oaddr, tgt->oport); + pif_sockaddr(c, &sa, pif, &tgt->oaddr, tgt->oport); switch (pif) { case PIF_HOST: @@ -222,13 +219,12 @@ int flowside_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif, else if (sa.sa_family == AF_INET6) ifname = c->ip6.ifname_out; - return sock_l4_sa(c, type, &sa, sl, ifname, + return sock_l4_sa(c, type, &sa, ifname, sa.sa_family == AF_INET6); case PIF_SPLICE: { struct flowside_sock_args args = { - .c = c, .type = type, - .sa = &sa.sa, .sl = sl, + .c = c, .type = type, .sa = &sa, }; NS_CALL(flowside_sock_splice, &args); errno = args.err; @@ -257,10 +253,9 @@ int flowside_connect(const struct ctx *c, int s, uint8_t pif, const struct flowside *tgt) { union sockaddr_inany sa; - socklen_t sl; - pif_sockaddr(c, &sa, &sl, pif, &tgt->eaddr, tgt->eport); - return connect(s, &sa.sa, sl); + pif_sockaddr(c, &sa, pif, &tgt->eaddr, tgt->eport); + return connect(s, &sa.sa, socklen_inany(&sa)); } /** flow_log_ - Log flow-related message @@ -312,8 +312,9 @@ int icmp_tap_handler(const struct ctx *c, uint8_t pif, sa_family_t af, ASSERT(flow_proto[pingf->f.type] == proto); pingf->ts = now->tv_sec; - pif_sockaddr(c, &sa, &msh.msg_namelen, PIF_HOST, &tgt->eaddr, 0); + pif_sockaddr(c, &sa, PIF_HOST, &tgt->eaddr, 0); msh.msg_name = &sa; + msh.msg_namelen = socklen_inany(&sa); msh.msg_iov = iov; msh.msg_iovlen = cnt; msh.msg_control = NULL; @@ -67,6 +67,23 @@ union sockaddr_inany { struct sockaddr_in6 sa6; }; +/** socklen_inany() - Get relevant address length for sockaddr_inany address + * @sa: sockaddr_inany socket address + * + * Return: socket address length for bind() or connect(), from IP family in @sa + */ +static inline socklen_t socklen_inany(const union sockaddr_inany *sa) +{ + switch (sa->sa_family) { + case AF_INET: + return sizeof(sa->sa4); + case AF_INET6: + return sizeof(sa->sa6); + default: + ASSERT(0); + } +} + /** inany_v4 - Extract IPv4 address, if present, from IPv[46] address * @addr: IPv4 or IPv6 address * @@ -30,12 +30,11 @@ static_assert(ARRAY_SIZE(pif_type_str) == PIF_NUM_TYPES, /** pif_sockaddr() - Construct a socket address suitable for an interface * @c: Execution context * @sa: Pointer to sockaddr to fill in - * @sl: Updated to relevant length of initialised @sa * @pif: Interface to create the socket address * @addr: IPv[46] address * @port: Port (host byte order) */ -void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, socklen_t *sl, +void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, uint8_t pif, const union inany_addr *addr, in_port_t port) { const struct in_addr *v4 = inany_v4(addr); @@ -47,7 +46,6 @@ void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, socklen_t *sl, sa->sa4.sin_addr = *v4; sa->sa4.sin_port = htons(port); memset(&sa->sa4.sin_zero, 0, sizeof(sa->sa4.sin_zero)); - *sl = sizeof(sa->sa4); } else { sa->sa_family = AF_INET6; sa->sa6.sin6_addr = addr->a6; @@ -57,7 +55,6 @@ void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, socklen_t *sl, else sa->sa6.sin6_scope_id = 0; sa->sa6.sin6_flowinfo = 0; - *sl = sizeof(sa->sa6); } } @@ -85,7 +82,6 @@ int pif_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif, .sa6.sin6_port = htons(port), }; union epoll_ref ref; - socklen_t sl; int ret; ASSERT(pif_is_socket(pif)); @@ -97,12 +93,11 @@ int pif_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif, } if (!addr) { - ref.fd = sock_l4_sa(c, type, &sa, sizeof(sa.sa6), - ifname, false); + ref.fd = sock_l4_sa(c, type, &sa, ifname, false); } else { - pif_sockaddr(c, &sa, &sl, pif, addr, port); - ref.fd = sock_l4_sa(c, type, &sa, sl, - ifname, sa.sa_family == AF_INET6); + pif_sockaddr(c, &sa, pif, addr, port); + ref.fd = sock_l4_sa(c, type, &sa, ifname, + sa.sa_family == AF_INET6); } if (ref.fd < 0) @@ -57,7 +57,7 @@ static inline bool pif_is_socket(uint8_t pif) return pif == PIF_HOST || pif == PIF_SPLICE; } -void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, socklen_t *sl, +void pif_sockaddr(const struct ctx *c, union sockaddr_inany *sa, uint8_t pif, const union inany_addr *addr, in_port_t port); int pif_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif, const union inany_addr *addr, const char *ifname, @@ -1472,12 +1472,11 @@ static void tcp_bind_outbound(const struct ctx *c, { const struct flowside *tgt = &conn->f.side[TGTSIDE]; union sockaddr_inany bind_sa; - socklen_t sl; - pif_sockaddr(c, &bind_sa, &sl, PIF_HOST, &tgt->oaddr, tgt->oport); + pif_sockaddr(c, &bind_sa, PIF_HOST, &tgt->oaddr, tgt->oport); if (!inany_is_unspecified(&tgt->oaddr) || tgt->oport) { - if (bind(s, &bind_sa.sa, sl)) { + if (bind(s, &bind_sa.sa, socklen_inany(&bind_sa))) { char sstr[INANY_ADDRSTRLEN]; flow_dbg_perror(conn, @@ -1537,7 +1536,6 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af, union flow *flow; int s = -1, mss; uint64_t hash; - socklen_t sl; if (!(flow = flow_alloc())) return; @@ -1570,7 +1568,7 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af, if ((s = tcp_conn_sock(af)) < 0) goto cancel; - pif_sockaddr(c, &sa, &sl, PIF_HOST, &tgt->eaddr, tgt->eport); + pif_sockaddr(c, &sa, PIF_HOST, &tgt->eaddr, tgt->eport); /* Use bind() to check if the target address is local (EADDRINUSE or * similar) and already bound, and set the LOCAL flag in that case. @@ -1582,7 +1580,7 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af, * * So, if bind() succeeds, close the socket, get a new one, and proceed. */ - if (bind(s, &sa.sa, sl)) { + if (bind(s, &sa.sa, socklen_inany(&sa))) { if (errno != EADDRNOTAVAIL && errno != EACCES) conn_flag(c, conn, LOCAL); } else { @@ -1622,7 +1620,7 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af, tcp_bind_outbound(c, conn, s); - if (connect(s, &sa.sa, sl)) { + if (connect(s, &sa.sa, socklen_inany(&sa))) { if (errno != EINPROGRESS) { tcp_rst(c, conn); goto cancel; @@ -1641,7 +1639,8 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af, tcp_epoll_ctl(c, conn); if (c->mode == MODE_VU) { /* To rebind to same oport after migration */ - sl = sizeof(sa); + socklen_t sl = sizeof(sa); + if (getsockname(s, &sa.sa, &sl) || inany_from_sockaddr(&tgt->oaddr, &tgt->oport, &sa) < 0) err_perror("Can't get local address for socket %i", s); @@ -3664,11 +3663,10 @@ static int tcp_flow_repair_bind(const struct ctx *c, struct tcp_tap_conn *conn) { const struct flowside *sockside = HOSTFLOW(conn); union sockaddr_inany a; - socklen_t sl; - pif_sockaddr(c, &a, &sl, PIF_HOST, &sockside->oaddr, sockside->oport); + pif_sockaddr(c, &a, PIF_HOST, &sockside->oaddr, sockside->oport); - if (bind(conn->sock, &a.sa, sizeof(a))) { + if (bind(conn->sock, &a.sa, socklen_inany(&a))) { int rc = -errno; flow_perror(conn, "Failed to bind socket for migrated flow"); return rc; diff --git a/tcp_splice.c b/tcp_splice.c index 5efd859..717766a 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -352,7 +352,6 @@ static int tcp_splice_connect(const struct ctx *c, struct tcp_splice_conn *conn) sa_family_t af = inany_v4(&tgt->eaddr) ? AF_INET : AF_INET6; uint8_t tgtpif = conn->f.pif[TGTSIDE]; union sockaddr_inany sa; - socklen_t sl; int one = 1; if (tgtpif == PIF_HOST) @@ -380,9 +379,9 @@ static int tcp_splice_connect(const struct ctx *c, struct tcp_splice_conn *conn) conn->s[1]); } - pif_sockaddr(c, &sa, &sl, tgtpif, &tgt->eaddr, tgt->eport); + pif_sockaddr(c, &sa, tgtpif, &tgt->eaddr, tgt->eport); - if (connect(conn->s[1], &sa.sa, sl)) { + if (connect(conn->s[1], &sa.sa, socklen_inany(&sa))) { if (errno != EINPROGRESS) { flow_trace(conn, "Couldn't connect socket for splice: %s", strerror_(errno)); @@ -780,7 +780,6 @@ static void udp_sock_to_sock(const struct ctx *c, int from_s, int n, const struct udp_flow *uflow = udp_at_sidx(tosidx); uint8_t topif = pif_at_sidx(tosidx); int to_s = uflow->s[tosidx.sidei]; - socklen_t sl; int i; if ((n = udp_sock_recv(c, from_s, udp_mh_recv, n)) <= 0) @@ -791,7 +790,7 @@ static void udp_sock_to_sock(const struct ctx *c, int from_s, int n, = udp_mh_recv[i].msg_len; } - pif_sockaddr(c, &udp_splice_to, &sl, topif, + pif_sockaddr(c, &udp_splice_to, topif, &toside->eaddr, toside->eport); sendmmsg(to_s, udp_mh_splice, n, MSG_NOSIGNAL); @@ -999,7 +998,6 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif, flow_sidx_t tosidx; in_port_t src, dst; uint8_t topif; - socklen_t sl; ASSERT(!c->no_udp); @@ -1041,7 +1039,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif, s = uflow->s[tosidx.sidei]; ASSERT(s >= 0); - pif_sockaddr(c, &to_sa, &sl, topif, &toside->eaddr, toside->eport); + pif_sockaddr(c, &to_sa, topif, &toside->eaddr, toside->eport); for (i = 0, j = 0; i < (int)p->count - idx && j < UIO_MAXIOV; i++) { const struct udphdr *uh_send; @@ -1054,7 +1052,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif, return p->count - idx; mm[i].msg_hdr.msg_name = &to_sa; - mm[i].msg_hdr.msg_namelen = sl; + mm[i].msg_hdr.msg_namelen = socklen_inany(&to_sa); if (data.cnt) { int cnt; @@ -44,17 +44,15 @@ * @c: Execution context * @type: epoll type * @sa: Socket address to bind to - * @sl: Length of @sa * @ifname: Interface for binding, NULL for any * @v6only: Set IPV6_V6ONLY socket option * * Return: newly created socket, negative error code on failure */ int sock_l4_sa(const struct ctx *c, enum epoll_type type, - const void *sa, socklen_t sl, - const char *ifname, bool v6only) + const union sockaddr_inany *sa, const char *ifname, bool v6only) { - sa_family_t af = ((const struct sockaddr *)sa)->sa_family; + sa_family_t af = sa->sa_family; bool freebind = false; int fd, y = 1, ret; uint8_t proto; @@ -147,7 +145,7 @@ int sock_l4_sa(const struct ctx *c, enum epoll_type type, } } - if (bind(fd, sa, sl) < 0) { + if (bind(fd, &sa->sa, socklen_inany(sa)) < 0) { /* We'll fail to bind to low ports if we don't have enough * capabilities, and we'll fail to bind on already bound ports, * this is fine. This might also fail for ICMP because of a @@ -206,10 +206,10 @@ int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags, #include "packet.h" struct ctx; +union sockaddr_inany; int sock_l4_sa(const struct ctx *c, enum epoll_type type, - const void *sa, socklen_t sl, - const char *ifname, bool v6only); + const union sockaddr_inany *sa, const char *ifname, bool v6only); int sock_unix(char *sock_path); void sock_probe_features(struct ctx *c); long timespec_diff_ms(const struct timespec *a, const struct timespec *b); |
