commit fa708f56ec3dd0cdb2a07cf5298d37da27560db8 Author: Andrey V. Elsukov Date: Fri Sep 25 14:01:51 2020 +0300 [nat64] add IPv4 reassembling support diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.c b/sys/netpfil/ipfw/nat64/nat64lsn.c index 3b59c7f7414..9efa7e434e1 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn.c +++ b/sys/netpfil/ipfw/nat64/nat64lsn.c @@ -542,6 +542,57 @@ nat64lsn_get_state4to6(struct nat64lsn_cfg *cfg, struct nat64lsn_alias *alias, 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; + 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) @@ -563,6 +614,14 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, 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 */ switch (proto) { case IPPROTO_ICMP: