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

Reply via email to