From nobody Sat Nov 13 23:16:57 2021 X-Original-To: dev-commits-src-branches@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 D74B31857226; Sat, 13 Nov 2021 23:16:57 +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 "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HsBDT5dwWz53T7; Sat, 13 Nov 2021 23:16:57 +0000 (UTC) (envelope-from git@FreeBSD.org) 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 9758A1BFB3; Sat, 13 Nov 2021 23:16:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1ADNGvdR005013; Sat, 13 Nov 2021 23:16:57 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1ADNGvsV005012; Sat, 13 Nov 2021 23:16:57 GMT (envelope-from git) Date: Sat, 13 Nov 2021 23:16:57 GMT Message-Id: <202111132316.1ADNGvsV005012@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: a50876f0ac7a - stable/12 - pf: ensure we have the correct source/destination IP address in ICMP errors List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@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/12 X-Git-Reftype: branch X-Git-Commit: a50876f0ac7a5839531c0c169cb1c88bc6e13389 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/12 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=a50876f0ac7a5839531c0c169cb1c88bc6e13389 commit a50876f0ac7a5839531c0c169cb1c88bc6e13389 Author: Luiz Otavio O Souza AuthorDate: 2021-10-19 11:37:54 +0000 Commit: Kristof Provost CommitDate: 2021-11-13 23:15:43 +0000 pf: ensure we have the correct source/destination IP address in ICMP errors When we route-to a packet that later turns out to not fit in the outbound interface MTU we generate an ICMP error. However, if we've already changed those (i.e. we've passed through a NAT rule) we have to undo the transformation first. Obtained from: pfSense MFC after: 3 weeks Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D32571 (cherry picked from commit ab238f14544b2415561c4fed674ee360aa8b5860) --- sys/netpfil/pf/pf.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index dd4c49959a60..5ec25baee419 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -314,6 +314,8 @@ static u_int pf_purge_expired_states(u_int, int); static void pf_purge_unlinked_rules(void); static int pf_mtag_uminit(void *, int, int); static void pf_mtag_free(struct m_tag *); +static void pf_packet_rework_nat(struct mbuf *, struct pf_pdesc *, + int, struct pf_state_key *); #ifdef INET static void pf_route(struct mbuf **, struct pf_krule *, int, struct ifnet *, struct pf_kstate *, @@ -335,6 +337,16 @@ extern struct proc *pf_purge_proc; VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]); +#define PACKET_UNDO_NAT(_m, _pd, _off, _s, _dir) \ + do { \ + struct pf_state_key *nk; \ + if ((_dir) == PF_OUT) \ + nk = (_s)->key[PF_SK_STACK]; \ + else \ + nk = (_s)->key[PF_SK_WIRE]; \ + pf_packet_rework_nat(_m, _pd, _off, nk); \ + } while (0) + #define PACKET_LOOPED(pd) ((pd)->pf_mtag && \ (pd)->pf_mtag->flags & PF_PACKET_LOOPED) @@ -439,6 +451,83 @@ pf_addr_cmp(struct pf_addr *a, struct pf_addr *b, sa_family_t af) return (0); } +static void +pf_packet_rework_nat(struct mbuf *m, struct pf_pdesc *pd, int off, + struct pf_state_key *nk) +{ + + switch (pd->proto) { + case IPPROTO_TCP: { + struct tcphdr *th = &pd->hdr.tcp; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) + pf_change_ap(m, pd->src, &th->th_sport, pd->ip_sum, + &th->th_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 0, pd->af); + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) + pf_change_ap(m, pd->dst, &th->th_dport, pd->ip_sum, + &th->th_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 0, pd->af); + m_copyback(m, off, sizeof(*th), (caddr_t)th); + break; + } + case IPPROTO_UDP: { + struct udphdr *uh = &pd->hdr.udp; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) + pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum, + &uh->uh_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) + pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum, + &uh->uh_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + break; + } + case IPPROTO_ICMP: { + struct icmp *ih = &pd->hdr.icmp; + + if (nk->port[pd->sidx] != ih->icmp_id) { + pd->hdr.icmp.icmp_cksum = pf_cksum_fixup( + ih->icmp_cksum, ih->icmp_id, + nk->port[pd->sidx], 0); + ih->icmp_id = nk->port[pd->sidx]; + pd->sport = &ih->icmp_id; + + m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih); + } + /* FALLTHROUGH */ + } + default: + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) { + switch (pd->af) { + case AF_INET: + pf_change_a(&pd->src->v4.s_addr, + pd->ip_sum, nk->addr[pd->sidx].v4.s_addr, + 0); + break; + case AF_INET6: + PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); + break; + } + } + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) { + switch (pd->af) { + case AF_INET: + pf_change_a(&pd->dst->v4.s_addr, + pd->ip_sum, nk->addr[pd->didx].v4.s_addr, + 0); + break; + case AF_INET6: + PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); + break; + } + } + break; + } +} + static __inline uint32_t pf_hashkey(struct pf_state_key *sk) { @@ -6021,6 +6110,11 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, error = EMSGSIZE; KMOD_IPSTAT_INC(ips_cantfrag); if (r->rt != PF_DUPTO) { + if (s && pd->nat_rule != NULL) + PACKET_UNDO_NAT(m0, pd, + (ip->ip_hl << 2) + (ip_off & IP_OFFMASK), + s, dir); + icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, ifp->if_mtu); goto done; @@ -6166,9 +6260,14 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, nd6_output_ifp(ifp, ifp, m0, &dst, NULL); else { in6_ifstat_inc(ifp, ifs6_in_toobig); - if (r->rt != PF_DUPTO) + if (r->rt != PF_DUPTO) { + if (s && pd->nat_rule != NULL) + PACKET_UNDO_NAT(m0, pd, + ((caddr_t)ip6 - m0->m_data) + + sizeof(struct ip6_hdr), s, dir); + icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); - else + } else goto bad; }