svn commit: r366681 - head/sys/netpfil/ipfw/nat64

Andrey V. Elsukov ae at FreeBSD.org
Tue Oct 13 18:57:43 UTC 2020


Author: ae
Date: Tue Oct 13 18:57:42 2020
New Revision: 366681
URL: https://svnweb.freebsd.org/changeset/base/366681

Log:
  Add IPv4 fragments reassembling to NAT64LSN.
  
  NAT64LSN requires the presence of upper level protocol header
  in a IPv4 datagram to find corresponding state to make translation.
  Now it will be handled automatically by nat64lsn instance.
  
  Reviewed by:	melifaro
  Obtained from:	Yandex LLC
  MFC after:	1 week
  Sponsored by:	Yandex LLC
  Differential Revision:	https://reviews.freebsd.org/D26758

Modified:
  head/sys/netpfil/ipfw/nat64/nat64lsn.c

Modified: head/sys/netpfil/ipfw/nat64/nat64lsn.c
==============================================================================
--- head/sys/netpfil/ipfw/nat64/nat64lsn.c	Tue Oct 13 18:36:35 2020	(r366680)
+++ head/sys/netpfil/ipfw/nat64/nat64lsn.c	Tue Oct 13 18:57:42 2020	(r366681)
@@ -547,6 +547,57 @@ nat64lsn_get_state4to6(struct nat64lsn_cfg *cfg, struc
 	return (NULL);
 }
 
+/*
+ * Reassemble IPv4 fragments, make PULLUP if needed, get some ULP fields
+ * that might be unknown until reassembling is completed.
+ */
+static struct mbuf*
+nat64lsn_reassemble4(struct nat64lsn_cfg *cfg, struct mbuf *m,
+    uint16_t *port)
+{
+	struct ip *ip;
+	int len;
+
+	m = ip_reass(m);
+	if (m == NULL)
+		return (NULL);
+	/* IP header must be contigious after ip_reass() */
+	ip = mtod(m, struct ip *);
+	len = ip->ip_hl << 2;
+	switch (ip->ip_p) {
+	case IPPROTO_ICMP:
+		len += ICMP_MINLEN; /* Enough to get icmp_id */
+		break;
+	case IPPROTO_TCP:
+		len += sizeof(struct tcphdr);
+		break;
+	case IPPROTO_UDP:
+		len += sizeof(struct udphdr);
+		break;
+	default:
+		m_freem(m);
+		NAT64STAT_INC(&cfg->base.stats, noproto);
+		return (NULL);
+	}
+	if (m->m_len < len) {
+		m = m_pullup(m, len);
+		if (m == NULL) {
+			NAT64STAT_INC(&cfg->base.stats, nomem);
+			return (NULL);
+		}
+		ip = mtod(m, struct ip *);
+	}
+	switch (ip->ip_p) {
+	case IPPROTO_TCP:
+		*port = ntohs(L3HDR(ip, struct tcphdr *)->th_dport);
+		break;
+	case IPPROTO_UDP:
+		*port = ntohs(L3HDR(ip, struct udphdr *)->uh_dport);
+		break;
+	}
+	return (m);
+}
+
 static int
 nat64lsn_translate4(struct nat64lsn_cfg *cfg,
     const struct ipfw_flow_id *f_id, struct mbuf **mp)
@@ -566,6 +617,14 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg,
 	if (addr < cfg->prefix4 || addr > cfg->pmask4) {
 		NAT64STAT_INC(&cfg->base.stats, nomatch4);
 		return (cfg->nomatch_verdict);
+	}
+
+	/* Reassemble fragments if needed */
+	ret = ntohs(mtod(*mp, struct ip *)->ip_off);
+	if ((ret & (IP_MF | IP_OFFMASK)) != 0) {
+		*mp = nat64lsn_reassemble4(cfg, *mp, &port);
+		if (*mp == NULL)
+			return (IP_FW_DENY);
 	}
 
 	/* Check if protocol is supported */


More information about the svn-src-all mailing list