Bring in some last changes in NAT64 implementation:

o Modify ipfw(8) to be able set any prefix6 not just Well-Known,
  and also show configured prefix6;
o relocate some definitions and macros into proper place;
o convert nat64_debug and nat64_allow_private variables to be
  VNET-compatible;
o add struct nat64_config that keeps generic configuration needed
  to NAT64 code;
o add nat64_check_prefix6() function to check validness of specified
  by user IPv6 prefix according to RFC6052;
o use nat64_check_private_ip4() and nat64_embed_ip4() functions
  instead of nat64_get_ip4() and nat64_set_ip4() macros. This allows
  to use any configured IPv6 prefixes that are allowed by RFC6052;
o introduce NAT64_WKPFX flag, that is set when IPv6 prefix is
  Well-Known IPv6 prefix. It is used to reduce overhead to check this;
o modify nat64lsn_cfg and nat64stl_cfg structures to use nat64_config
  structure. And respectivelly modify the rest of code;
o remove now unused ro argument from nat64_output() function;
o remove __FreeBSD_version ifdef, NAT64 was not merged to older versions;
o add commented -DIPFIREWALL_NAT64_DIRECT_OUTPUT flag to module's Makefile
  as example.

Obtained from:	Yandex LLC
MFC after:	1 month
Sponsored by:	Yandex LLC
This commit is contained in:
ae 2018-05-09 11:59:24 +00:00
parent 2149cb08d1
commit 68071c299a
14 changed files with 404 additions and 368 deletions

View File

@ -384,6 +384,7 @@ void ipfw_nat64lsn_handler(int ac, char *av[]);
void ipfw_nat64stl_handler(int ac, char *av[]);
void ipfw_nptv6_handler(int ac, char *av[]);
int ipfw_check_object_name(const char *name);
int ipfw_check_nat64prefix(const struct in6_addr *prefix, int length);
#ifdef PF
/* altq.c */

View File

@ -428,13 +428,17 @@ nat64lsn_create(const char *name, uint8_t set, int ac, char **av)
flags |= NAT64LSN_HAS_PREFIX4;
ac--; av++;
break;
#if 0
case TOK_PREFIX6:
NEED1("IPv6 prefix required");
nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
&cfg->plen6);
if (ipfw_check_nat64prefix(&cfg->prefix6,
cfg->plen6) != 0)
errx(EX_USAGE, "Bad prefix6 %s", *av);
ac--; av++;
break;
#if 0
case TOK_AGG_LEN:
NEED1("Aggregation prefix len required");
cfg->agg_prefix_len = nat64lsn_parse_int(*av, opt);
@ -767,10 +771,10 @@ nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set)
if (co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
inet_ntop(AF_INET, &cfg->prefix4, abuf, sizeof(abuf));
printf("nat64lsn %s prefix4 %s/%u ", cfg->name, abuf, cfg->plen4);
#if 0
printf("nat64lsn %s prefix4 %s/%u", cfg->name, abuf, cfg->plen4);
inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
printf("prefix6 %s/%u", abuf, cfg->plen6);
printf(" prefix6 %s/%u", abuf, cfg->plen6);
#if 0
printf("agg_len %u agg_count %u ", cfg->agg_prefix_len,
cfg->agg_prefix_max);
if (cfg->min_port != NAT64LSN_PORT_MIN ||

View File

@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip_fw_nat64.h>
#include <arpa/inet.h>
static int nat64stl_check_prefix(struct in6_addr *prefix, int length);
typedef int (nat64stl_cb_t)(ipfw_nat64stl_cfg *i, const char *name,
uint8_t set);
static int nat64stl_foreach(nat64stl_cb_t *f, const char *name, uint8_t set,
@ -80,13 +79,10 @@ static struct _s_x nat64cmds[] = {
((a)->__u6_addr.__u6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == 0)
static int
nat64stl_check_prefix(struct in6_addr *prefix, int length)
int
ipfw_check_nat64prefix(const struct in6_addr *prefix, int length)
{
if (IN6_IS_ADDR_WKPFX(prefix) && length == 96)
return (0);
#if 0
switch (length) {
case 32:
case 40:
@ -95,21 +91,20 @@ nat64stl_check_prefix(struct in6_addr *prefix, int length)
case 64:
/* Well-known prefix has 96 prefix length */
if (IN6_IS_ADDR_WKPFX(prefix))
return (1);
return (EINVAL);
/* FALLTHROUGH */
case 96:
/* Bits 64 to 71 must be set to zero */
if (prefix->__u6_addr.__u6_addr8[8] != 0)
return (1);
return (EINVAL);
/* XXX: looks incorrect */
if (IN6_IS_ADDR_MULTICAST(prefix) ||
IN6_IS_ADDR_UNSPECIFIED(prefix) ||
IN6_IS_ADDR_LOOPBACK(prefix))
return (1);
return (EINVAL);
return (0);
}
#endif
return (1);
return (EINVAL);
}
static struct _s_x nat64statscmds[] = {
@ -255,7 +250,7 @@ nat64stl_create(const char *name, uint8_t set, int ac, char *av[])
errx(EX_USAGE,
"Bad prefix: %s", *av);
cfg->plen6 = strtol(p, NULL, 10);
if (nat64stl_check_prefix(&cfg->prefix6,
if (ipfw_check_nat64prefix(&cfg->prefix6,
cfg->plen6) != 0)
errx(EX_USAGE,
"Bad prefix length: %s", p);
@ -439,6 +434,7 @@ nat64stl_reset_stats(const char *name, uint8_t set)
static int
nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *name, uint8_t set)
{
char abuf[INET6_ADDRSTRLEN];
if (name != NULL && strcmp(cfg->name, name) != 0)
return (ESRCH);
@ -448,8 +444,11 @@ nat64stl_show_cb(ipfw_nat64stl_cfg *cfg, const char *name, uint8_t set)
if (co.use_set != 0 || cfg->set != 0)
printf("set %u ", cfg->set);
printf("nat64stl %s table4 %s table6 %s",
cfg->name, cfg->ntlv4.name, cfg->ntlv6.name);
inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
printf(" prefix6 %s/%u", abuf, cfg->plen6);
if (cfg->flags & NAT64_LOG)
printf(" log");
printf("\n");

View File

@ -8,4 +8,6 @@ SRCS+= nat64lsn.c nat64lsn_control.c
SRCS+= nat64stl.c nat64stl_control.c
SRCS+= opt_ipfw.h
#CFLAGS+= -DIPFIREWALL_NAT64_DIRECT_OUTPUT
.include <bsd.kmod.mk>

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2015-2016 Yandex LLC
* Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
* Copyright (c) 2015-2018 Yandex LLC
* Copyright (c) 2015-2018 Andrey V. Elsukov <ae@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -46,18 +46,17 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_fw.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64_translate.h>
#include "ip_fw_nat64.h"
VNET_DEFINE(int, nat64_debug) = 0;
VNET_DEFINE(int, nat64_allow_private) = 0;
int nat64_debug = 0;
SYSCTL_DECL(_net_inet_ip_fw);
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_debug, CTLFLAG_RW,
&nat64_debug, 0, "Debug level for NAT64 module");
int nat64_allow_private = 0;
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, nat64_allow_private, CTLFLAG_RW,
&nat64_allow_private, 0,
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

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2015-2016 Yandex LLC
* Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
* Copyright (c) 2015-2018 Yandex LLC
* Copyright (c) 2015-2018 Andrey V. Elsukov <ae@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,7 +31,7 @@
#define _IP_FW_NAT64_H_
#define DPRINTF(mask, fmt, ...) \
if (nat64_debug & (mask)) \
if (V_nat64_debug & (mask)) \
printf("NAT64: %s: " fmt "\n", __func__, ## __VA_ARGS__)
#define DP_GENERIC 0x0001
#define DP_OBJ 0x0002
@ -39,7 +39,11 @@
#define DP_STATE 0x0008
#define DP_DROPS 0x0010
#define DP_ALL 0xFFFF
extern int nat64_debug;
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
@ -47,71 +51,9 @@ extern int nat64_debug;
#define NAT64NOINLINE
#endif
int nat64stl_init(struct ip_fw_chain *ch, int first);
void nat64stl_uninit(struct ip_fw_chain *ch, int last);
int nat64lsn_init(struct ip_fw_chain *ch, int first);
void nat64lsn_uninit(struct ip_fw_chain *ch, int last);
struct ip_fw_nat64_stats {
counter_u64_t opcnt64; /* 6to4 of packets translated */
counter_u64_t opcnt46; /* 4to6 of packets translated */
counter_u64_t ofrags; /* number of fragments generated */
counter_u64_t ifrags; /* number of fragments received */
counter_u64_t oerrors; /* number of output errors */
counter_u64_t noroute4;
counter_u64_t noroute6;
counter_u64_t nomatch4; /* No addr/port match */
counter_u64_t noproto; /* Protocol not supported */
counter_u64_t nomem; /* mbufs allocation failed */
counter_u64_t dropped; /* number of packets silently
* dropped due to some errors/
* unsupported/etc.
*/
counter_u64_t jrequests; /* number of jobs requests queued */
counter_u64_t jcalls; /* number of jobs handler calls */
counter_u64_t jhostsreq; /* number of hosts requests */
counter_u64_t jportreq;
counter_u64_t jhostfails;
counter_u64_t jportfails;
counter_u64_t jmaxlen;
counter_u64_t jnomem;
counter_u64_t jreinjected;
counter_u64_t screated;
counter_u64_t sdeleted;
counter_u64_t spgcreated;
counter_u64_t spgdeleted;
};
#define IPFW_NAT64_VERSION 1
#define NAT64STATS (sizeof(struct ip_fw_nat64_stats) / sizeof(uint64_t))
typedef struct _nat64_stats_block {
counter_u64_t stats[NAT64STATS];
} nat64_stats_block;
#define NAT64STAT_ADD(s, f, v) \
counter_u64_add((s)->stats[ \
offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)], (v))
#define NAT64STAT_INC(s, f) NAT64STAT_ADD(s, f, 1)
#define NAT64STAT_FETCH(s, f) \
counter_u64_fetch((s)->stats[ \
offsetof(struct ip_fw_nat64_stats, f) / sizeof(uint64_t)])
#define L3HDR(_ip, _t) ((_t)((u_int32_t *)(_ip) + (_ip)->ip_hl))
#define TCP(p) ((struct tcphdr *)(p))
#define UDP(p) ((struct udphdr *)(p))
#define ICMP(p) ((struct icmphdr *)(p))
#define ICMP6(p) ((struct icmp6_hdr *)(p))
#define NAT64SKIP 0
#define NAT64RETURN 1
#define NAT64MFREE -1
/* Well-known prefix 64:ff9b::/96 */
#define IPV6_ADDR_INT32_WKPFX htonl(0x64ff9b)
#define IN6_IS_ADDR_WKPFX(a) \
((a)->s6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
(a)->s6_addr32[1] == 0 && (a)->s6_addr32[2] == 0)
#endif
int nat64stl_init(struct ip_fw_chain *ch, int first);
void nat64stl_uninit(struct ip_fw_chain *ch, int last);
int nat64lsn_init(struct ip_fw_chain *ch, int first);
void nat64lsn_uninit(struct ip_fw_chain *ch, int last);
#endif /* _IP_FW_NAT64_H_ */

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2015-2016 Yandex LLC
* Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
* Copyright (c) 2015-2018 Yandex LLC
* Copyright (c) 2015-2018 Andrey V. Elsukov <ae@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -66,10 +66,11 @@ __FBSDID("$FreeBSD$");
#include <netpfil/pf/pf.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64_translate.h>
#include <machine/in_cksum.h>
#include "ip_fw_nat64.h"
#include "nat64_translate.h"
static void
nat64_log(struct pfloghdr *logdata, struct mbuf *m, sa_family_t family)
{
@ -86,22 +87,21 @@ static NAT64NOINLINE int nat64_find_route6(struct nhop6_basic *,
struct sockaddr_in6 *, struct mbuf *);
static NAT64NOINLINE int
nat64_output(struct ifnet *ifp, struct mbuf *m,
struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
void *logdata)
nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct nat64_counters *stats, void *logdata)
{
int error;
if (logdata != NULL)
nat64_log(logdata, m, dst->sa_family);
error = (*ifp->if_output)(ifp, m, dst, ro);
error = (*ifp->if_output)(ifp, m, dst, NULL);
if (error != 0)
NAT64STAT_INC(stats, oerrors);
return (error);
}
static NAT64NOINLINE int
nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
nat64_output_one(struct mbuf *m, struct nat64_counters *stats, void *logdata)
{
struct nhop6_basic nh6;
struct nhop4_basic nh4;
@ -155,9 +155,8 @@ nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
}
#else /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
static NAT64NOINLINE int
nat64_output(struct ifnet *ifp, struct mbuf *m,
struct sockaddr *dst, struct route *ro, nat64_stats_block *stats,
void *logdata)
nat64_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct nat64_counters *stats, void *logdata)
{
struct ip *ip4;
int ret, af;
@ -187,50 +186,103 @@ nat64_output(struct ifnet *ifp, struct mbuf *m,
}
static NAT64NOINLINE int
nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata)
nat64_output_one(struct mbuf *m, struct nat64_counters *stats, void *logdata)
{
return (nat64_output(NULL, m, NULL, NULL, stats, logdata));
return (nat64_output(NULL, m, NULL, stats, logdata));
}
#endif /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */
#if 0
void print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize);
void
print_ipv6_header(struct ip6_hdr *ip6, char *buf, size_t bufsize)
/*
* Check the given IPv6 prefix and length according to RFC6052:
* The prefixes can only have one of the following lengths:
* 32, 40, 48, 56, 64, or 96 (The Well-Known Prefix is 96 bits long).
* Returns zero on success, otherwise EINVAL.
*/
int
nat64_check_prefix6(const struct in6_addr *prefix, int length)
{
char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ip6->ip6_src, sbuf, sizeof(sbuf));
inet_ntop(AF_INET6, &ip6->ip6_dst, dbuf, sizeof(dbuf));
snprintf(buf, bufsize, "%s -> %s %d", sbuf, dbuf, ip6->ip6_nxt);
switch (length) {
case 32:
case 40:
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);
}
static NAT64NOINLINE int
nat64_embed_ip4(struct nat64_cfg *cfg, in_addr_t ia, struct in6_addr *ip6)
int
nat64_check_private_ip4(const struct nat64_config *cfg, in_addr_t ia)
{
/* assume the prefix is properly filled with zeros */
bcopy(&cfg->prefix, ip6, sizeof(*ip6));
switch (cfg->plen) {
if (V_nat64_allow_private)
return (0);
/* WKPFX must not be used to represent non-global IPv4 addresses */
if (cfg->flags & NAT64_WKPFX) {
/* IN_PRIVATE */
if ((ia & htonl(0xff000000)) == htonl(0x0a000000) ||
(ia & htonl(0xfff00000)) == htonl(0xac100000) ||
(ia & htonl(0xffff0000)) == htonl(0xc0a80000))
return (1);
/*
* RFC 5735:
* 192.0.0.0/24 - reserved for IETF protocol assignments
* 192.88.99.0/24 - for use as 6to4 relay anycast addresses
* 198.18.0.0/15 - for use in benchmark tests
* 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 - for use
* in documentation and example code
*/
if ((ia & htonl(0xffffff00)) == htonl(0xc0000000) ||
(ia & htonl(0xffffff00)) == htonl(0xc0586300) ||
(ia & htonl(0xfffffe00)) == htonl(0xc6120000) ||
(ia & htonl(0xffffff00)) == htonl(0xc0000200) ||
(ia & htonl(0xfffffe00)) == htonl(0xc6336400) ||
(ia & htonl(0xffffff00)) == htonl(0xcb007100))
return (1);
}
return (0);
}
void
nat64_embed_ip4(const struct nat64_config *cfg, in_addr_t ia,
struct in6_addr *ip6)
{
/* assume the prefix6 is properly filled with zeros */
bcopy(&cfg->prefix6, ip6, sizeof(*ip6));
switch (cfg->plen6) {
case 32:
case 96:
ip6->s6_addr32[cfg->plen / 32] = ia;
ip6->s6_addr32[cfg->plen6 / 32] = ia;
break;
case 40:
case 48:
case 56:
#if BYTE_ORDER == BIG_ENDIAN
ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
(ia >> (cfg->plen % 32));
ip6->s6_addr32[2] = ia << (24 - cfg->plen % 32);
ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
(ia >> (cfg->plen6 % 32));
ip6->s6_addr32[2] = ia << (24 - cfg->plen6 % 32);
#elif BYTE_ORDER == LITTLE_ENDIAN
ip6->s6_addr32[1] = cfg->prefix.s6_addr32[1] |
(ia << (cfg->plen % 32));
ip6->s6_addr32[2] = ia >> (24 - cfg->plen % 32);
ip6->s6_addr32[1] = cfg->prefix6.s6_addr32[1] |
(ia << (cfg->plen6 % 32));
ip6->s6_addr32[2] = ia >> (24 - cfg->plen6 % 32);
#endif
break;
case 64:
@ -243,14 +295,13 @@ nat64_embed_ip4(struct nat64_cfg *cfg, in_addr_t ia, struct in6_addr *ip6)
#endif
break;
default:
return (0);
panic("Wrong plen6");
};
ip6->s6_addr8[8] = 0;
return (1);
}
static NAT64NOINLINE in_addr_t
nat64_extract_ip4(struct in6_addr *ip6, int plen)
in_addr_t
nat64_extract_ip4(const struct nat64_config *cfg, const struct in6_addr *ip6)
{
in_addr_t ia;
@ -261,7 +312,7 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
* The suffix bits are reserved for future extensions and SHOULD
* be set to zero.
*/
switch (plen) {
switch (cfg->plen6) {
case 32:
if (ip6->s6_addr32[3] != 0 || ip6->s6_addr32[2] != 0)
goto badip6;
@ -285,20 +336,20 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
(ip6->s6_addr32[3] & htonl(0x00ffffff)) != 0)
goto badip6;
};
switch (plen) {
switch (cfg->plen6) {
case 32:
case 96:
ia = ip6->s6_addr32[plen / 32];
ia = ip6->s6_addr32[cfg->plen6 / 32];
break;
case 40:
case 48:
case 56:
#if BYTE_ORDER == BIG_ENDIAN
ia = (ip6->s6_addr32[1] << (plen % 32)) |
(ip6->s6_addr32[2] >> (24 - plen % 32));
ia = (ip6->s6_addr32[1] << (cfg->plen6 % 32)) |
(ip6->s6_addr32[2] >> (24 - cfg->plen6 % 32));
#elif BYTE_ORDER == LITTLE_ENDIAN
ia = (ip6->s6_addr32[1] >> (plen % 32)) |
(ip6->s6_addr32[2] << (24 - plen % 32));
ia = (ip6->s6_addr32[1] >> (cfg->plen6 % 32)) |
(ip6->s6_addr32[2] << (24 - cfg->plen6 % 32));
#endif
break;
case 64:
@ -312,18 +363,18 @@ nat64_extract_ip4(struct in6_addr *ip6, int plen)
return (0);
};
if (nat64_check_ip4(ia) != 0 ||
nat64_check_private_ip4(ia) != 0)
nat64_check_private_ip4(cfg, ia) != 0)
goto badip4;
return (ia);
badip4:
DPRINTF(DP_GENERIC, "invalid destination address: %08x", ia);
DPRINTF(DP_GENERIC | DP_DROPS,
"invalid destination address: %08x", ia);
return (0);
badip6:
DPRINTF(DP_GENERIC, "invalid IPv4-embedded IPv6 address");
DPRINTF(DP_GENERIC | DP_DROPS, "invalid IPv4-embedded IPv6 address");
return (0);
}
#endif
/*
* According to RFC 1624 the equation for incremental checksum update is:
@ -363,9 +414,6 @@ nat64_cksum_convert(struct ip6_hdr *ip6, struct ip *ip)
return (sum);
}
#if __FreeBSD_version < 1100000
#define ip_fillid(ip) (ip)->ip_id = ip_newid()
#endif
static NAT64NOINLINE void
nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag,
uint16_t plen, uint8_t proto, struct ip *ip)
@ -397,8 +445,9 @@ nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct ip6_frag *frag,
#define FRAGSZ(mtu) ((mtu) - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag))
static NAT64NOINLINE int
nat64_fragment6(nat64_stats_block *stats, struct ip6_hdr *ip6, struct mbufq *mq,
struct mbuf *m, uint32_t mtu, uint16_t ip_id, uint16_t ip_off)
nat64_fragment6(struct nat64_counters *stats, struct ip6_hdr *ip6,
struct mbufq *mq, struct mbuf *m, uint32_t mtu, uint16_t ip_id,
uint16_t ip_off)
{
struct ip6_frag ip6f;
struct mbuf *n;
@ -510,7 +559,7 @@ nat64_find_route6(struct nhop6_basic *pnh, struct sockaddr_in6 *dst,
#define NAT64_ICMP6_PLEN 64
static NAT64NOINLINE void
nat64_icmp6_reflect(struct mbuf *m, uint8_t type, uint8_t code, uint32_t mtu,
nat64_stats_block *stats, void *logdata)
struct nat64_counters *stats, void *logdata)
{
struct icmp6_hdr *icmp6;
struct ip6_hdr *ip6, *oip6;
@ -625,7 +674,7 @@ nat64_find_route4(struct nhop4_basic *pnh, struct sockaddr_in *dst,
#define NAT64_ICMP_PLEN 64
static NAT64NOINLINE void
nat64_icmp_reflect(struct mbuf *m, uint8_t type,
uint8_t code, uint16_t mtu, nat64_stats_block *stats, void *logdata)
uint8_t code, uint16_t mtu, struct nat64_counters *stats, void *logdata)
{
struct icmp *icmp;
struct ip *ip, *oip;
@ -734,7 +783,7 @@ nat64_icmp_handle_echo(struct ip6_hdr *ip6, struct icmp6_hdr *icmp6,
static NAT64NOINLINE struct mbuf *
nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
int offset, nat64_stats_block *stats)
int offset, struct nat64_config *cfg)
{
struct ip ip;
struct icmp *icmp;
@ -749,7 +798,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
if (m->m_len < offset + ICMP_MINLEN)
m = m_pullup(m, offset + ICMP_MINLEN);
if (m == NULL) {
NAT64STAT_INC(stats, nomem);
NAT64STAT_INC(&cfg->stats, nomem);
return (m);
}
mtu = 0;
@ -889,8 +938,8 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
hlen += ip.ip_hl << 2; /* Skip inner IP header */
if (nat64_check_ip4(ip.ip_src.s_addr) != 0 ||
nat64_check_ip4(ip.ip_dst.s_addr) != 0 ||
nat64_check_private_ip4(ip.ip_src.s_addr) != 0 ||
nat64_check_private_ip4(ip.ip_dst.s_addr) != 0) {
nat64_check_private_ip4(cfg, ip.ip_src.s_addr) != 0 ||
nat64_check_private_ip4(cfg, ip.ip_dst.s_addr) != 0) {
DPRINTF(DP_DROPS, "IP addresses checks failed %04x -> %04x",
ntohl(ip.ip_src.s_addr), ntohl(ip.ip_dst.s_addr));
goto freeit;
@ -925,7 +974,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
plen = sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + len;
n = m_get2(offset + plen + max_hdr, M_NOWAIT, MT_HEADER, M_PKTHDR);
if (n == NULL) {
NAT64STAT_INC(stats, nomem);
NAT64STAT_INC(&cfg->stats, nomem);
m_freem(m);
return (NULL);
}
@ -939,7 +988,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
eip6->ip6_src = ip6->ip6_dst;
/* Use the fact that we have single /96 prefix for IPv4 map */
eip6->ip6_dst = ip6->ip6_src;
nat64_set_ip4(&eip6->ip6_dst, ip.ip_dst.s_addr);
nat64_embed_ip4(cfg, ip.ip_dst.s_addr, &eip6->ip6_dst);
eip6->ip6_flow = htonl(ip.ip_tos << 20);
eip6->ip6_vfc |= IPV6_VERSION;
@ -1009,7 +1058,7 @@ nat64_icmp_translate(struct mbuf *m, struct ip6_hdr *ip6, uint16_t icmpid,
return (n);
freeit:
m_freem(m);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NULL);
}
@ -1057,7 +1106,7 @@ nat64_getlasthdr(struct mbuf *m, int *offset)
int
nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats,
struct in6_addr *daddr, uint16_t lport, struct nat64_config *cfg,
void *logdata)
{
struct nhop6_basic nh;
@ -1074,7 +1123,7 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
if (ip->ip_ttl <= IPTTLDEC) {
nat64_icmp_reflect(m, ICMP_TIMXCEED,
ICMP_TIMXCEED_INTRANS, 0, stats, logdata);
ICMP_TIMXCEED_INTRANS, 0, &cfg->stats, logdata);
return (NAT64RETURN);
}
@ -1092,27 +1141,27 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
/* Fragment length must be multiple of 8 octets */
if ((ip->ip_off & htons(IP_MF)) != 0 && (plen & 0x7) != 0) {
nat64_icmp_reflect(m, ICMP_PARAMPROB,
ICMP_PARAMPROB_LENGTH, 0, stats, logdata);
ICMP_PARAMPROB_LENGTH, 0, &cfg->stats, logdata);
return (NAT64RETURN);
}
/* Fragmented ICMP is unsupported */
if (proto == IPPROTO_ICMP && ip_off != 0) {
DPRINTF(DP_DROPS, "dropped due to fragmented ICMP");
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
dst.sin6_addr = ip6.ip6_dst;
if (nat64_find_route6(&nh, &dst, m) != 0) {
NAT64STAT_INC(stats, noroute6);
NAT64STAT_INC(&cfg->stats, noroute6);
nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0,
stats, logdata);
&cfg->stats, logdata);
return (NAT64RETURN);
}
if (nh.nh_mtu < plen + sizeof(ip6) &&
(ip->ip_off & htons(IP_DF)) != 0) {
nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
FRAGSZ(nh.nh_mtu) + sizeof(struct ip), stats, logdata);
FRAGSZ(nh.nh_mtu) + sizeof(struct ip), &cfg->stats, logdata);
return (NAT64RETURN);
}
@ -1147,19 +1196,19 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
*csum = cksum_add(*csum, ~nat64_cksum_convert(&ip6, ip));
break;
case IPPROTO_ICMP:
m = nat64_icmp_translate(m, &ip6, lport, hlen, stats);
m = nat64_icmp_translate(m, &ip6, lport, hlen, cfg);
if (m == NULL) /* stats already accounted */
return (NAT64RETURN);
}
m_adj(m, hlen);
mbufq_init(&mq, 255);
nat64_fragment6(stats, &ip6, &mq, m, nh.nh_mtu, ip_id, ip_off);
nat64_fragment6(&cfg->stats, &ip6, &mq, m, nh.nh_mtu, ip_id, ip_off);
while ((m = mbufq_dequeue(&mq)) != NULL) {
if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst,
NULL, stats, logdata) != 0)
&cfg->stats, logdata) != 0)
break;
NAT64STAT_INC(stats, opcnt46);
NAT64STAT_INC(&cfg->stats, opcnt46);
}
mbufq_drain(&mq);
return (NAT64RETURN);
@ -1167,7 +1216,7 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *saddr,
int
nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
nat64_stats_block *stats, void *logdata)
struct nat64_config *cfg, void *logdata)
{
struct ip ip;
struct icmp6_hdr *icmp6;
@ -1187,7 +1236,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
if (proto != IPPROTO_ICMPV6) {
DPRINTF(DP_DROPS,
"dropped due to mbuf isn't contigious");
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
}
@ -1217,7 +1266,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
" code %d", icmp6->icmp6_type,
icmp6->icmp6_code);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
break;
@ -1229,7 +1278,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
DPRINTF(DP_DROPS, "Wrong MTU %d in ICMPv6 type %d,"
" code %d", mtu, icmp6->icmp6_type,
icmp6->icmp6_code);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
/*
@ -1274,7 +1323,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
" code %d, pptr %d", icmp6->icmp6_type,
icmp6->icmp6_code, mtu);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
case ICMP6_PARAMPROB_NEXTHEADER:
@ -1285,20 +1334,20 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d,"
" code %d, pptr %d", icmp6->icmp6_type,
icmp6->icmp6_code, ntohl(icmp6->icmp6_pptr));
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
break;
default:
DPRINTF(DP_DROPS, "Unsupported ICMPv6 type %d, code %d",
icmp6->icmp6_type, icmp6->icmp6_code);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
hlen += sizeof(struct icmp6_hdr);
if (m->m_pkthdr.len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN) {
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
DPRINTF(DP_DROPS, "Message is too short %d",
m->m_pkthdr.len);
return (NAT64MFREE);
@ -1325,7 +1374,7 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
if (m->m_len < hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN)
m = m_pullup(m, hlen + sizeof(struct ip6_hdr) + ICMP_MINLEN);
if (m == NULL) {
NAT64STAT_INC(stats, nomem);
NAT64STAT_INC(&cfg->stats, nomem);
return (NAT64RETURN);
}
ip6 = mtod(m, struct ip6_hdr *);
@ -1364,7 +1413,7 @@ 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_get_ip4(&ip6i->ip6_src);
ip.ip_src.s_addr = nat64_extract_ip4(cfg, &ip6i->ip6_src);
/* XXX: Make fake ulp header */
#ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT
ip6i->ip6_hlim += IPV6_HLIMDEC; /* init_ip4hdr will decrement it */
@ -1372,7 +1421,8 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
nat64_init_ip4hdr(ip6i, ip6f, plen, proto, &ip);
m_adj(m, hlen - sizeof(struct ip));
bcopy(&ip, mtod(m, void *), sizeof(ip));
nat64_icmp_reflect(m, type, code, (uint16_t)mtu, stats, logdata);
nat64_icmp_reflect(m, type, code, (uint16_t)mtu, &cfg->stats,
logdata);
return (NAT64RETURN);
fail:
/*
@ -1380,13 +1430,13 @@ nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
* changed with m_pullup().
*/
m_freem(m);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64RETURN);
}
int
nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
nat64_stats_block *stats, void *logdata)
struct nat64_config *cfg, void *logdata)
{
struct ip ip;
struct nhop4_basic nh;
@ -1411,21 +1461,21 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
/* Starting from this point we must not return zero */
ip.ip_src.s_addr = aaddr;
if (nat64_check_ip4(ip.ip_src.s_addr) != 0) {
DPRINTF(DP_GENERIC, "invalid source address: %08x",
DPRINTF(DP_GENERIC | DP_DROPS, "invalid source address: %08x",
ip.ip_src.s_addr);
/* XXX: stats? */
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
ip.ip_dst.s_addr = nat64_get_ip4(&ip6->ip6_dst);
ip.ip_dst.s_addr = nat64_extract_ip4(cfg, &ip6->ip6_dst);
if (ip.ip_dst.s_addr == 0) {
/* XXX: stats? */
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
nat64_icmp6_reflect(m, ICMP6_TIME_EXCEEDED,
ICMP6_TIME_EXCEED_TRANSIT, 0, stats, logdata);
ICMP6_TIME_EXCEED_TRANSIT, 0, &cfg->stats, logdata);
return (NAT64RETURN);
}
@ -1434,7 +1484,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
proto = nat64_getlasthdr(m, &hlen);
if (proto < 0) {
DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
frag = NULL;
@ -1443,7 +1493,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
if (m->m_len < hlen + sizeof(*frag)) {
DPRINTF(DP_DROPS,
"dropped due to mbuf isn't contigious");
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
frag = mtodo(m, hlen);
@ -1452,7 +1502,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
/* Fragmented ICMPv6 is unsupported */
if (proto == IPPROTO_ICMPV6) {
DPRINTF(DP_DROPS, "dropped due to fragmented ICMPv6");
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
/* Fragment length must be multiple of 8 octets */
@ -1460,7 +1510,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
((plen + sizeof(struct ip6_hdr) - hlen) & 0x7) != 0) {
nat64_icmp6_reflect(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
offsetof(struct ip6_hdr, ip6_plen), stats,
offsetof(struct ip6_hdr, ip6_plen), &cfg->stats,
logdata);
return (NAT64RETURN);
}
@ -1469,7 +1519,7 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
if (plen < 0 || m->m_pkthdr.len < plen + hlen) {
DPRINTF(DP_DROPS, "plen %d, pkthdr.len %d, hlen %d",
plen, m->m_pkthdr.len, hlen);
NAT64STAT_INC(stats, dropped);
NAT64STAT_INC(&cfg->stats, dropped);
return (NAT64MFREE);
}
@ -1479,18 +1529,18 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
if (icmp6->icmp6_type != ICMP6_ECHO_REQUEST &&
icmp6->icmp6_type != ICMP6_ECHO_REPLY)
return (nat64_handle_icmp6(m, hlen, aaddr, aport,
stats, logdata));
cfg, logdata));
}
dst.sin_addr.s_addr = ip.ip_dst.s_addr;
if (nat64_find_route4(&nh, &dst, m) != 0) {
NAT64STAT_INC(stats, noroute4);
NAT64STAT_INC(&cfg->stats, noroute4);
nat64_icmp6_reflect(m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_NOROUTE, 0, stats, logdata);
ICMP6_DST_UNREACH_NOROUTE, 0, &cfg->stats, logdata);
return (NAT64RETURN);
}
if (nh.nh_mtu < plen + sizeof(ip)) {
nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu,
stats, logdata);
&cfg->stats, logdata);
return (NAT64RETURN);
}
nat64_init_ip4hdr(ip6, frag, plen, proto, &ip);
@ -1537,9 +1587,9 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
m_adj(m, hlen - sizeof(ip));
bcopy(&ip, mtod(m, void *), sizeof(ip));
if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst, NULL,
stats, logdata) == 0)
NAT64STAT_INC(stats, opcnt64);
if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst,
&cfg->stats, logdata) == 0)
NAT64STAT_INC(&cfg->stats, opcnt64);
return (NAT64RETURN);
}

View File

@ -30,6 +30,70 @@
#ifndef _IP_FW_NAT64_TRANSLATE_H_
#define _IP_FW_NAT64_TRANSLATE_H_
struct nat64_stats {
uint64_t opcnt64; /* 6to4 of packets translated */
uint64_t opcnt46; /* 4to6 of packets translated */
uint64_t ofrags; /* number of fragments generated */
uint64_t ifrags; /* number of fragments received */
uint64_t oerrors; /* number of output errors */
uint64_t noroute4;
uint64_t noroute6;
uint64_t nomatch4; /* No addr/port match */
uint64_t noproto; /* Protocol not supported */
uint64_t nomem; /* mbufs allocation failed */
uint64_t dropped; /* number of packets silently
* dropped due to some errors/
* 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 jmaxlen;
uint64_t jnomem;
uint64_t jreinjected;
uint64_t screated;
uint64_t sdeleted;
uint64_t spgcreated;
uint64_t spgdeleted;
};
#define IPFW_NAT64_VERSION 1
#define NAT64STATS (sizeof(struct nat64_stats) / sizeof(uint64_t))
struct nat64_counters {
counter_u64_t cnt[NAT64STATS];
};
#define NAT64STAT_ADD(s, f, v) \
counter_u64_add((s)->cnt[ \
offsetof(struct nat64_stats, f) / sizeof(uint64_t)], (v))
#define NAT64STAT_INC(s, f) NAT64STAT_ADD(s, f, 1)
#define NAT64STAT_FETCH(s, f) \
counter_u64_fetch((s)->cnt[ \
offsetof(struct nat64_stats, f) / sizeof(uint64_t)])
#define L3HDR(_ip, _t) ((_t)((uint32_t *)(_ip) + (_ip)->ip_hl))
#define TCP(p) ((struct tcphdr *)(p))
#define UDP(p) ((struct udphdr *)(p))
#define ICMP(p) ((struct icmphdr *)(p))
#define ICMP6(p) ((struct icmp6_hdr *)(p))
#define NAT64SKIP 0
#define NAT64RETURN 1
#define NAT64MFREE -1
struct nat64_config {
uint32_t flags;
#define NAT64_WKPFX 0x00010000 /* prefix6 is WKPFX */
struct in6_addr prefix6;
uint8_t plen6;
struct nat64_counters stats;
};
static inline int
nat64_check_ip6(struct in6_addr *addr)
{
@ -41,39 +105,6 @@ nat64_check_ip6(struct in6_addr *addr)
return (0);
}
extern int nat64_allow_private;
static inline int
nat64_check_private_ip4(in_addr_t ia)
{
if (nat64_allow_private)
return (0);
/* WKPFX must not be used to represent non-global IPv4 addresses */
// if (cfg->flags & NAT64_WKPFX) {
/* IN_PRIVATE */
if ((ia & htonl(0xff000000)) == htonl(0x0a000000) ||
(ia & htonl(0xfff00000)) == htonl(0xac100000) ||
(ia & htonl(0xffff0000)) == htonl(0xc0a80000))
return (1);
/*
* RFC 5735:
* 192.0.0.0/24 - reserved for IETF protocol assignments
* 192.88.99.0/24 - for use as 6to4 relay anycast addresses
* 198.18.0.0/15 - for use in benchmark tests
* 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 - for use
* in documentation and example code
*/
if ((ia & htonl(0xffffff00)) == htonl(0xc0000000) ||
(ia & htonl(0xffffff00)) == htonl(0xc0586300) ||
(ia & htonl(0xfffffe00)) == htonl(0xc6120000) ||
(ia & htonl(0xffffff00)) == htonl(0xc0000200) ||
(ia & htonl(0xfffffe00)) == htonl(0xc6336400) ||
(ia & htonl(0xffffff00)) == htonl(0xcb007100))
return (1);
// }
return (0);
}
static inline int
nat64_check_ip4(in_addr_t ia)
{
@ -90,17 +121,26 @@ nat64_check_ip4(in_addr_t ia)
return (0);
}
#define nat64_get_ip4(_ip6) ((_ip6)->s6_addr32[3])
#define nat64_set_ip4(_ip6, _ip4) (_ip6)->s6_addr32[3] = (_ip4)
/* Well-known prefix 64:ff9b::/96 */
#define IPV6_ADDR_INT32_WKPFX htonl(0x64ff9b)
#define IN6_IS_ADDR_WKPFX(a) \
((a)->s6_addr32[0] == IPV6_ADDR_INT32_WKPFX && \
(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_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,
struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats,
struct in6_addr *daddr, uint16_t lport, struct nat64_config *cfg,
void *logdata);
int nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport,
nat64_stats_block *stats, void *logdata);
int nat64_handle_icmp6(struct mbuf *m, int hlen, uint32_t aaddr, uint16_t aport,
nat64_stats_block *stats, void *logdata);
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);
#endif

View File

@ -64,11 +64,10 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip_fw_nat64.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64lsn.h>
#include <netpfil/ipfw/nat64/nat64_translate.h>
#include <netpfil/pf/pf.h>
#include "nat64lsn.h"
MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
static void nat64lsn_periodic(void *data);
@ -336,14 +335,14 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
addr = f_id->dst_ip;
port = f_id->dst_port;
if (addr < cfg->prefix4 || addr > cfg->pmask4) {
NAT64STAT_INC(&cfg->stats, nomatch4);
NAT64STAT_INC(&cfg->base.stats, nomatch4);
return (cfg->nomatch_verdict);
}
/* Check if protocol is supported and get its short id */
nat_proto = nat64lsn_proto_map[f_id->proto];
if (nat_proto == 0) {
NAT64STAT_INC(&cfg->stats, noproto);
NAT64STAT_INC(&cfg->base.stats, noproto);
return (cfg->nomatch_verdict);
}
@ -352,15 +351,15 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
ret = inspect_icmp_mbuf(pm, &nat_proto, &addr, &port);
if (ret != 0) {
if (ret == ENOMEM) {
NAT64STAT_INC(&cfg->stats, nomem);
NAT64STAT_INC(&cfg->base.stats, nomem);
return (IP_FW_DENY);
}
NAT64STAT_INC(&cfg->stats, noproto);
NAT64STAT_INC(&cfg->base.stats, noproto);
return (cfg->nomatch_verdict);
}
/* XXX: Check addr for validity */
if (addr < cfg->prefix4 || addr > cfg->pmask4) {
NAT64STAT_INC(&cfg->stats, nomatch4);
NAT64STAT_INC(&cfg->base.stats, nomatch4);
return (cfg->nomatch_verdict);
}
}
@ -370,7 +369,7 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
/* Check if this port is occupied by any portgroup */
if (pg == NULL) {
NAT64STAT_INC(&cfg->stats, nomatch4);
NAT64STAT_INC(&cfg->base.stats, nomatch4);
#if 0
DPRINTF(DP_STATE, "NOMATCH %u %d %d (%d)", addr, nat_proto, port,
_GET_PORTGROUP_IDX(cfg, addr, nat_proto, port));
@ -402,19 +401,15 @@ nat64lsn_translate4(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
NAT64_UNLOCK(nh);
if (cfg->flags & NAT64_LOG) {
if (cfg->base.flags & NAT64_LOG) {
logdata = &loghdr;
nat64lsn_log(logdata, *pm, AF_INET, pg->idx, st->cur.off);
} else
logdata = NULL;
src6.s6_addr32[0] = cfg->prefix6.s6_addr32[0];
src6.s6_addr32[1] = cfg->prefix6.s6_addr32[1];
src6.s6_addr32[2] = cfg->prefix6.s6_addr32[2];
src6.s6_addr32[3] = htonl(f_id->src_ip);
nat64_embed_ip4(&cfg->base, htonl(f_id->src_ip), &src6);
ret = nat64_do_handle_ip4(*pm, &src6, &nh->addr, lport,
&cfg->stats, logdata);
&cfg->base, logdata);
if (ret == NAT64SKIP)
return (cfg->nomatch_verdict);
@ -432,7 +427,7 @@ nat64lsn_dump_state(const struct nat64lsn_cfg *cfg,
{
char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], d[INET_ADDRSTRLEN];
if ((nat64_debug & DP_STATE) == 0)
if ((V_nat64_debug & DP_STATE) == 0)
return;
inet_ntop(AF_INET6, &pg->host->addr, s, sizeof(s));
inet_ntop(AF_INET, &pg->aaddr, a, sizeof(a));
@ -604,7 +599,7 @@ nat64lsn_periodic_chkstates(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh)
SET_AGE(si.pg->timestamp);
}
}
NAT64STAT_ADD(&cfg->stats, sdeleted, delcount);
NAT64STAT_ADD(&cfg->base.stats, sdeleted, delcount);
return (delcount);
}
@ -750,7 +745,7 @@ reinject_mbuf(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
if (ji->f_id.addr_type != 6 || ji->done == 0) {
m_freem(ji->m);
ji->m = NULL;
NAT64STAT_INC(&cfg->stats, dropped);
NAT64STAT_INC(&cfg->base.stats, dropped);
DPRINTF(DP_DROPS, "mbuf dropped: type %d, done %d",
ji->jtype, ji->done);
return;
@ -760,7 +755,7 @@ reinject_mbuf(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
* XXX: Limit recursion level
*/
NAT64STAT_INC(&cfg->stats, jreinjected);
NAT64STAT_INC(&cfg->base.stats, jreinjected);
DPRINTF(DP_JQUEUE, "Reinject mbuf");
nat64lsn_translate6(cfg, &ji->f_id, &ji->m);
}
@ -823,7 +818,7 @@ alloc_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
return (2);
}
if (alloc_portgroup(ji) != 0) {
NAT64STAT_INC(&cfg->stats, jportfails);
NAT64STAT_INC(&cfg->base.stats, jportfails);
uma_zfree(nat64lsn_pgidx_zone, PORTGROUP_CHUNK(nh, 0));
uma_zfree(nat64lsn_host_zone, nh);
return (3);
@ -882,7 +877,7 @@ attach_host6(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
if (attach_portgroup(cfg, ji) != 0) {
DPRINTF(DP_DROPS, "%s %p failed to attach PG",
a, nh);
NAT64STAT_INC(&cfg->stats, jportfails);
NAT64STAT_INC(&cfg->base.stats, jportfails);
return (1);
}
return (0);
@ -1021,7 +1016,7 @@ attach_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
cfg->pg[pg_idx] = pg;
cfg->protochunks[pg->nat_proto]++;
NAT64STAT_INC(&cfg->stats, spgcreated);
NAT64STAT_INC(&cfg->base.stats, spgcreated);
pg->aaddr = aaddr;
pg->aport = aport;
@ -1075,7 +1070,7 @@ consider_del_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
KASSERT(cfg->pg[idx] == pg, ("Non matched pg"));
cfg->pg[idx] = NULL;
cfg->protochunks[pg->nat_proto]--;
NAT64STAT_INC(&cfg->stats, spgdeleted);
NAT64STAT_INC(&cfg->base.stats, spgdeleted);
/* Decrease pg_used */
while (nh->pg_used > 0 &&
@ -1101,7 +1096,7 @@ consider_del_portgroup(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
/* TODO: Delay freeing portgroups */
while (pg_lidx > 0) {
pg_lidx--;
NAT64STAT_INC(&cfg->stats, spgdeleted);
NAT64STAT_INC(&cfg->base.stats, spgdeleted);
destroy_portgroup(pg_list[pg_lidx]);
}
}
@ -1158,7 +1153,7 @@ nat64lsn_do_request(void *data)
return;
}
NAT64STAT_INC(&cfg->stats, jcalls);
NAT64STAT_INC(&cfg->base.stats, jcalls);
DPRINTF(DP_JQUEUE, "count=%d", jcount);
/*
@ -1175,11 +1170,13 @@ nat64lsn_do_request(void *data)
switch (ji->jtype) {
case JTYPE_NEWHOST:
if (alloc_host6(cfg, ji) != 0)
NAT64STAT_INC(&cfg->stats, jhostfails);
NAT64STAT_INC(&cfg->base.stats,
jhostfails);
break;
case JTYPE_NEWPORTGROUP:
if (alloc_portgroup(ji) != 0)
NAT64STAT_INC(&cfg->stats, jportfails);
NAT64STAT_INC(&cfg->base.stats,
jportfails);
break;
case JTYPE_DELPORTGROUP:
delcount += ji->delcount;
@ -1210,7 +1207,8 @@ nat64lsn_do_request(void *data)
case JTYPE_NEWPORTGROUP:
if (ji->pg != NULL &&
attach_portgroup(cfg, ji) != 0)
NAT64STAT_INC(&cfg->stats, jportfails);
NAT64STAT_INC(&cfg->base.stats,
jportfails);
break;
case JTYPE_DELPORTGROUP:
consider_del_portgroup(cfg, ji);
@ -1255,7 +1253,7 @@ nat64lsn_create_job(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
* Drop packet instead.
*/
if (cfg->jlen >= cfg->jmaxlen) {
NAT64STAT_INC(&cfg->stats, jmaxlen);
NAT64STAT_INC(&cfg->base.stats, jmaxlen);
return (NULL);
}
@ -1276,7 +1274,7 @@ nat64lsn_create_job(struct nat64lsn_cfg *cfg, const struct ipfw_flow_id *f_id,
M_NOWAIT | M_ZERO);
if (ji == NULL) {
NAT64STAT_INC(&cfg->stats, jnomem);
NAT64STAT_INC(&cfg->base.stats, jnomem);
return (NULL);
}
@ -1301,7 +1299,7 @@ nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
JQUEUE_LOCK();
TAILQ_INSERT_TAIL(&cfg->jhead, ji, next);
cfg->jlen++;
NAT64STAT_INC(&cfg->stats, jrequests);
NAT64STAT_INC(&cfg->base.stats, jrequests);
if (callout_pending(&cfg->jcallout) == 0)
callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
@ -1320,7 +1318,7 @@ nat64lsn_enqueue_jobs(struct nat64lsn_cfg *cfg,
JQUEUE_LOCK();
TAILQ_CONCAT(&cfg->jhead, jhead, next);
cfg->jlen += jlen;
NAT64STAT_ADD(&cfg->stats, jrequests, jlen);
NAT64STAT_ADD(&cfg->base.stats, jrequests, jlen);
if (callout_pending(&cfg->jcallout) == 0)
callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
@ -1353,14 +1351,14 @@ nat64lsn_request_host(struct nat64lsn_cfg *cfg,
ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWHOST);
if (ji == NULL) {
m_freem(m);
NAT64STAT_INC(&cfg->stats, dropped);
NAT64STAT_INC(&cfg->base.stats, dropped);
DPRINTF(DP_DROPS, "failed to create job");
} else {
ji->m = m;
/* Provide pseudo-random value based on flow */
ji->fhash = flow6_hash(f_id);
nat64lsn_enqueue_job(cfg, ji);
NAT64STAT_INC(&cfg->stats, jhostsreq);
NAT64STAT_INC(&cfg->base.stats, jhostsreq);
}
return (IP_FW_DENY);
@ -1380,7 +1378,7 @@ nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
ji = nat64lsn_create_job(cfg, f_id, JTYPE_NEWPORTGROUP);
if (ji == NULL) {
m_freem(m);
NAT64STAT_INC(&cfg->stats, dropped);
NAT64STAT_INC(&cfg->base.stats, dropped);
DPRINTF(DP_DROPS, "failed to create job");
} else {
ji->m = m;
@ -1389,7 +1387,7 @@ nat64lsn_request_portgroup(struct nat64lsn_cfg *cfg,
ji->aaddr = aaddr;
ji->needs_idx = needs_idx;
nat64lsn_enqueue_job(cfg, ji);
NAT64STAT_INC(&cfg->stats, jportreq);
NAT64STAT_INC(&cfg->base.stats, jportreq);
}
return (IP_FW_DENY);
@ -1435,7 +1433,7 @@ nat64lsn_create_state(struct nat64lsn_cfg *cfg, struct nat64lsn_host *nh,
nat64lsn_dump_state(cfg, pg, st, "ALLOC STATE", off);
NAT64STAT_INC(&cfg->stats, screated);
NAT64STAT_INC(&cfg->base.stats, screated);
return (st);
}
@ -1469,10 +1467,8 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
* to free mbuf by self, do not leave this task to
* ipfw_check_packet().
*/
NAT64STAT_INC(&cfg->stats, noproto);
m_freem(*pm);
*pm = NULL;
return (IP_FW_DENY);
NAT64STAT_INC(&cfg->base.stats, noproto);
goto drop;
}
/* Try to find host first */
@ -1482,7 +1478,11 @@ 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 = f_id->dst_ip6.s6_addr32[3];
kst.u.s.faddr = nat64_extract_ip4(&cfg->base, &f_id->dst_ip6);
if (kst.u.s.faddr == 0) {
NAT64STAT_INC(&cfg->base.stats, dropped);
goto drop;
}
kst.u.s.fport = f_id->dst_port;
kst.u.s.lport = f_id->src_port;
@ -1490,11 +1490,9 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
hval = 0;
proto = nat64_getlasthdr(*pm, &hval);
if (proto < 0) {
NAT64STAT_INC(&cfg->stats, dropped);
NAT64STAT_INC(&cfg->base.stats, dropped);
DPRINTF(DP_DROPS, "dropped due to mbuf isn't contigious");
m_freem(*pm);
*pm = NULL;
return (IP_FW_DENY);
goto drop;
}
SET_AGE(state_ts);
@ -1544,7 +1542,6 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
/* No free states. Request more if we can */
if (nh->pg_used >= cfg->max_chunks) {
/* Limit reached */
NAT64STAT_INC(&cfg->stats, dropped);
inet_ntop(AF_INET6, &nh->addr, a, sizeof(a));
DPRINTF(DP_DROPS, "PG limit reached "
" for host %s (used %u, allocated %u, "
@ -1552,10 +1549,9 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
nh->pg_used * NAT64_CHUNK_SIZE,
nh->pg_allocated * NAT64_CHUNK_SIZE,
cfg->max_chunks * NAT64_CHUNK_SIZE);
m_freem(*pm);
*pm = NULL;
NAT64_UNLOCK(nh);
return (IP_FW_DENY);
NAT64STAT_INC(&cfg->base.stats, dropped);
goto drop;
}
if ((nh->pg_allocated <=
nh->pg_used + NAT64LSN_REMAININGPG) &&
@ -1588,17 +1584,19 @@ nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
NAT64_UNLOCK(nh);
if (cfg->flags & NAT64_LOG) {
if (cfg->base.flags & NAT64_LOG) {
logdata = &loghdr;
nat64lsn_log(logdata, *pm, AF_INET6, pg->idx, st->cur.off);
} else
logdata = NULL;
action = nat64_do_handle_ip6(*pm, aaddr, aport, &cfg->stats, logdata);
action = nat64_do_handle_ip6(*pm, aaddr, aport, &cfg->base, logdata);
if (action == NAT64SKIP)
return (cfg->nomatch_verdict);
if (action == NAT64MFREE)
if (action == NAT64MFREE) {
drop:
m_freem(*pm);
}
*pm = NULL; /* mark mbuf as consumed */
return (IP_FW_DENY);
}
@ -1711,7 +1709,7 @@ nat64lsn_init_instance(struct ip_fw_chain *ch, size_t numaddr)
TAILQ_INIT(&cfg->jhead);
cfg->vp = curvnet;
cfg->ch = ch;
COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK);
COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
cfg->ihsize = NAT64LSN_HSIZE;
cfg->ih = malloc(sizeof(void *) * cfg->ihsize, M_IPFW,
@ -1760,7 +1758,7 @@ nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
I6HASH_FOREACH_SAFE(cfg, nh, tmp, nat64lsn_destroy_host, cfg);
DPRINTF(DP_OBJ, "instance %s: hosts %d", cfg->name, cfg->ihcount);
COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS);
COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
free(cfg->ih, M_IPFW);
free(cfg->pg, M_IPFW);
free(cfg, M_IPFW);

View File

@ -31,6 +31,9 @@
#ifndef _IP_FW_NAT64LSN_H_
#define _IP_FW_NAT64LSN_H_
#include "ip_fw_nat64.h"
#include "nat64_translate.h"
#define NAT64_CHUNK_SIZE_BITS 6 /* 64 ports */
#define NAT64_CHUNK_SIZE (1 << NAT64_CHUNK_SIZE_BITS)
@ -187,26 +190,21 @@ _pg_get_free_idx(const struct nat64lsn_portgroup *pg)
TAILQ_HEAD(nat64lsn_job_head, nat64lsn_job_item);
#define NAT64LSN_FLAGSMASK (NAT64_LOG)
struct nat64lsn_cfg {
struct named_object no;
//struct nat64_exthost *ex; /* Pointer to external addr array */
struct nat64lsn_portgroup **pg; /* XXX: array of pointers */
struct nat64lsn_host **ih; /* Host hash */
uint32_t prefix4; /* IPv4 prefix */
uint32_t pmask4; /* IPv4 prefix mask */
uint32_t ihsize; /* IPv6 host hash size */
uint8_t plen4;
uint8_t plen6;
uint8_t nomatch_verdict;/* What to return to ipfw on no-match */
struct in6_addr prefix6; /* IPv6 prefix to embed IPv4 hosts */
uint32_t ihcount; /* Number of items in host hash */
int max_chunks; /* Max chunks per client */
int agg_prefix_len; /* Prefix length to count */
int agg_prefix_max; /* Max hosts per agg prefix */
uint32_t jmaxlen; /* Max jobqueue length */
uint32_t flags;
uint16_t min_chunk; /* Min port group # to use */
uint16_t max_chunk; /* Max port group # to use */
uint16_t nh_delete_delay; /* Stale host delete delay */
@ -217,6 +215,8 @@ struct nat64lsn_cfg {
uint16_t st_udp_ttl; /* UDP expire */
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)
struct callout periodic;
struct callout jcallout;
@ -225,7 +225,6 @@ struct nat64lsn_cfg {
struct nat64lsn_job_head jhead;
int jlen;
char name[64]; /* Nat instance name */
nat64_stats_block stats;
};
struct nat64lsn_cfg *nat64lsn_init_instance(struct ip_fw_chain *ch,

View File

@ -51,11 +51,11 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_fw.h>
#include <netinet6/ip_fw_nat64.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64lsn.h>
#include <netinet6/ip_fw_nat64.h>
#include "nat64lsn.h"
VNET_DEFINE(uint16_t, nat64lsn_eid) = 0;
@ -131,7 +131,7 @@ nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
if (uc->plen4 > 32)
return (EINVAL);
if (uc->plen6 > 128 || ((uc->plen6 % 8) != 0))
if (nat64_check_prefix6(&uc->prefix6, uc->plen6) != 0)
return (EINVAL);
/* XXX: Check prefix4 to be global */
@ -139,8 +139,6 @@ nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
mask4 = ~((1 << (32 - uc->plen4)) - 1);
if ((addr4 & mask4) != addr4)
return (EINVAL);
/* XXX: Check prefix6 */
if (uc->min_port == 0)
uc->min_port = NAT64_MIN_PORT;
if (uc->max_port == 0)
@ -166,13 +164,16 @@ 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.flags |= NAT64_WKPFX;
cfg->prefix4 = addr4;
cfg->pmask4 = addr4 | ~mask4;
/* XXX: Copy 96 bits */
cfg->plen6 = 96;
memcpy(&cfg->prefix6, &uc->prefix6, cfg->plen6 / 8);
cfg->plen4 = uc->plen4;
cfg->flags = uc->flags & NAT64LSN_FLAGSMASK;
cfg->max_chunks = uc->max_ports / NAT64_CHUNK_SIZE;
cfg->agg_prefix_len = uc->agg_prefix_len;
cfg->agg_prefix_max = uc->agg_prefix_max;
@ -264,7 +265,7 @@ nat64lsn_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
}
#define __COPY_STAT_FIELD(_cfg, _stats, _field) \
(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field)
(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field)
static void
export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg,
struct ipfw_nat64lsn_stats *stats)
@ -308,7 +309,7 @@ nat64lsn_export_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg,
ipfw_nat64lsn_cfg *uc)
{
uc->flags = cfg->flags & NAT64LSN_FLAGSMASK;
uc->flags = cfg->base.flags & NAT64LSN_FLAGSMASK;
uc->max_ports = cfg->max_chunks * NAT64_CHUNK_SIZE;
uc->agg_prefix_len = cfg->agg_prefix_len;
uc->agg_prefix_max = cfg->agg_prefix_max;
@ -322,9 +323,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->prefix6;
uc->prefix6 = cfg->base.prefix6;
uc->plen4 = cfg->plen4;
uc->plen6 = cfg->plen6;
uc->plen6 = cfg->base.plen6;
uc->set = cfg->no.set;
strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
}
@ -453,7 +454,8 @@ nat64lsn_config(struct ip_fw_chain *ch, ip_fw3_opheader *op,
cfg->st_estab_ttl = uc->st_estab_ttl;
cfg->st_udp_ttl = uc->st_udp_ttl;
cfg->st_icmp_ttl = uc->st_icmp_ttl;
cfg->flags = uc->flags & NAT64LSN_FLAGSMASK;
cfg->base.flags &= ~NAT64LSN_FLAGSMASK;
cfg->base.flags |= uc->flags & NAT64LSN_FLAGSMASK;
IPFW_UH_WUNLOCK(ch);
@ -536,7 +538,7 @@ nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
IPFW_UH_WUNLOCK(ch);
return (ESRCH);
}
COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS);
COUNTER_ARRAY_ZERO(cfg->base.stats.cnt, NAT64STATS);
IPFW_UH_WUNLOCK(ch);
return (0);
}

View File

@ -55,11 +55,10 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip_fw_nat64.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64_translate.h>
#include <netpfil/ipfw/nat64/nat64stl.h>
#include <netpfil/pf/pf.h>
#include "nat64stl.h"
#define NAT64_LOOKUP(chain, cmd) \
(struct nat64stl_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
@ -93,22 +92,20 @@ nat64stl_handle_ip4(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
ip = mtod(m, struct ip*);
if (nat64_check_ip4(ip->ip_src.s_addr) != 0 ||
nat64_check_ip4(ip->ip_dst.s_addr) != 0 ||
nat64_check_private_ip4(ip->ip_src.s_addr) != 0 ||
nat64_check_private_ip4(ip->ip_dst.s_addr) != 0)
nat64_check_private_ip4(&cfg->base, ip->ip_src.s_addr) != 0 ||
nat64_check_private_ip4(&cfg->base, ip->ip_dst.s_addr) != 0)
return (NAT64SKIP);
daddr = TARG_VAL(chain, tablearg, nh6);
if (nat64_check_ip6(&daddr) != 0)
return (NAT64MFREE);
saddr = cfg->prefix6;
nat64_set_ip4(&saddr, ip->ip_src.s_addr);
if (cfg->flags & NAT64_LOG) {
nat64_embed_ip4(&cfg->base, ip->ip_src.s_addr, &saddr);
if (cfg->base.flags & NAT64_LOG) {
logdata = &loghdr;
nat64stl_log(logdata, m, AF_INET, cfg->no.kidx);
} else
logdata = NULL;
return (nat64_do_handle_ip4(m, &saddr, &daddr, 0, &cfg->stats,
return (nat64_do_handle_ip4(m, &saddr, &daddr, 0, &cfg->base,
logdata));
}
@ -129,15 +126,15 @@ 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->prefix6, cfg->plen6 / 8) != 0)
if (bcmp(&ip6->ip6_dst, &cfg->base.prefix6, cfg->base.plen6 / 8) != 0)
return (NAT64SKIP);
if (cfg->flags & NAT64_LOG) {
if (cfg->base.flags & NAT64_LOG) {
logdata = &loghdr;
nat64stl_log(logdata, m, AF_INET6, cfg->no.kidx);
} else
logdata = NULL;
return (nat64_do_handle_ip6(m, aaddr, 0, &cfg->stats, logdata));
return (nat64_do_handle_ip6(m, aaddr, 0, &cfg->base, logdata));
}
static int
@ -145,14 +142,14 @@ nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
struct mbuf *m)
{
struct pfloghdr loghdr, *logdata;
nat64_stats_block *stats;
struct nat64_counters *stats;
struct ip6_hdr *ip6i;
struct icmp6_hdr *icmp6;
uint32_t tablearg;
int hlen, proto;
hlen = 0;
stats = &cfg->stats;
stats = &cfg->base.stats;
proto = nat64_getlasthdr(m, &hlen);
if (proto != IPPROTO_ICMPV6) {
NAT64STAT_INC(stats, dropped);
@ -190,13 +187,13 @@ nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
m_freem(m);
return (NAT64RETURN);
}
if (cfg->flags & NAT64_LOG) {
if (cfg->base.flags & NAT64_LOG) {
logdata = &loghdr;
nat64stl_log(logdata, m, AF_INET6, cfg->no.kidx);
} else
logdata = NULL;
return (nat64_handle_icmp6(m, 0,
htonl(TARG_VAL(chain, tablearg, nh4)), 0, stats, logdata));
htonl(TARG_VAL(chain, tablearg, nh4)), 0, &cfg->base, logdata));
}
int

View File

@ -30,21 +30,21 @@
#ifndef _IP_FW_NAT64STL_H_
#define _IP_FW_NAT64STL_H_
#include "ip_fw_nat64.h"
#include "nat64_translate.h"
struct nat64stl_cfg {
struct named_object no;
uint16_t map64; /* table with 6to4 mapping */
uint16_t map46; /* table with 4to6 mapping */
struct in6_addr prefix6;/* IPv6 prefix */
uint8_t plen6; /* prefix length */
uint32_t flags; /* flags for internal use */
struct nat64_config base;
#define NAT64STL_KIDX 0x0100
#define NAT64STL_46T 0x0200
#define NAT64STL_64T 0x0400
#define NAT64STL_FLAGSMASK (NAT64_LOG) /* flags to pass to userland */
char name[64];
nat64_stats_block stats;
};
VNET_DECLARE(uint16_t, nat64stl_eid);

View File

@ -57,15 +57,16 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_fw.h>
#include <netinet6/in6_var.h>
#include <netinet6/ip6_var.h>
#include <netinet6/ip_fw_nat64.h>
#include <netpfil/ipfw/ip_fw_private.h>
#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
#include <netpfil/ipfw/nat64/nat64stl.h>
#include <netinet6/ip_fw_nat64.h>
#include "nat64stl.h"
VNET_DEFINE(uint16_t, nat64stl_eid) = 0;
static struct nat64stl_cfg *nat64stl_alloc_config(const char *name, uint8_t set);
static struct nat64stl_cfg *nat64stl_alloc_config(const char *name,
uint8_t set);
static void nat64stl_free_config(struct nat64stl_cfg *cfg);
static struct nat64stl_cfg *nat64stl_find(struct namedobj_instance *ni,
const char *name, uint8_t set);
@ -76,7 +77,7 @@ nat64stl_alloc_config(const char *name, uint8_t set)
struct nat64stl_cfg *cfg;
cfg = malloc(sizeof(struct nat64stl_cfg), M_IPFW, M_WAITOK | M_ZERO);
COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK);
COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
cfg->no.name = cfg->name;
cfg->no.etlv = IPFW_TLV_NAT64STL_NAME;
cfg->no.set = set;
@ -88,7 +89,7 @@ static void
nat64stl_free_config(struct nat64stl_cfg *cfg)
{
COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS);
COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
free(cfg, M_IPFW);
}
@ -98,9 +99,9 @@ nat64stl_export_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
{
struct named_object *no;
uc->prefix6 = cfg->prefix6;
uc->plen6 = cfg->plen6;
uc->flags = cfg->flags & NAT64STL_FLAGSMASK;
uc->prefix6 = cfg->base.prefix6;
uc->plen6 = cfg->base.plen6;
uc->flags = cfg->base.flags & NAT64STL_FLAGSMASK;
uc->set = cfg->no.set;
strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
@ -148,15 +149,15 @@ nat64stl_create_internal(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0)
return (ENOSPC);
cfg->flags |= NAT64STL_KIDX;
cfg->base.flags |= NAT64STL_KIDX;
if (ipfw_ref_table(ch, &i->ntlv4, &cfg->map46) != 0)
return (EINVAL);
cfg->flags |= NAT64STL_46T;
cfg->base.flags |= NAT64STL_46T;
if (ipfw_ref_table(ch, &i->ntlv6, &cfg->map64) != 0)
return (EINVAL);
cfg->flags |= NAT64STL_64T;
cfg->base.flags |= NAT64STL_64T;
ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no);
@ -188,9 +189,8 @@ nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
if (ipfw_check_object_name_generic(uc->name) != 0)
return (EINVAL);
if (!IN6_IS_ADDR_WKPFX(&uc->prefix6))
return (EINVAL);
if (uc->plen6 != 96 || uc->set >= IPFW_MAX_SETS)
if (uc->set >= IPFW_MAX_SETS ||
nat64_check_prefix6(&uc->prefix6, uc->plen6) != 0)
return (EINVAL);
/* XXX: check types of tables */
@ -206,9 +206,11 @@ nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
IPFW_UH_RUNLOCK(ch);
cfg = nat64stl_alloc_config(uc->name, uc->set);
cfg->prefix6 = uc->prefix6;
cfg->plen6 = uc->plen6;
cfg->flags = uc->flags & NAT64STL_FLAGSMASK;
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.flags |= NAT64_WKPFX;
IPFW_UH_WLOCK(ch);
@ -225,11 +227,11 @@ nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
return (0);
}
if (cfg->flags & NAT64STL_KIDX)
if (cfg->base.flags & NAT64STL_KIDX)
ipfw_objhash_free_idx(ni, cfg->no.kidx);
if (cfg->flags & NAT64STL_46T)
if (cfg->base.flags & NAT64STL_46T)
ipfw_unref_table(ch, cfg->map46);
if (cfg->flags & NAT64STL_64T)
if (cfg->base.flags & NAT64STL_64T)
ipfw_unref_table(ch, cfg->map64);
IPFW_UH_WUNLOCK(ch);
@ -289,8 +291,9 @@ nat64stl_config(struct ip_fw_chain *ch, ip_fw3_opheader *op,
* For now allow to change only following values:
* flags.
*/
cfg->flags &= ~NAT64STL_FLAGSMASK;
cfg->flags |= uc->flags & NAT64STL_FLAGSMASK;
cfg->base.flags &= ~NAT64STL_FLAGSMASK;
cfg->base.flags |= uc->flags & NAT64STL_FLAGSMASK;
IPFW_UH_WUNLOCK(ch);
return (0);
}
@ -389,7 +392,7 @@ nat64stl_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
}
#define __COPY_STAT_FIELD(_cfg, _stats, _field) \
(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field)
(_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field)
static void
export_stats(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
struct ipfw_nat64stl_stats *stats)
@ -482,7 +485,7 @@ nat64stl_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
IPFW_UH_WUNLOCK(ch);
return (ESRCH);
}
COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS);
COUNTER_ARRAY_ZERO(cfg->base.stats.cnt, NAT64STATS);
IPFW_UH_WUNLOCK(ch);
return (0);
}