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:
parent
2149cb08d1
commit
68071c299a
@ -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 */
|
||||
|
@ -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 ||
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user