From 68071c299a95327a7869cc160fabb6610fde74cd Mon Sep 17 00:00:00 2001 From: ae Date: Wed, 9 May 2018 11:59:24 +0000 Subject: [PATCH] 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 --- sbin/ipfw/ipfw2.h | 1 + sbin/ipfw/nat64lsn.c | 12 +- sbin/ipfw/nat64stl.c | 23 +- sys/modules/ipfw_nat64/Makefile | 2 + sys/netpfil/ipfw/nat64/ip_fw_nat64.c | 21 +- sys/netpfil/ipfw/nat64/ip_fw_nat64.h | 84 ++----- sys/netpfil/ipfw/nat64/nat64_translate.c | 264 +++++++++++++--------- sys/netpfil/ipfw/nat64/nat64_translate.h | 118 ++++++---- sys/netpfil/ipfw/nat64/nat64lsn.c | 110 +++++---- sys/netpfil/ipfw/nat64/nat64lsn.h | 11 +- sys/netpfil/ipfw/nat64/nat64lsn_control.c | 34 +-- sys/netpfil/ipfw/nat64/nat64stl.c | 31 ++- sys/netpfil/ipfw/nat64/nat64stl.h | 8 +- sys/netpfil/ipfw/nat64/nat64stl_control.c | 53 +++-- 14 files changed, 404 insertions(+), 368 deletions(-) diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 7791ed71fc66..6834d411f36c 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -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 */ diff --git a/sbin/ipfw/nat64lsn.c b/sbin/ipfw/nat64lsn.c index 7fd3c7770060..a364f0178556 100644 --- a/sbin/ipfw/nat64lsn.c +++ b/sbin/ipfw/nat64lsn.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 || diff --git a/sbin/ipfw/nat64stl.c b/sbin/ipfw/nat64stl.c index 6cd936c4c469..27653aa5b4df 100644 --- a/sbin/ipfw/nat64stl.c +++ b/sbin/ipfw/nat64stl.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); #include #include -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"); diff --git a/sys/modules/ipfw_nat64/Makefile b/sys/modules/ipfw_nat64/Makefile index c696f5bd5ab6..af7aec875430 100644 --- a/sys/modules/ipfw_nat64/Makefile +++ b/sys/modules/ipfw_nat64/Makefile @@ -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 diff --git a/sys/netpfil/ipfw/nat64/ip_fw_nat64.c b/sys/netpfil/ipfw/nat64/ip_fw_nat64.c index 58c4427c6025..b51d19d6ed17 100644 --- a/sys/netpfil/ipfw/nat64/ip_fw_nat64.c +++ b/sys/netpfil/ipfw/nat64/ip_fw_nat64.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * Copyright (c) 2015-2018 Yandex LLC + * Copyright (c) 2015-2018 Andrey V. Elsukov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,18 +46,17 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#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 diff --git a/sys/netpfil/ipfw/nat64/ip_fw_nat64.h b/sys/netpfil/ipfw/nat64/ip_fw_nat64.h index 1d2bb7749ed4..30c46e17e274 100644 --- a/sys/netpfil/ipfw/nat64/ip_fw_nat64.h +++ b/sys/netpfil/ipfw/nat64/ip_fw_nat64.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * Copyright (c) 2015-2018 Yandex LLC + * Copyright (c) 2015-2018 Andrey V. Elsukov * 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_ */ diff --git a/sys/netpfil/ipfw/nat64/nat64_translate.c b/sys/netpfil/ipfw/nat64/nat64_translate.c index 6fd08d5bfd32..bbc073a9514d 100644 --- a/sys/netpfil/ipfw/nat64/nat64_translate.c +++ b/sys/netpfil/ipfw/nat64/nat64_translate.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * Copyright (c) 2015-2018 Yandex LLC + * Copyright (c) 2015-2018 Andrey V. Elsukov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,10 +66,11 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include +#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); } diff --git a/sys/netpfil/ipfw/nat64/nat64_translate.h b/sys/netpfil/ipfw/nat64/nat64_translate.h index 06918661c3f0..9b79aea0a10f 100644 --- a/sys/netpfil/ipfw/nat64/nat64_translate.h +++ b/sys/netpfil/ipfw/nat64/nat64_translate.h @@ -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 diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.c b/sys/netpfil/ipfw/nat64/nat64lsn.c index 78a2aa9fff2a..d71d6227682d 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn.c +++ b/sys/netpfil/ipfw/nat64/nat64lsn.c @@ -64,11 +64,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include #include +#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); diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.h b/sys/netpfil/ipfw/nat64/nat64lsn.h index 7e65d677979d..59ed1cc841b3 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn.h +++ b/sys/netpfil/ipfw/nat64/nat64lsn.h @@ -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, diff --git a/sys/netpfil/ipfw/nat64/nat64lsn_control.c b/sys/netpfil/ipfw/nat64/nat64lsn_control.c index 001db07c0fb2..a90e3cfb6d02 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn_control.c +++ b/sys/netpfil/ipfw/nat64/nat64lsn_control.c @@ -51,11 +51,11 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include -#include -#include -#include + +#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); } diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c index 87e64ec34b3b..8770b94623d8 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl.c +++ b/sys/netpfil/ipfw/nat64/nat64stl.c @@ -55,11 +55,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include #include +#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 diff --git a/sys/netpfil/ipfw/nat64/nat64stl.h b/sys/netpfil/ipfw/nat64/nat64stl.h index ec182740a2df..42d70e8905a8 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl.h +++ b/sys/netpfil/ipfw/nat64/nat64stl.h @@ -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); diff --git a/sys/netpfil/ipfw/nat64/nat64stl_control.c b/sys/netpfil/ipfw/nat64/nat64stl_control.c index aa21e08596a2..457556aca919 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl_control.c +++ b/sys/netpfil/ipfw/nat64/nat64stl_control.c @@ -57,15 +57,16 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include -#include -#include -#include + +#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); }