From owner-svn-src-stable-12@freebsd.org Tue Sep 3 14:06:50 2019 Return-Path: Delivered-To: svn-src-stable-12@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 8AB60DD00C; Tue, 3 Sep 2019 14:06:50 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [96.47.72.132]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46N7zt0ZnLz4Pxr; Tue, 3 Sep 2019 14:06:50 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 1452) id A8FBB1AC56; Tue, 3 Sep 2019 14:06:18 +0000 (UTC) X-Original-To: yuripv@localmail.freebsd.org Delivered-To: yuripv@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 0A3F4130E8; Sun, 14 Apr 2019 10:38:58 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [96.47.72.132]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 59E908AAFF; Sun, 14 Apr 2019 10:38:58 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 538) id 1C5A7130C0; Sun, 14 Apr 2019 10:38:58 +0000 (UTC) Delivered-To: src-committers@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 0A0B5130BE for ; Sun, 14 Apr 2019 10:38:55 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id B93278AAFA; Sun, 14 Apr 2019 10:38:54 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 833181F3E9; Sun, 14 Apr 2019 10:38:54 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3EAcsHJ088751; Sun, 14 Apr 2019 10:38:54 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3EAcpmf088732; Sun, 14 Apr 2019 10:38:51 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201904141038.x3EAcpmf088732@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" 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 X-SVN-Group: stable-12 X-SVN-Commit-Author: ae X-SVN-Commit-Paths: in stable/12: sbin/ipfw sys/netinet6 sys/netpfil/ipfw sys/netpfil/ipfw/nat64 X-SVN-Commit-Revision: 346198 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk X-Loop: FreeBSD.org Sender: owner-src-committers@freebsd.org X-Rspamd-Queue-Id: 59E908AAFF X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.95 / 15.00]; local_wl_from(0.00)[freebsd.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.95)[-0.955,0]; ASN(0.00)[asn:11403, ipnet:96.47.64.0/20, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] Status: O X-BeenThere: svn-src-stable-12@freebsd.org X-Mailman-Version: 2.1.29 List-Id: SVN commit messages for only the 12-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Tue, 03 Sep 2019 14:06:51 -0000 X-Original-Date: Sun, 14 Apr 2019 10:38:51 +0000 (UTC) X-List-Received-Date: Tue, 03 Sep 2019 14:06:51 -0000 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 #include #include +#include #include #include @@ -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);