From nobody Wed Sep 04 08:53:29 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4WzGVd6Wt2z5TSG1; Wed, 04 Sep 2024 08:53:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4WzGVd4kWQz4XTc; Wed, 4 Sep 2024 08:53:29 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1725440009; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=n/lcJTB+Mj7Cb3Y5/RbSH0XHf3k78D3KxQkrPjIUrDs=; b=tn5NYzd4UXk3njwgDID+jin6zm5nBHYqwqGXbISLaTAs59ArqXBvc2xu9Dcek/f1lWXv2s 9lZAnKmtgyV846QeW0wkqK/zzlfuNkggM2mLcpoVtyTMxZk2/bMIzDo8gRybV0ZKuWQbTp /B8ukfwSR9vX2ioW7tZyJEiB8JtHvKS7mkqAqZrxkYx9SqGwA3nfzxrLNULruMX59cD+dh ke0UsW9EwcXV7f03vdCTJFf8jlPPkosFYPn8HAyE+EH1J8wxitDh4FUR/Qrhy3xhQ5z9MH UHcXrZhBK7UcIgxW1QHgCwC9+aev8Nq3bktPZsQC5vlBFFS1mWPuxgjSqNyWzg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1725440009; a=rsa-sha256; cv=none; b=TQXsG8EYGMgYiH4IVJFi/AlNtL+CQGKYxlfT2A9ayPH+QWIaxosCD4sK+VYR3MZ5wp1gMp SI+ehIq03PMenPPio8b8yJ+dU+ZxOPHzgSI7wNo3Jg8Lg8IpMnBp7A9FZz9+6p3FSOTcrA 7A5328al/fE5ZHo62xdg16e3ts9csot7jkNf0fyXorZ++8F/ptQ1DyVLNyQI8S1HIpNt1s aLOyv6NTev3OhnjDg8H8jlqcnq3ZF0ZLyJ8rAiXuybru0Guvp4VEADtY0Cur4nZNE5ViS3 kwg850c4Nm4SQL2rmyF3V31yNHdYiiv4kb5+4UL8RzMNSXCBdXlBRqzbgH5RYw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1725440009; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=n/lcJTB+Mj7Cb3Y5/RbSH0XHf3k78D3KxQkrPjIUrDs=; b=Qv3JvlU6vabJGALuDw2iMhOLMSxa18+voB9grIEn1WYuFp0rsqKZlORiofUNyVoRwb7WOM d1GRiAtlkZmXMf5Qtl5Mm6jd23d+H0fcoDIHYtMhf6K4fDnWq3t/XdHJZYxZuiQswaxb4N M8vTKOiPYP3IoWj3TAqbV115Y/pLi2LWFhrM/vu24HdhFvGLmanT7tV+Dpe3b1ZFfAZTpq itj+679F/yeihVU7CkcPMLLQf5xeYgpXNalRFNk81y3CNPp8Zuu1i7UkQuyBgfMgsRnZ0m gaCYTos/bWGnoX9m+kJsElo8YBBqG673ixUxOOvQRV+Hxs7atBGc4kgbdcLixA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4WzGVd4L0QzHnj; Wed, 4 Sep 2024 08:53:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4848rT14005402; Wed, 4 Sep 2024 08:53:29 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4848rTMp005393; Wed, 4 Sep 2024 08:53:29 GMT (envelope-from git) Date: Wed, 4 Sep 2024 08:53:29 GMT Message-Id: <202409040853.4848rTMp005393@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kristof Provost Subject: git: 0121a4baaca0 - stable/14 - pf: improve the ICMPv6 direction check List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 0121a4baaca09049d130d830aa9179e3cb9c9e88 Auto-Submitted: auto-generated The branch stable/14 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=0121a4baaca09049d130d830aa9179e3cb9c9e88 commit 0121a4baaca09049d130d830aa9179e3cb9c9e88 Author: Kristof Provost AuthorDate: 2024-08-26 12:59:38 +0000 Commit: Kristof Provost CommitDate: 2024-09-04 08:38:15 +0000 pf: improve the ICMPv6 direction check Following bluhm's advice this changes the way we setup state keys and perform state lookups for ICMPv6 Neighbor Discovery packets: - replace the NS-dst with ND target address; - replace the NA-src with ND target address; - replace the NA-dst with unspecified address if it is a multicast. This allows pf to match Address Resolution, Neighbor Unreachability Detection and Duplicate Address Detection packets to the corresponding states without the need to create new ones or match unrelated ones. As a side effect we're doing now one state table lookup for ND packets instead of two. Fixes a bug uncovered by one of the previous commits that virtually breaks IPv6 connectivity after few minutes of use. ok stsp henning, with and ok bluhm PR: 280701 MFC after: 1 week Obtained from: OpenBSD, mikeb , 2633ae8c4c8a Sponsored by: Rubicon Communications, LLC ("Netgate") (cherry picked from commit 5ab1e5f7e5585558a73b723f07528977a82cee82) --- sys/net/pfvar.h | 4 +- sys/netpfil/pf/pf.c | 116 ++++++++++++++++++++++++++++++++++--------------- sys/netpfil/pf/pf_lb.c | 2 +- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4e2888b21a39..d33c747efa7e 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2516,8 +2516,8 @@ struct pf_krule *pf_get_translation(struct pf_pdesc *, struct mbuf *, struct pf_addr *, struct pf_addr *, uint16_t, uint16_t, struct pf_kanchor_stackframe *); -struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct pf_addr *, - struct pf_addr *, u_int16_t, u_int16_t); +struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct mbuf *, int, + struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t); struct pf_state_key *pf_state_key_clone(const struct pf_state_key *); void pf_rule_to_actions(struct pf_krule *, struct pf_rule_actions *); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index fe3ae843f68a..62ee12322e8b 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -329,6 +329,9 @@ static int pf_create_state(struct pf_krule *, struct pf_krule *, u_int16_t, u_int16_t, int *, struct pfi_kkif *, struct pf_kstate **, int, u_int16_t, u_int16_t, int, struct pf_krule_slist *); +static int pf_state_key_addr_setup(struct pf_pdesc *, struct mbuf *, + int, struct pf_state_key_cmp *, int, struct pf_addr *, + int, struct pf_addr *, int); static int pf_test_fragment(struct pf_krule **, struct pfi_kkif *, struct mbuf *, void *, struct pf_pdesc *, struct pf_krule **, struct pf_kruleset **); @@ -345,7 +348,7 @@ static int pf_test_state_udp(struct pf_kstate **, void *, struct pf_pdesc *); int pf_icmp_state_lookup(struct pf_state_key_cmp *, struct pf_pdesc *, struct pf_kstate **, struct mbuf *, - int, struct pfi_kkif *, u_int16_t, u_int16_t, + int, int, struct pfi_kkif *, u_int16_t, u_int16_t, int, int *, int, int); static int pf_test_state_icmp(struct pf_kstate **, struct pfi_kkif *, struct mbuf *, int, @@ -399,7 +402,7 @@ extern struct proc *pf_purge_proc; VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]); -enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_SOLICITED, PF_ICMP_MULTI_LINK }; +enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_LINK }; #define PACKET_UNDO_NAT(_m, _pd, _off, _s) \ do { \ @@ -1466,9 +1469,66 @@ pf_state_key_ctor(void *mem, int size, void *arg, int flags) return (0); } +static int +pf_state_key_addr_setup(struct pf_pdesc *pd, struct mbuf *m, int off, + struct pf_state_key_cmp *key, int sidx, struct pf_addr *saddr, + int didx, struct pf_addr *daddr, int multi) +{ +#ifdef INET6 + struct nd_neighbor_solicit nd; + struct pf_addr *target; + u_short action, reason; + + if (pd->af == AF_INET || pd->proto != IPPROTO_ICMPV6) + goto copy; + + switch (pd->hdr.icmp6.icmp6_type) { + case ND_NEIGHBOR_SOLICIT: + if (multi) + return (-1); + if (!pf_pull_hdr(m, off, &nd, sizeof(nd), &action, &reason, pd->af)) + return (-1); + target = (struct pf_addr *)&nd.nd_ns_target; + daddr = target; + break; + case ND_NEIGHBOR_ADVERT: + if (multi) + return (-1); + if (!pf_pull_hdr(m, off, &nd, sizeof(nd), &action, &reason, pd->af)) + return (-1); + target = (struct pf_addr *)&nd.nd_ns_target; + saddr = target; + if (IN6_IS_ADDR_MULTICAST(&pd->dst->v6)) { + key->addr[didx].addr32[0] = 0; + key->addr[didx].addr32[1] = 0; + key->addr[didx].addr32[2] = 0; + key->addr[didx].addr32[3] = 0; + daddr = NULL; /* overwritten */ + } + break; + default: + if (multi == PF_ICMP_MULTI_LINK) { + key->addr[sidx].addr32[0] = IPV6_ADDR_INT32_MLL; + key->addr[sidx].addr32[1] = 0; + key->addr[sidx].addr32[2] = 0; + key->addr[sidx].addr32[3] = IPV6_ADDR_INT32_ONE; + saddr = NULL; /* overwritten */ + } + } +copy: +#endif + if (saddr) + PF_ACPY(&key->addr[sidx], saddr, pd->af); + if (daddr) + PF_ACPY(&key->addr[didx], daddr, pd->af); + + return (0); +} + struct pf_state_key * -pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr, - struct pf_addr *daddr, u_int16_t sport, u_int16_t dport) +pf_state_key_setup(struct pf_pdesc *pd, struct mbuf *m, int off, + struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t sport, + u_int16_t dport) { struct pf_state_key *sk; @@ -1476,8 +1536,12 @@ pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr, if (sk == NULL) return (NULL); - PF_ACPY(&sk->addr[pd->sidx], saddr, pd->af); - PF_ACPY(&sk->addr[pd->didx], daddr, pd->af); + if (pf_state_key_addr_setup(pd, m, off, (struct pf_state_key_cmp *)sk, + pd->sidx, pd->src, pd->didx, pd->dst, 0)) { + uma_zfree(V_pf_state_key_z, sk); + return (NULL); + } + sk->port[pd->sidx] = sport; sk->port[pd->didx] = dport; sk->proto = pd->proto; @@ -5163,7 +5227,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, if (nr == NULL) { KASSERT((sk == NULL && nk == NULL), ("%s: nr %p sk %p, nk %p", __func__, nr, sk, nk)); - sk = pf_state_key_setup(pd, pd->src, pd->dst, sport, dport); + sk = pf_state_key_setup(pd, m, off, pd->src, pd->dst, sport, dport); if (sk == NULL) goto csfailed; nk = sk; @@ -6605,9 +6669,9 @@ pf_multihome_scan_asconf(struct mbuf *m, int start, int len, int pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd, - struct pf_kstate **state, struct mbuf *m, int direction, struct pfi_kkif *kif, - u_int16_t icmpid, u_int16_t type, int icmp_dir, int *iidx, int multi, - int inner) + struct pf_kstate **state, struct mbuf *m, int off, int direction, + struct pfi_kkif *kif, u_int16_t icmpid, u_int16_t type, int icmp_dir, + int *iidx, int multi, int inner) { key->af = pd->af; key->proto = pd->proto; @@ -6620,25 +6684,9 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd, key->port[pd->sidx] = type; key->port[pd->didx] = icmpid; } - if (pd->af == AF_INET6 && multi != PF_ICMP_MULTI_NONE) { - switch (multi) { - case PF_ICMP_MULTI_SOLICITED: - key->addr[pd->sidx].addr32[0] = IPV6_ADDR_INT32_MLL; - key->addr[pd->sidx].addr32[1] = 0; - key->addr[pd->sidx].addr32[2] = IPV6_ADDR_INT32_ONE; - key->addr[pd->sidx].addr32[3] = pd->src->addr32[3]; - key->addr[pd->sidx].addr8[12] = 0xff; - break; - case PF_ICMP_MULTI_LINK: - key->addr[pd->sidx].addr32[0] = IPV6_ADDR_INT32_MLL; - key->addr[pd->sidx].addr32[1] = 0; - key->addr[pd->sidx].addr32[2] = 0; - key->addr[pd->sidx].addr32[3] = IPV6_ADDR_INT32_ONE; - break; - } - } else - PF_ACPY(&key->addr[pd->sidx], pd->src, key->af); - PF_ACPY(&key->addr[pd->didx], pd->dst, key->af); + if (pf_state_key_addr_setup(pd, m, off, key, pd->sidx, pd->src, + pd->didx, pd->dst, multi)) + return (PF_DROP); STATE_LOOKUP(kif, key, *state, pd); @@ -6701,7 +6749,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, * ICMP query/reply message not related to a TCP/UDP packet. * Search for an ICMP state. */ - ret = pf_icmp_state_lookup(&key, pd, state, m, pd->dir, + ret = pf_icmp_state_lookup(&key, pd, state, m, off, pd->dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 0); if (ret >= 0) { @@ -6709,7 +6757,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, icmp_dir == PF_OUT) { if (*state != NULL) PF_STATE_UNLOCK((*state)); - ret = pf_icmp_state_lookup(&key, pd, state, m, + ret = pf_icmp_state_lookup(&key, pd, state, m, off, pd->dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, multi, 0); if (ret >= 0) @@ -7117,7 +7165,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, pf_icmp_mapping(&pd2, iih->icmp_type, &icmp_dir, &multi, &virtual_id, &virtual_type); - ret = pf_icmp_state_lookup(&key, &pd2, state, m, + ret = pf_icmp_state_lookup(&key, &pd2, state, m, off, pd2.dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1); if (ret >= 0) @@ -7172,7 +7220,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, pf_icmp_mapping(&pd2, iih->icmp6_type, &icmp_dir, &multi, &virtual_id, &virtual_type); - ret = pf_icmp_state_lookup(&key, &pd2, state, m, + ret = pf_icmp_state_lookup(&key, &pd2, state, m, off, pd->dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1); if (ret >= 0) { @@ -7181,7 +7229,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, if (*state != NULL) PF_STATE_UNLOCK((*state)); ret = pf_icmp_state_lookup(&key, pd, - state, m, pd->dir, kif, + state, m, off, pd->dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, multi, 1); if (ret >= 0) diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 4fcad7e578a8..06c82569ad6c 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -633,7 +633,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, return (NULL); } - *skp = pf_state_key_setup(pd, saddr, daddr, sport, dport); + *skp = pf_state_key_setup(pd, m, off, saddr, daddr, sport, dport); if (*skp == NULL) return (NULL); *nkp = pf_state_key_clone(*skp);