aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/pf/pf_norm.c
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2024-11-22 15:30:25 +0000
committerKristof Provost <kp@FreeBSD.org>2024-12-17 10:07:16 +0000
commit7cae58a449559e7dca179129a37d971379d4e2c2 (patch)
tree139c304b7bf0519b97dc5d3d0b6777a2a0dfb0f6 /sys/netpfil/pf/pf_norm.c
parent6c5c91a039c77244dac38f638a8e2323ae78ff3d (diff)
pf: handle fragmentation for nat64
When we reassemble IPv4 packets tag them just like we tag the IPv6 reassembled packtes. Use this information as the basis for refragmenting the IPv6 packet. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D47804
Diffstat (limited to 'sys/netpfil/pf/pf_norm.c')
-rw-r--r--sys/netpfil/pf/pf_norm.c26
1 files changed, 19 insertions, 7 deletions
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index cea6f9e72638..4adace4c92cf 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -103,13 +103,6 @@ struct pf_fragment {
TAILQ_HEAD(pf_fragq, pf_frent) fr_queue;
};
-struct pf_fragment_tag {
- uint16_t ft_hdrlen; /* header length of reassembled pkt */
- uint16_t ft_extoff; /* last extension header offset or 0 */
- uint16_t ft_maxlen; /* maximum fragment payload length */
- uint32_t ft_id; /* fragment id */
-};
-
VNET_DEFINE_STATIC(struct mtx, pf_frag_mtx);
#define V_pf_frag_mtx VNET(pf_frag_mtx)
#define PF_FRAG_LOCK() mtx_lock(&V_pf_frag_mtx)
@@ -750,8 +743,12 @@ pf_reassemble(struct mbuf **m0, int dir, u_short *reason)
struct ip *ip = mtod(m, struct ip *);
struct pf_frent *frent;
struct pf_fragment *frag;
+ struct m_tag *mtag;
+ struct pf_fragment_tag *ftag;
struct pf_fragment_cmp key;
uint16_t total, hdrlen;
+ uint32_t frag_id;
+ uint16_t maxlen;
/* Get an entry for the fragment queue */
if ((frent = pf_create_fragment(reason)) == NULL)
@@ -784,6 +781,8 @@ pf_reassemble(struct mbuf **m0, int dir, u_short *reason)
TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_len;
hdrlen = frent->fe_hdrlen;
+ maxlen = frag->fr_maxlen;
+ frag_id = frag->fr_id;
m = *m0 = pf_join_fragment(frag);
frag = NULL;
@@ -795,6 +794,19 @@ pf_reassemble(struct mbuf **m0, int dir, u_short *reason)
m->m_pkthdr.len = plen;
}
+ if ((mtag = m_tag_get(PACKET_TAG_PF_REASSEMBLED,
+ sizeof(struct pf_fragment_tag), M_NOWAIT)) == NULL) {
+ REASON_SET(reason, PFRES_SHORT);
+ /* PF_DROP requires a valid mbuf *m0 in pf_test() */
+ return (PF_DROP);
+ }
+ ftag = (struct pf_fragment_tag *)(mtag + 1);
+ ftag->ft_hdrlen = hdrlen;
+ ftag->ft_extoff = 0;
+ ftag->ft_maxlen = maxlen;
+ ftag->ft_id = frag_id;
+ m_tag_prepend(m, mtag);
+
ip = mtod(m, struct ip *);
ip->ip_sum = pf_cksum_fixup(ip->ip_sum, ip->ip_len,
htons(hdrlen + total), 0);