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
MFC after:	1 month
Sponsored by:	Yandex LLC
This commit is contained in:
Andrey V. Elsukov 2019-03-18 10:39:14 +00:00
parent 783efeb544
commit b11efc1eb6
16 changed files with 183 additions and 103 deletions

View File

@ -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

View File

@ -288,6 +288,8 @@ enum tokens {
TOK_UDP_AGE,
TOK_ICMP_AGE,
TOK_LOGOFF,
TOK_PRIVATE,
TOK_PRIVATEOFF,
/* NPTv6 tokens */
TOK_NPTV6,

View File

@ -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, char **av)
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, char **av)
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 *name, uint8_t set)
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);
}

View File

@ -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, char *av[])
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, char **av)
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 *name, uint8_t set)
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);
}

View File

@ -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 */

View File

@ -148,8 +148,8 @@ ipfw_check_packet(struct mbuf **m0, struct ifnet *ifp, int flags,
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__));
ret = PFIL_PASS;
switch (ipfw) {

View File

@ -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)

View File

@ -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

View File

@ -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 *stats, void *logdata)
* 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 length)
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, in_addr_t ia)
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_addr_t ia,
#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, const struct in6_addr *ip6)
* 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, const struct in6_addr *ip6)
(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, const struct in6_addr *ip6)
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 @@ nat64_extract_ip4(const struct nat64_config *cfg, const struct in6_addr *ip6)
* 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 *ip6, uint16_t icmpid,
/* 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 aaddr, uint16_t aport,
/* 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, uint16_t aport,
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);

View File

@ -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, uint16_t aport,
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);

View File

@ -407,7 +407,7 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
} 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 ipfw_flow_id *f_id,
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;
}

View File

@ -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;

View File

@ -164,10 +164,10 @@ nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
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 nat64lsn_cfg *cfg,
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));
}

View File

@ -99,7 +99,9 @@ nat64stl_handle_ip4(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
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 nat64stl_cfg *cfg,
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 nat64stl_cfg *cfg,
*/
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_args *args,
if (ret == NAT64MFREE)
m_freem(args->m);
args->m = NULL;
return (IP_FW_DENY);
return (IP_FW_NAT64);
}

View File

@ -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];
};

View File

@ -99,8 +99,8 @@ nat64stl_export_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
{
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_opheader *op3,
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);