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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to