Index: sys/modules/ipfw_nat64/Makefile =================================================================== --- sys/modules/ipfw_nat64/Makefile +++ sys/modules/ipfw_nat64/Makefile @@ -7,6 +7,7 @@ SRCS+= nat64clat.c nat64clat_control.c SRCS+= nat64lsn.c nat64lsn_control.c SRCS+= nat64stl.c nat64stl_control.c +SRCS+= opt_ipstealth.h CFLAGS+= -I${SRCTOP}/sys/contrib/ck/include Index: sys/netpfil/ipfw/nat64/nat64_translate.c =================================================================== --- sys/netpfil/ipfw/nat64/nat64_translate.c +++ sys/netpfil/ipfw/nat64/nat64_translate.c @@ -29,6 +29,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ipstealth.h" + #include #include #include @@ -92,14 +94,29 @@ struct nat64_methods { nat64_output_t output; nat64_output_one_t output_one; + const int *ipstealth; + const int *ip6stealth; }; + +const int stealth_on = 1; +#ifndef IPSTEALTH +const int stealth_off = 0; +#endif static const struct nat64_methods nat64_netisr = { .output = nat64_output, - .output_one = nat64_output_one + .output_one = nat64_output_one, + /* Forwarding code will decrement TTL/HLIM */ + .ipstealth = &stealth_on, + .ip6stealth = &stealth_on, }; + static const struct nat64_methods nat64_direct = { .output = nat64_direct_output, - .output_one = nat64_direct_output_one + .output_one = nat64_direct_output_one, +#ifndef IPSTEALTH + .ipstealth = &stealth_off, + .ip6stealth = &stealth_off, +#endif /* IPSTEALTH */ }; VNET_DEFINE_STATIC(const struct nat64_methods *, nat64out) = &nat64_netisr; #define V_nat64out VNET(nat64out) @@ -109,6 +126,12 @@ { V_nat64out = direct != 0 ? &nat64_direct: &nat64_netisr; +#ifdef IPSTEALTH + if (direct != 0) { + V_nat64out->ipstealth = &V_ipstealth; + V_nat64out->ip6stealth = &V_ip6stealth; + } +#endif } int @@ -486,8 +509,7 @@ ip->ip_tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; ip->ip_len = htons(sizeof(*ip) + plen); ip->ip_ttl = ip6->ip6_hlim; - /* Forwarding code will decrement TTL for netisr based output. */ - if (V_nat64out == &nat64_direct) + if (*V_nat64out->ip6stealth == 0) ip->ip_ttl -= IPV6_HLIMDEC; ip->ip_sum = 0; ip->ip_p = (proto == IPPROTO_ICMPV6) ? IPPROTO_ICMP: proto; @@ -623,18 +645,18 @@ struct icmp6_hdr *icmp6; struct ip6_hdr *ip6, *oip6; struct mbuf *n; - int len, plen; + int len, plen, proto; len = 0; - plen = nat64_getlasthdr(m, &len); - if (plen < 0) { + proto = nat64_getlasthdr(m, &len); + if (proto < 0) { DPRINTF(DP_DROPS, "mbuf isn't contigious"); goto freeit; } /* * Do not send ICMPv6 in reply to ICMPv6 errors. */ - if (plen == IPPROTO_ICMPV6) { + if (proto == IPPROTO_ICMPV6) { if (m->m_len < len + sizeof(*icmp6)) { DPRINTF(DP_DROPS, "mbuf isn't contigious"); goto freeit; @@ -646,6 +668,21 @@ "ICMPv6 errors"); goto freeit; } + /* + * If there are extra headers between IPv6 and ICMPv6, + * strip off them. + */ + if (len > sizeof(struct ip6_hdr)) { + /* + * NOTE: ipfw_chk already did m_pullup() and it is + * expected that data is contigious from the start + * of IPv6 header up to the end of ICMPv6 header. + */ + bcopy(mtod(m, caddr_t), + mtodo(m, len - sizeof(struct ip6_hdr)), + sizeof(struct ip6_hdr)); + m_adj(m, len - sizeof(struct ip6_hdr)); + } } /* if (icmp6_ratelimit(&ip6->ip6_src, type, code)) @@ -687,7 +724,19 @@ n->m_len = n->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; oip6 = mtod(n, struct ip6_hdr *); - oip6->ip6_src = ip6->ip6_dst; + /* + * Make IPv6 source address selection for reflected datagram. + * nat64_check_ip6() doesn't allow scoped addresses, therefore + * we use zero scopeid. + */ + if (in6_selectsrc_addr(M_GETFIB(n), &ip6->ip6_src, 0, + n->m_pkthdr.rcvif, &oip6->ip6_src, NULL) != 0) { + /* + * Failed to find proper source address, drop the packet. + */ + m_freem(n); + goto freeit; + } oip6->ip6_dst = ip6->ip6_src; oip6->ip6_nxt = IPPROTO_ICMPV6; oip6->ip6_flow = 0; @@ -1182,7 +1231,7 @@ ip = mtod(m, struct ip*); - if (ip->ip_ttl <= IPTTLDEC) { + if (*V_nat64out->ipstealth == 0 && ip->ip_ttl <= IPTTLDEC) { nat64_icmp_reflect(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, &cfg->stats, logdata); return (NAT64RETURN); @@ -1229,8 +1278,7 @@ ip6.ip6_flow = htonl(ip->ip_tos << 20); ip6.ip6_vfc |= IPV6_VERSION; ip6.ip6_hlim = ip->ip_ttl; - /* Forwarding code will decrement TTL for netisr based output. */ - if (V_nat64out == &nat64_direct) + if (*V_nat64out->ipstealth == 0) ip6.ip6_hlim -= IPTTLDEC; ip6.ip6_plen = htons(plen); ip6.ip6_nxt = (proto == IPPROTO_ICMP) ? IPPROTO_ICMPV6: proto; @@ -1533,7 +1581,7 @@ return (NAT64MFREE); } - if (ip6->ip6_hlim <= IPV6_HLIMDEC) { + if (*V_nat64out->ip6stealth == 0 && ip6->ip6_hlim <= IPV6_HLIMDEC) { nat64_icmp6_reflect(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0, &cfg->stats, logdata); return (NAT64RETURN);