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:
parent
783efeb544
commit
b11efc1eb6
@ -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
|
||||
|
@ -288,6 +288,8 @@ enum tokens {
|
||||
TOK_UDP_AGE,
|
||||
TOK_ICMP_AGE,
|
||||
TOK_LOGOFF,
|
||||
TOK_PRIVATE,
|
||||
TOK_PRIVATEOFF,
|
||||
|
||||
/* NPTv6 tokens */
|
||||
TOK_NPTV6,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user