Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Apr 2019 10:38:51 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r346198 - in stable/12: sbin/ipfw sys/netinet6 sys/netpfil/ipfw sys/netpfil/ipfw/nat64
Message-ID:  <201904141038.x3EAcpmf088732@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sun Apr 14 10:38:50 2019
New Revision: 346198
URL: https://svnweb.freebsd.org/changeset/base/346198

Log:
  MFC r345262:
    Modify struct nat64_config.
  
    Add second IPv6 prefix to generic config structure and rename another
    fields to conform to RFC6877. Now it contains two prefixes and length:
    PLAT is provider-side translator that translates N:1 global IPv6 addresses
    to global IPv4 addresses. CLAT is customer-side translator (XLAT) that
    algorithmically translates 1:1 IPv4 addresses to global IPv6 addresses.
    Use PLAT prefix in stateless (nat64stl) and stateful (nat64lsn)
    translators.
  
    Modify nat64_extract_ip4() and nat64_embed_ip4() functions to accept
    prefix length and use plat_plen to specify prefix length.
  
    Retire net.inet.ip.fw.nat64_allow_private sysctl variable.
    Add NAT64_ALLOW_PRIVATE flag and use "allow_private" config option to
    configure this ability separately for each NAT64 instance.
  
    Obtained from:	Yandex LLC
    Sponsored by:	Yandex LLC

Modified:
  stable/12/sbin/ipfw/ipfw.8
  stable/12/sbin/ipfw/ipfw2.h
  stable/12/sbin/ipfw/nat64lsn.c
  stable/12/sbin/ipfw/nat64stl.c
  stable/12/sys/netinet6/ip_fw_nat64.h
  stable/12/sys/netpfil/ipfw/ip_fw_pfil.c
  stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.c
  stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.h
  stable/12/sys/netpfil/ipfw/nat64/nat64_translate.c
  stable/12/sys/netpfil/ipfw/nat64/nat64_translate.h
  stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c
  stable/12/sys/netpfil/ipfw/nat64/nat64lsn.h
  stable/12/sys/netpfil/ipfw/nat64/nat64lsn_control.c
  stable/12/sys/netpfil/ipfw/nat64/nat64stl.c
  stable/12/sys/netpfil/ipfw/nat64/nat64stl.h
  stable/12/sys/netpfil/ipfw/nat64/nat64stl_control.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sbin/ipfw/ipfw.8
==============================================================================
--- stable/12/sbin/ipfw/ipfw.8	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sbin/ipfw/ipfw.8	Sun Apr 14 10:38:50 2019	(r346198)
@@ -1,7 +1,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 1, 2019
+.Dd March 18, 2019
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -3413,6 +3413,14 @@ With
 you are able to see each handled packet before and after translation.
 .It Cm -log
 Turn off logging of all handled packets via BPF.
+.It Cm allow_private
+Turn on processing private IPv4 addresses. By default IPv6 packets with
+destinations mapped to private address ranges defined by RFC1918 are not
+processed.
+.It Cm -allow_private
+Turn off private address handling in
+.Nm nat64
+instance.
 .El
 .Pp
 To inspect a states table of stateful NAT64 the following command can be used:
@@ -3460,6 +3468,14 @@ Turn on logging of all handled packets via BPF through
 interface.
 .It Cm -log
 Turn off logging of all handled packets via BPF.
+.It Cm allow_private
+Turn on processing private IPv4 addresses. By default IPv6 packets with
+destinations mapped to private address ranges defined by RFC1918 are not
+processed.
+.It Cm -allow_private
+Turn off private address handling in
+.Nm nat64
+instance.
 .El
 .Pp
 Note that the behavior of stateless translator with respect to not matched
@@ -3948,16 +3964,6 @@ Default is no.
 Controls whether bridged packets are passed to
 .Nm .
 Default is no.
-.It Va net.inet.ip.fw.nat64_allow_private : No 0
-Defines how
-.Nm nat64
-handles private IPv4 addresses:
-.Bl -tag -width indent
-.It Cm 0
-Packets with private IPv4 will not be handled by translator
-.It Cm 1
-Translator will accept and process packets with private IPv4 addresses.
-.El
 .It Va net.inet.ip.fw.nat64_debug : No 0
 Controls debugging messages produced by
 .Nm ipfw_nat64

Modified: stable/12/sbin/ipfw/ipfw2.h
==============================================================================
--- stable/12/sbin/ipfw/ipfw2.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sbin/ipfw/ipfw2.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -288,6 +288,8 @@ enum tokens {
 	TOK_UDP_AGE,
 	TOK_ICMP_AGE,
 	TOK_LOGOFF,
+	TOK_PRIVATE,
+	TOK_PRIVATEOFF,
 
 	/* NPTv6 tokens */
 	TOK_NPTV6,

Modified: stable/12/sbin/ipfw/nat64lsn.c
==============================================================================
--- stable/12/sbin/ipfw/nat64lsn.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sbin/ipfw/nat64lsn.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -377,6 +377,8 @@ static struct _s_x nat64newcmds[] = {
       { "icmp_age",	TOK_ICMP_AGE },
       { "log",		TOK_LOG },
       { "-log",		TOK_LOGOFF },
+      { "allow_private", TOK_PRIVATE },
+      { "-allow_private", TOK_PRIVATEOFF },
       { NULL, 0 }
 };
 
@@ -522,6 +524,12 @@ nat64lsn_create(const char *name, uint8_t set, int ac,
 		case TOK_LOGOFF:
 			cfg->flags &= ~NAT64_LOG;
 			break;
+		case TOK_PRIVATE:
+			cfg->flags |= NAT64_ALLOW_PRIVATE;
+			break;
+		case TOK_PRIVATEOFF:
+			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
+			break;
 		}
 	}
 
@@ -627,6 +635,12 @@ nat64lsn_config(const char *name, uint8_t set, int ac,
 		case TOK_LOGOFF:
 			cfg->flags &= ~NAT64_LOG;
 			break;
+		case TOK_PRIVATE:
+			cfg->flags |= NAT64_ALLOW_PRIVATE;
+			break;
+		case TOK_PRIVATEOFF:
+			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
+			break;
 		default:
 			errx(EX_USAGE, "Can't change %s option", opt);
 		}
@@ -801,6 +815,8 @@ nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *n
 		printf(" icmp_age %u", cfg->st_icmp_ttl);
 	if (cfg->flags & NAT64_LOG)
 		printf(" log");
+	if (cfg->flags & NAT64_ALLOW_PRIVATE)
+		printf(" allow_private");
 	printf("\n");
 	return (0);
 }

Modified: stable/12/sbin/ipfw/nat64stl.c
==============================================================================
--- stable/12/sbin/ipfw/nat64stl.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sbin/ipfw/nat64stl.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -196,6 +196,8 @@ static struct _s_x nat64newcmds[] = {
       { "prefix6",	TOK_PREFIX6 },
       { "log",		TOK_LOG },
       { "-log",		TOK_LOGOFF },
+      { "allow_private", TOK_PRIVATE },
+      { "-allow_private", TOK_PRIVATEOFF },
       { NULL, 0 }
 };
 
@@ -263,6 +265,12 @@ nat64stl_create(const char *name, uint8_t set, int ac,
 		case TOK_LOGOFF:
 			cfg->flags &= ~NAT64_LOG;
 			break;
+		case TOK_PRIVATE:
+			cfg->flags |= NAT64_ALLOW_PRIVATE;
+			break;
+		case TOK_PRIVATEOFF:
+			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
+			break;
 		}
 	}
 
@@ -332,6 +340,12 @@ nat64stl_config(const char *name, uint8_t set, int ac,
 		case TOK_LOGOFF:
 			cfg->flags &= ~NAT64_LOG;
 			break;
+		case TOK_PRIVATE:
+			cfg->flags |= NAT64_ALLOW_PRIVATE;
+			break;
+		case TOK_PRIVATEOFF:
+			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
+			break;
 		default:
 			errx(EX_USAGE, "Can't change %s option", opt);
 		}
@@ -451,6 +465,8 @@ nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *n
 	printf(" prefix6 %s/%u", abuf, cfg->plen6);
 	if (cfg->flags & NAT64_LOG)
 		printf(" log");
+	if (cfg->flags & NAT64_ALLOW_PRIVATE)
+		printf(" allow_private");
 	printf("\n");
 	return (0);
 }

Modified: stable/12/sys/netinet6/ip_fw_nat64.h
==============================================================================
--- stable/12/sys/netinet6/ip_fw_nat64.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netinet6/ip_fw_nat64.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -40,7 +40,7 @@ struct ipfw_nat64stl_stats {
 	uint64_t	noroute4;
 	uint64_t	noroute6;
 	uint64_t	noproto;	/* Protocol not supported */
-	uint64_t	nomem;		/* mbuf allocation filed */
+	uint64_t	nomem;		/* mbuf allocation failed */
 	uint64_t	dropped;	/* dropped due to some errors */
 };
 
@@ -53,7 +53,7 @@ struct ipfw_nat64lsn_stats {
 	uint64_t	noroute4;
 	uint64_t	noroute6;
 	uint64_t	noproto;	/* Protocol not supported */
-	uint64_t	nomem;		/* mbuf allocation filed */
+	uint64_t	nomem;		/* mbuf allocation failed */
 	uint64_t	dropped;	/* dropped due to some errors */
 
 	uint64_t	nomatch4;	/* No addr/port match */
@@ -79,8 +79,10 @@ struct ipfw_nat64lsn_stats {
 	uint64_t	_reserved[4];
 };
 
-#define	NAT64_LOG	0x0001		/* Enable logging via BPF */
-
+#define	NAT64_LOG		0x0001	/* Enable logging via BPF */
+#define	NAT64_ALLOW_PRIVATE	0x0002	/* Allow private IPv4 address
+					 * translation
+					 */
 typedef struct _ipfw_nat64stl_cfg {
 	char		name[64];	/* NAT name			*/
 	ipfw_obj_ntlv	ntlv6;		/* object name tlv		*/

Modified: stable/12/sys/netpfil/ipfw/ip_fw_pfil.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/ip_fw_pfil.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/ip_fw_pfil.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -152,8 +152,8 @@ again:
 	ipfw = ipfw_chk(&args);
 	*m0 = args.m;
 
-	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
-	    __func__));
+	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY ||
+	    ipfw == IP_FW_NAT64, ("%s: m0 is NULL", __func__));
 
 	/* breaking out of the switch means drop */
 	switch (ipfw) {

Modified: stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -51,14 +51,10 @@ __FBSDID("$FreeBSD$");
 #include "nat64_translate.h"
 
 VNET_DEFINE(int, nat64_debug) = 0;
-VNET_DEFINE(int, nat64_allow_private) = 0;
 
 SYSCTL_DECL(_net_inet_ip_fw);
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_debug, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(nat64_debug), 0, "Debug level for NAT64 module");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_allow_private,
-    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(nat64_allow_private), 0,
-    "Allow use of non-global IPv4 addresses with NAT64");
 
 static int
 sysctl_direct_output(SYSCTL_HANDLER_ARGS)

Modified: stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.h
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/ip_fw_nat64.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -41,9 +41,7 @@
 #define	DP_ALL		0xFFFF
 
 VNET_DECLARE(int, nat64_debug);
-VNET_DECLARE(int, nat64_allow_private);
 #define	V_nat64_debug		VNET(nat64_debug)
-#define	V_nat64_allow_private	VNET(nat64_allow_private)
 
 #if 0
 #define	NAT64NOINLINE	__noinline

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64_translate.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64_translate.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64_translate.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet6/in6_var.h>
 #include <netinet6/in6_fib.h>
 #include <netinet6/ip6_var.h>
+#include <netinet6/ip_fw_nat64.h>
 
 #include <netpfil/pf/pf.h>
 #include <netpfil/ipfw/ip_fw_private.h>
@@ -241,7 +242,7 @@ nat64_output_one(struct mbuf *m, struct nat64_counters
  * Returns zero on success, otherwise EINVAL.
  */
 int
-nat64_check_prefix6(const struct in6_addr *prefix, int length)
+nat64_check_prefixlen(int length)
 {
 
 	switch (length) {
@@ -250,29 +251,40 @@ nat64_check_prefix6(const struct in6_addr *prefix, int
 	case 48:
 	case 56:
 	case 64:
-		/* Well-known prefix has 96 prefix length */
-		if (IN6_IS_ADDR_WKPFX(prefix))
-			return (EINVAL);
-		/* FALLTHROUGH */
 	case 96:
-		/* Bits 64 to 71 must be set to zero */
-		if (prefix->__u6_addr.__u6_addr8[8] != 0)
-			return (EINVAL);
-		/* Some extra checks */
-		if (IN6_IS_ADDR_MULTICAST(prefix) ||
-		    IN6_IS_ADDR_UNSPECIFIED(prefix) ||
-		    IN6_IS_ADDR_LOOPBACK(prefix))
-			return (EINVAL);
 		return (0);
 	}
 	return (EINVAL);
 }
 
 int
+nat64_check_prefix6(const struct in6_addr *prefix, int length)
+{
+
+	if (nat64_check_prefixlen(length) != 0)
+		return (EINVAL);
+
+	/* Well-known prefix has 96 prefix length */
+	if (IN6_IS_ADDR_WKPFX(prefix) && length != 96)
+		return (EINVAL);
+
+	/* Bits 64 to 71 must be set to zero */
+	if (prefix->__u6_addr.__u6_addr8[8] != 0)
+		return (EINVAL);
+
+	/* Some extra checks */
+	if (IN6_IS_ADDR_MULTICAST(prefix) ||
+	    IN6_IS_ADDR_UNSPECIFIED(prefix) ||
+	    IN6_IS_ADDR_LOOPBACK(prefix))
+		return (EINVAL);
+	return (0);
+}
+
+int
 nat64_check_private_ip4(const struct nat64_config *cfg, in_addr_t ia)
 {
 
-	if (V_nat64_allow_private)
+	if (cfg->flags & NAT64_ALLOW_PRIVATE)
 		return (0);
 
 	/* WKPFX must not be used to represent non-global IPv4 addresses */
@@ -301,29 +313,34 @@ nat64_check_private_ip4(const struct nat64_config *cfg
 	return (0);
 }
 
+/*
+ * Embed @ia IPv4 address into @ip6 IPv6 address.
+ * Place to embedding determined from prefix length @plen.
+ */
 void
-nat64_embed_ip4(const struct nat64_config *cfg, in_addr_t ia,
-    struct in6_addr *ip6)
+nat64_embed_ip4(struct in6_addr *ip6, int plen, in_addr_t ia)
 {
 
-	/* assume the prefix6 is properly filled with zeros */
-	bcopy(&cfg->prefix6, ip6, sizeof(*ip6));
-	switch (cfg->plen6) {
+	switch (plen) {
 	case 32:
 	case 96:
-		ip6->s6_addr32[cfg->plen6 / 32] = ia;
+		ip6->s6_addr32[plen / 32] = ia;
 		break;
 	case 40:
 	case 48:
 	case 56:
+		/*
+		 * Preserve prefix bits.
+		 * Since suffix bits should be zero and reserved for future
+		 * use, we just overwrite the whole word, where they are.
+		 */
+		ip6->s6_addr32[1] &= 0xffffffff << (32 - plen % 32);
 #if BYTE_ORDER == BIG_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
-		    (ia >> (cfg->plen6 % 32));
-		ip6->s6_addr32[2] = ia << (24 - cfg->plen6 % 32);
+		ip6->s6_addr32[1] |= ia >> (plen % 32);
+		ip6->s6_addr32[2] = ia << (24 - plen % 32);
 #elif BYTE_ORDER == LITTLE_ENDIAN
-		ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
-		    (ia << (cfg->plen6 % 32));
-		ip6->s6_addr32[2] = ia >> (24 - cfg->plen6 % 32);
+		ip6->s6_addr32[1] |= ia << (plen % 32);
+		ip6->s6_addr32[2] = ia >> (24 - plen % 32);
 #endif
 		break;
 	case 64:
@@ -336,13 +353,18 @@ nat64_embed_ip4(const struct nat64_config *cfg, in_add
 #endif
 		break;
 	default:
-		panic("Wrong plen6");
+		panic("Wrong plen: %d", plen);
 	};
+	/*
+	 * Bits 64 to 71 of the address are reserved for compatibility
+	 * with the host identifier format defined in the IPv6 addressing
+	 * architecture [RFC4291]. These bits MUST be set to zero.
+	 */
 	ip6->s6_addr8[8] = 0;
 }
 
 in_addr_t
-nat64_extract_ip4(const struct nat64_config *cfg, const struct in6_addr *ip6)
+nat64_extract_ip4(const struct in6_addr *ip6, int plen)
 {
 	in_addr_t ia;
 
@@ -353,7 +375,7 @@ nat64_extract_ip4(const struct nat64_config *cfg, cons
 	 * The suffix bits are reserved for future extensions and SHOULD
 	 * be set to zero.
 	 */
-	switch (cfg->plen6) {
+	switch (plen) {
 	case 32:
 		if (ip6->s6_addr32[3] != 0 || ip6->s6_addr32[2] != 0)
 			goto badip6;
@@ -377,20 +399,20 @@ nat64_extract_ip4(const struct nat64_config *cfg, cons
 		    (ip6->s6_addr32[3] & htonl(0x00ffffff)) != 0)
 			goto badip6;
 	};
-	switch (cfg->plen6) {
+	switch (plen) {
 	case 32:
 	case 96:
-		ia = ip6->s6_addr32[cfg->plen6 / 32];
+		ia = ip6->s6_addr32[plen / 32];
 		break;
 	case 40:
 	case 48:
 	case 56:
 #if BYTE_ORDER == BIG_ENDIAN
-		ia = (ip6->s6_addr32[1] << (cfg->plen6 % 32)) |
-		    (ip6->s6_addr32[2] >> (24 - cfg->plen6 % 32));
+		ia = (ip6->s6_addr32[1] << (plen % 32)) |
+		    (ip6->s6_addr32[2] >> (24 - plen % 32));
 #elif BYTE_ORDER == LITTLE_ENDIAN
-		ia = (ip6->s6_addr32[1] >> (cfg->plen6 % 32)) |
-		    (ip6->s6_addr32[2] << (24 - cfg->plen6 % 32));
+		ia = (ip6->s6_addr32[1] >> (plen % 32)) |
+		    (ip6->s6_addr32[2] << (24 - plen % 32));
 #endif
 		break;
 	case 64:
@@ -403,12 +425,9 @@ nat64_extract_ip4(const struct nat64_config *cfg, cons
 	default:
 		return (0);
 	};
-	if (nat64_check_ip4(ia) != 0 ||
-	    nat64_check_private_ip4(cfg, ia) != 0)
-		goto badip4;
+	if (nat64_check_ip4(ia) == 0)
+		return (ia);
 
-	return (ia);
-badip4:
 	DPRINTF(DP_GENERIC | DP_DROPS,
 	    "invalid destination address: %08x", ia);
 	return (0);
@@ -435,7 +454,7 @@ badip6:
  *	IPv6 to IPv4:	HC' = cksum_add(HC, result)
  *	IPv4 to IPv6:	HC' = cksum_add(HC, ~result)
  */
-static NAT64NOINLINE uint16_t
+static uint16_t
 nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip)
 {
 	uint32_t sum;
@@ -455,7 +474,7 @@ nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip
 	return (sum);
 }
 
-static NAT64NOINLINE void
+static void
 nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag,
     uint16_t plen, uint8_t proto, struct ip *ip)
 {
@@ -1025,9 +1044,11 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *i
 	/* Construct new inner IPv6 header */
 	eip6 = mtodo(n, offset + sizeof(struct icmp6_hdr));
 	eip6->ip6_src = ip6->ip6_dst;
-	/* Use the fact that we have single /96 prefix for IPv4 map */
+
+	/* Use the same prefix that we have in outer header */
 	eip6->ip6_dst = ip6->ip6_src;
-	nat64_embed_ip4(cfg, ip.ip_dst.s_addr, &eip6->ip6_dst);
+	MPASS(cfg->flags & NAT64_PLATPFX);
+	nat64_embed_ip4(&eip6->ip6_dst, cfg->plat_plen, ip.ip_dst.s_addr);
 
 	eip6->ip6_flow = htonl(ip.ip_tos << 20);
 	eip6->ip6_vfc |= IPV6_VERSION;
@@ -1450,7 +1471,9 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t 
 
 	/* Now we need to make a fake IPv4 packet to generate ICMP message */
 	ip.ip_dst.s_addr = aaddr;
-	ip.ip_src.s_addr = nat64_extract_ip4(cfg, &ip6i->ip6_src);
+	ip.ip_src.s_addr = nat64_extract_ip4(&ip6i->ip6_src, cfg->plat_plen);
+	if (ip.ip_src.s_addr == 0)
+		goto fail;
 	/* XXX: Make fake ulp header */
 	if (V_nat64out == &nat64_direct) /* init_ip4hdr will decrement it */
 		ip6i->ip6_hlim += IPV6_HLIMDEC;
@@ -1503,7 +1526,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui
 		return (NAT64MFREE);
 	}
 
-	ip.ip_dst.s_addr = nat64_extract_ip4(cfg, &ip6->ip6_dst);
+	ip.ip_dst.s_addr = nat64_extract_ip4(&ip6->ip6_dst, cfg->plat_plen);
 	if (ip.ip_dst.s_addr == 0) {
 		NAT64STAT_INC(&cfg->stats, dropped);
 		return (NAT64MFREE);

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64_translate.h
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64_translate.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64_translate.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -46,12 +46,12 @@ struct nat64_stats {
 					 * unsupported/etc.
 					 */
 
-	uint64_t	jrequests;	/* number of jobs requests queued */
-	uint64_t	jcalls;		/* number of jobs handler calls */
-	uint64_t	jhostsreq;	/* number of hosts requests */
-	uint64_t	jportreq;
-	uint64_t	jhostfails;
-	uint64_t	jportfails;
+	uint64_t	jrequests;	/* jobs requests queued */
+	uint64_t	jcalls;		/* jobs handler calls */
+	uint64_t	jhostsreq;	/* hosts requests */
+	uint64_t	jportreq;	/* PG allocation requests */
+	uint64_t	jhostfails;	/* hosts requests failed */
+	uint64_t	jportfails;	/* PG allocation failed */
 	uint64_t	jmaxlen;
 	uint64_t	jnomem;
 	uint64_t	jreinjected;
@@ -85,11 +85,24 @@ struct nat64_counters {
 #define	NAT64RETURN	1
 #define	NAT64MFREE	-1
 
+/*
+ * According to RFC6877:
+ *  PLAT is provider-side translator (XLAT) that translates N:1 global
+ *  IPv6 addresses to global IPv4 addresses, and vice versa.
+ *
+ *  CLAT is customer-side translator (XLAT) that algorithmically
+ *  translates 1:1 private IPv4 addresses to global IPv6 addresses,
+ *  and vice versa.
+ */
 struct nat64_config {
+	struct in6_addr		clat_prefix;
+	struct in6_addr		plat_prefix;
 	uint32_t		flags;
-#define	NAT64_WKPFX		0x00010000	/* prefix6 is WKPFX */
-	struct in6_addr		prefix6;
-	uint8_t			plen6;
+#define	NAT64_WKPFX		0x00010000	/* prefix is well-known */
+#define	NAT64_CLATPFX		0x00020000	/* dst prefix is configured */
+#define	NAT64_PLATPFX		0x00040000	/* src prefix is configured */
+	uint8_t			clat_plen;
+	uint8_t			plat_plen;
 
 	struct nat64_counters	stats;
 };
@@ -128,6 +141,7 @@ nat64_check_ip4(in_addr_t ia)
 	(a)->s6_addr32[1] == 0 && (a)->s6_addr32[2] == 0)
 
 int nat64_check_private_ip4(const struct nat64_config *cfg, in_addr_t ia);
+int nat64_check_prefixlen(int length);
 int nat64_check_prefix6(const struct in6_addr *prefix, int length);
 int nat64_getlasthdr(struct mbuf *m, int *offset);
 int nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
@@ -137,10 +151,8 @@ int nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr
     struct nat64_config *cfg, void *logdata);
 int nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr,
     uint16_t aport, struct nat64_config *cfg, void *logdata);
-void nat64_embed_ip4(const struct nat64_config *cfg, in_addr_t ia,
-    struct in6_addr *ip6);
-in_addr_t nat64_extract_ip4(const struct nat64_config *cfg,
-    const struct in6_addr *ip6);
+void nat64_embed_ip4(struct in6_addr *ip6, int plen, in_addr_t ia);
+in_addr_t nat64_extract_ip4(const struct in6_addr *ip6, int plen);
 
 void nat64_set_output_method(int);
 int nat64_get_output_method(void);

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64lsn.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -407,7 +407,7 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const st
 	} else
 		logdata = NULL;
 
-	nat64_embed_ip4(&cfg->base, htonl(f_id->src_ip), &src6);
+	nat64_embed_ip4(&src6, cfg->base.plat_plen, htonl(f_id->src_ip));
 	ret = nat64_do_handle_ip4(*pm, &src6, &nh->addr, lport,
 	    &cfg->base, logdata);
 
@@ -1481,8 +1481,10 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct i
 		return (nat64lsn_request_host(cfg, f_id, pm));
 
 	/* Fill-in on-stack state structure */
-	kst.u.s.faddr = nat64_extract_ip4(&cfg->base, &f_id->dst_ip6);
-	if (kst.u.s.faddr == 0) {
+	kst.u.s.faddr = nat64_extract_ip4(&f_id->dst_ip6,
+	    cfg->base.plat_plen);
+	if (kst.u.s.faddr == 0 ||
+	    nat64_check_private_ip4(&cfg->base, kst.u.s.faddr) != 0) {
 		NAT64STAT_INC(&cfg->base.stats, dropped);
 		goto drop;
 	}

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64lsn.h
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64lsn.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64lsn.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -216,7 +216,7 @@ struct nat64lsn_cfg {
 	uint16_t	st_icmp_ttl;	/* ICMP expire */
 	uint32_t	protochunks[NAT_MAX_PROTO];/* Number of chunks used */
 	struct nat64_config	base;
-#define	NAT64LSN_FLAGSMASK	(NAT64_LOG)
+#define	NAT64LSN_FLAGSMASK	(NAT64_LOG | NAT64_ALLOW_PRIVATE)
 
 	struct callout		periodic;
 	struct callout		jcallout;

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64lsn_control.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64lsn_control.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64lsn_control.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -164,10 +164,10 @@ nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheade
 	cfg->no.etlv = IPFW_TLV_NAT64LSN_NAME;
 	cfg->no.set = uc->set;
 
-	cfg->base.prefix6 = uc->prefix6;
-	cfg->base.plen6 = uc->plen6;
-	cfg->base.flags = uc->flags & NAT64LSN_FLAGSMASK;
-	if (IN6_IS_ADDR_WKPFX(&cfg->base.prefix6))
+	cfg->base.plat_prefix = uc->prefix6;
+	cfg->base.plat_plen = uc->plen6;
+	cfg->base.flags = (uc->flags & NAT64LSN_FLAGSMASK) | NAT64_PLATPFX;
+	if (IN6_IS_ADDR_WKPFX(&cfg->base.plat_prefix))
 		cfg->base.flags |= NAT64_WKPFX;
 
 	cfg->prefix4 = addr4;
@@ -324,9 +324,9 @@ nat64lsn_export_config(struct ip_fw_chain *ch, struct 
 	uc->st_udp_ttl = cfg->st_udp_ttl;
 	uc->st_icmp_ttl = cfg->st_icmp_ttl;
 	uc->prefix4.s_addr = htonl(cfg->prefix4);
-	uc->prefix6 = cfg->base.prefix6;
+	uc->prefix6 = cfg->base.plat_prefix;
 	uc->plen4 = cfg->plen4;
-	uc->plen6 = cfg->base.plen6;
+	uc->plen6 = cfg->base.plat_plen;
 	uc->set = cfg->no.set;
 	strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
 }

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64stl.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64stl.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64stl.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -99,7 +99,9 @@ nat64stl_handle_ip4(struct ip_fw_chain *chain, struct 
 	daddr = TARG_VAL(chain, tablearg, nh6);
 	if (nat64_check_ip6(&daddr) != 0)
 		return (NAT64MFREE);
-	nat64_embed_ip4(&cfg->base, ip->ip_src.s_addr, &saddr);
+
+	saddr = cfg->base.plat_prefix;
+	nat64_embed_ip4(&saddr, cfg->base.plat_plen, ip->ip_src.s_addr);
 	if (cfg->base.flags & NAT64_LOG) {
 		logdata = &loghdr;
 		nat64stl_log(logdata, m, AF_INET, cfg->no.kidx);
@@ -118,7 +120,10 @@ nat64stl_handle_ip6(struct ip_fw_chain *chain, struct 
 	uint32_t aaddr;
 
 	aaddr = htonl(TARG_VAL(chain, tablearg, nh4));
-
+	if (nat64_check_private_ip4(&cfg->base, aaddr) != 0) {
+		NAT64STAT_INC(&cfg->base.stats, dropped);
+		return (NAT64MFREE);
+	}
 	/*
 	 * NOTE: we expect ipfw_chk() did m_pullup() up to upper level
 	 * protocol's headers. Also we skip some checks, that ip6_input(),
@@ -126,7 +131,8 @@ nat64stl_handle_ip6(struct ip_fw_chain *chain, struct 
 	 */
 	ip6 = mtod(m, struct ip6_hdr *);
 	/* Check ip6_dst matches configured prefix */
-	if (bcmp(&ip6->ip6_dst, &cfg->base.prefix6, cfg->base.plen6 / 8) != 0)
+	if (memcmp(&ip6->ip6_dst, &cfg->base.plat_prefix,
+	    cfg->base.plat_plen / 8) != 0)
 		return (NAT64SKIP);
 
 	if (cfg->base.flags & NAT64_LOG) {
@@ -254,7 +260,7 @@ ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_
 	if (ret == NAT64MFREE)
 		m_freem(args->m);
 	args->m = NULL;
-	return (IP_FW_DENY);
+	return (IP_FW_NAT64);
 }
 
 

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64stl.h
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64stl.h	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64stl.h	Sun Apr 14 10:38:50 2019	(r346198)
@@ -43,7 +43,8 @@ struct nat64stl_cfg {
 #define	NAT64STL_KIDX		0x0100
 #define	NAT64STL_46T		0x0200
 #define	NAT64STL_64T		0x0400
-#define	NAT64STL_FLAGSMASK	(NAT64_LOG) /* flags to pass to userland */
+	/* flags to pass to userland */
+#define	NAT64STL_FLAGSMASK	(NAT64_LOG | NAT64_ALLOW_PRIVATE)
 	char			name[64];
 };
 

Modified: stable/12/sys/netpfil/ipfw/nat64/nat64stl_control.c
==============================================================================
--- stable/12/sys/netpfil/ipfw/nat64/nat64stl_control.c	Sun Apr 14 10:18:14 2019	(r346197)
+++ stable/12/sys/netpfil/ipfw/nat64/nat64stl_control.c	Sun Apr 14 10:38:50 2019	(r346198)
@@ -99,8 +99,8 @@ nat64stl_export_config(struct ip_fw_chain *ch, struct 
 {
 	struct named_object *no;
 
-	uc->prefix6 = cfg->base.prefix6;
-	uc->plen6 = cfg->base.plen6;
+	uc->prefix6 = cfg->base.plat_prefix;
+	uc->plen6 = cfg->base.plat_plen;
 	uc->flags = cfg->base.flags & NAT64STL_FLAGSMASK;
 	uc->set = cfg->no.set;
 	strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
@@ -206,10 +206,10 @@ nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheade
 	IPFW_UH_RUNLOCK(ch);
 
 	cfg = nat64stl_alloc_config(uc->name, uc->set);
-	cfg->base.prefix6 = uc->prefix6;
-	cfg->base.plen6 = uc->plen6;
-	cfg->base.flags = uc->flags & NAT64STL_FLAGSMASK;
-	if (IN6_IS_ADDR_WKPFX(&cfg->base.prefix6))
+	cfg->base.plat_prefix = uc->prefix6;
+	cfg->base.plat_plen = uc->plen6;
+	cfg->base.flags = (uc->flags & NAT64STL_FLAGSMASK) | NAT64_PLATPFX;
+	if (IN6_IS_ADDR_WKPFX(&cfg->base.plat_prefix))
 		cfg->base.flags |= NAT64_WKPFX;
 
 	IPFW_UH_WLOCK(ch);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904141038.x3EAcpmf088732>