svn commit: r366892 - stable/12/sys/netpfil/ipfw/nat64

Andrey V. Elsukov ae at FreeBSD.org
Tue Oct 20 11:40:38 UTC 2020


Author: ae
Date: Tue Oct 20 11:40:37 2020
New Revision: 366892
URL: https://svnweb.freebsd.org/changeset/base/366892

Log:
  MFC r366681:
    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.
  
    Obtained from:	Yandex LLC
    Sponsored by:	Yandex LLC

Modified:
  stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c	Tue Oct 20 09:51:41 2020	(r366891)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c	Tue Oct 20 11:40:37 2020	(r366892)
@@ -548,6 +548,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)
@@ -567,6 +618,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