From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202504 header.b=ZwW7HbB+; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id D6CC25A026F for ; Thu, 10 Apr 2025 09:16:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202504; t=1744269401; bh=NMKpnxvsNNIQoIZ2GzTVPLQ0tj4vfOZjf0D1S5uAblk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZwW7HbB+ixWwNYarjhwQHSG5FasigEqyd9Y6QnR9bepKed8YuAs0Te1TAWMiNYQrr IiD8KTHX/6uP23lKvf4UKUamUw494/qv0q8QI7AncJqqlOQCd3W8pSWsz7piUMp3NK F7ywEfvBE5OqXOQ+rYa5XZhbi9v5k0NwIILI2XgyDvDqF2zbbyxEYo3GdjDrfZHAkL Y+TZ2EVDD3Ij++uOZQVjTyjjnjL3LlLoqjle7xizBi/bm27pKPXVefFHdVdH+5LTuL MmrCjLmsy4IsRjJMSquTKdtLXtOmpqfG34a0KfSLS+pAxlgNHA+WvIux0NaCy9cevY mgPIE7zS0mGPg== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4ZYB2K4KNwz4x3S; Thu, 10 Apr 2025 17:16:41 +1000 (AEST) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH 1/3] udp: Use PKTINFO cmsgs to get destination address for received datagrams Date: Thu, 10 Apr 2025 17:16:38 +1000 Message-ID: <20250410071640.2310091-2-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250410071640.2310091-1-david@gibson.dropbear.id.au> References: <20250410071640.2310091-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: X5TTEN6QV43IE7LVAMLCPQGI4J3V3XUQ X-Message-ID-Hash: X5TTEN6QV43IE7LVAMLCPQGI4J3V3XUQ X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Currently we get the source address for received datagrams from recvmsg(), but we don't get the local destination address. Sometimes we implicitly know this because the receiving socket is bound to a specific address, but when listening on 0.0.0.0 or ::, we don't. We need this information to properly direct replies to flows which come in to a non-default local address. So, enable the IP_PKTINFO and IPV6_PKTINFO control messages to obtain this information in udp_peek_addr(). For now we log a trace messages but don't do anything more with the information. Signed-off-by: David Gibson --- udp.c | 37 +++++++++++++++++++++++++++++++++++-- util.c | 8 ++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/udp.c b/udp.c index ed6edc12..a71141a5 100644 --- a/udp.c +++ b/udp.c @@ -587,18 +587,29 @@ static int udp_sock_errs(const struct ctx *c, union epoll_ref ref) return n_err; } +#define PKTINFO_SPACE \ + MAX(CMSG_SPACE(sizeof(struct in_pktinfo)), \ + CMSG_SPACE(sizeof(struct in6_pktinfo))) + /** * udp_peek_addr() - Get source address for next packet * @s: Socket to get information from * @src: Socket address (output) + * @dst: (Local) destination address (output) * * Return: 0 on success, -1 otherwise */ -static int udp_peek_addr(int s, union sockaddr_inany *src) +static int udp_peek_addr(int s, union sockaddr_inany *src, + union inany_addr *dst) { + char sastr[SOCKADDR_STRLEN], dstr[INANY_ADDRSTRLEN]; + const struct cmsghdr *hdr; + char cmsg[PKTINFO_SPACE]; struct msghdr msg = { .msg_name = src, .msg_namelen = sizeof(*src), + .msg_control = cmsg, + .msg_controllen = sizeof(cmsg), }; int rc; @@ -608,6 +619,27 @@ static int udp_peek_addr(int s, union sockaddr_inany *src) warn_perror("Error peeking at socket address"); return rc; } + + hdr = CMSG_FIRSTHDR(&msg); + if (hdr && hdr->cmsg_level == IPPROTO_IP && + hdr->cmsg_type == IP_PKTINFO) { + const struct in_pktinfo *info4 = (void *)CMSG_DATA(hdr); + + *dst = inany_from_v4(info4->ipi_addr); + } else if (hdr && hdr->cmsg_level == IPPROTO_IPV6 && + hdr->cmsg_type == IPV6_PKTINFO) { + const struct in6_pktinfo *info6 = (void *)CMSG_DATA(hdr); + + dst->a6 = info6->ipi6_addr; + } else { + debug("Unexpected cmsg on UDP datagram"); + *dst = inany_any6; + } + + trace("Peeked UDP datagram: %s -> %s", + sockaddr_ntop(src, sastr, sizeof(sastr)), + inany_ntop(dst, dstr, sizeof(dstr))); + return 0; } @@ -702,8 +734,9 @@ void udp_sock_fwd(const struct ctx *c, int s, uint8_t frompif, in_port_t port, const struct timespec *now) { union sockaddr_inany src; + union inany_addr dst; - while (udp_peek_addr(s, &src) == 0) { + while (udp_peek_addr(s, &src, &dst) == 0) { flow_sidx_t tosidx = udp_flow_from_sock(c, frompif, port, &src, now); uint8_t topif = pif_at_sidx(tosidx); diff --git a/util.c b/util.c index 0f68cf57..62a6003e 100644 --- a/util.c +++ b/util.c @@ -109,11 +109,15 @@ int sock_l4_sa(const struct ctx *c, enum epoll_type type, debug("Failed to set SO_REUSEADDR on socket %i", fd); if (proto == IPPROTO_UDP) { + int pktinfo = af == AF_INET ? IP_PKTINFO : IPV6_RECVPKTINFO; + int recverr = af == AF_INET ? IP_RECVERR : IPV6_RECVERR; int level = af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; - int opt = af == AF_INET ? IP_RECVERR : IPV6_RECVERR; - if (setsockopt(fd, level, opt, &y, sizeof(y))) + if (setsockopt(fd, level, recverr, &y, sizeof(y))) die_perror("Failed to set RECVERR on socket %i", fd); + + if (setsockopt(fd, level, pktinfo, &y, sizeof(y))) + die_perror("Failed to set PKTINFO on socket %i", fd); } if (ifname && *ifname) { -- 2.49.0