diff options
author | Chion Tang <sdspeedonion@gmail.com> | 2018-03-16 16:04:34 +0000 |
---|---|---|
committer | Chion Tang <sdspeedonion@gmail.com> | 2018-03-16 16:04:43 +0000 |
commit | 0adc60f09e4dca90f050a7d6d2b0e1ee8241d8f5 (patch) | |
tree | d245db532d4179ea6e37888b3efb1552197f9c11 | |
parent | fix: missing header for old kernels (diff) | |
download | netfilter-full-cone-nat-0adc60f09e4dca90f050a7d6d2b0e1ee8241d8f5.tar.gz netfilter-full-cone-nat-0adc60f09e4dca90f050a7d6d2b0e1ee8241d8f5.tar.bz2 netfilter-full-cone-nat-0adc60f09e4dca90f050a7d6d2b0e1ee8241d8f5.zip |
feature: remove xt_FULLCONENAT-old-kernel.c and modify README
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | xt_FULLCONENAT-old-kernel.c | 368 |
2 files changed, 1 insertions, 369 deletions
@@ -14,7 +14,7 @@ Prerequisites: * kernel source * iptables source (git://git.netfilter.org/iptables.git) -Replace `xt_FULLCONENAT.c` with `xt_FULLCONENAT-old-kernel.c` if your kernel version is somehow below 4.1x and have issue compiling the module source. +Confirm the kernel configuration option `CONFIG_NF_CONNTRACK_EVENTS` is enabled. If this option is disabled on your system, enable it and rebuild your netfilter modules. Kernel Module (as standalone module) ------------- diff --git a/xt_FULLCONENAT-old-kernel.c b/xt_FULLCONENAT-old-kernel.c deleted file mode 100644 index 9a8b6ed..0000000 --- a/xt_FULLCONENAT-old-kernel.c +++ /dev/null @@ -1,368 +0,0 @@ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/random.h> -#include <linux/hashtable.h> -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/netfilter.h> -#include <linux/netfilter_ipv4.h> -#include <linux/netfilter/x_tables.h> -#include <net/netfilter/nf_nat.h> -#include <net/netfilter/nf_conntrack.h> -#include <net/netfilter/nf_conntrack_core.h> - -#define xt_hooknum(par) (par->hooknum) - -struct natmapping { - uint16_t port; - __be32 int_addr; /* internal source ip address */ - uint16_t int_port; /* internal source port */ - struct nf_conntrack_tuple original_tuple; - - struct hlist_node node; -}; - -static DEFINE_HASHTABLE(mapping_table, 10); - -static DEFINE_SPINLOCK(fullconenat_lock); - -static struct natmapping* get_mapping(const uint16_t port, const int create_new) { - struct natmapping *p_current, *p_new; - - hash_for_each_possible(mapping_table, p_current, node, port) { - if (p_current->port == port) { - return p_current; - } - } - - if (!create_new) { - return NULL; - } - - p_new = kmalloc(sizeof(struct natmapping), GFP_ATOMIC); - if (p_new == NULL) { - return NULL; - } - p_new->port = port; - p_new->int_addr = 0; - p_new->int_port = 0; - memset(&p_new->original_tuple, 0, sizeof(struct nf_conntrack_tuple)); - - hash_add(mapping_table, &p_new->node, port); - - return p_new; -} - -static struct natmapping* get_mapping_by_original_src(const __be32 src_ip, const uint16_t src_port) { - struct natmapping *p_current; - int i; - hash_for_each(mapping_table, i, p_current, node) { - if (p_current->int_addr == src_ip && p_current->int_port == src_port) { - return p_current; - } - } - return NULL; -} - -static void destroy_mappings(void) { - struct natmapping *p_current; - struct hlist_node *tmp; - int i; - - spin_lock(&fullconenat_lock); - - hash_for_each_safe(mapping_table, i, tmp, p_current, node) { - hash_del(&p_current->node); - kfree(p_current); - } - - spin_unlock(&fullconenat_lock); -} - -static int is_mapping_active(const struct natmapping* mapping, const struct nf_conn *ct) -{ - const struct nf_conntrack_zone *zone; - struct net *net; - struct nf_conntrack_tuple_hash *original_tuple_hash; - - if (mapping->port == 0 || mapping->int_addr == 0 || mapping->int_port == 0) { - return 0; - } - - /* get corresponding conntrack from the saved tuple */ - net = nf_ct_net(ct); - zone = nf_ct_zone(ct); - if (net == NULL || zone == NULL) { - return 0; - } - original_tuple_hash = nf_conntrack_find_get(net, zone, &mapping->original_tuple); - - if (original_tuple_hash) { - /* if the corresponding conntrack is found, consider the mapping is active */ - return 1; - } else { - return 0; - } -} - -static void clear_inactive_mappings(const struct nf_conn *ct) { - struct natmapping *p_current; - struct hlist_node *tmp; - int i; - - spin_lock(&fullconenat_lock); - - hash_for_each_safe(mapping_table, i, tmp, p_current, node) { - if (!is_mapping_active(p_current, ct)) { - hash_del(&p_current->node); - kfree(p_current); - } - } - - spin_unlock(&fullconenat_lock); -} - -static __be32 get_device_ip(const struct net_device* dev) { - struct in_device* in_dev; - struct in_ifaddr* if_info; - - in_dev = dev->ip_ptr; - if (in_dev == NULL) { - return 0; - } - if_info = in_dev->ifa_list; - if (if_info) { - return if_info->ifa_local; - } else { - return 0; - } -} - -static void fullconenat_tg_destroy(const struct xt_tgdtor_param *par) -{ - -} - -static uint16_t find_appropriate_port(const uint16_t original_port, const struct nf_nat_ipv4_range *range, struct nf_conn *ct) { - uint16_t min, start, selected, range_size, i; - struct natmapping* mapping = NULL; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - min = be16_to_cpu((range->min).udp.port); - range_size = be16_to_cpu((range->max).udp.port) - min + 1; - } else { - /* minimum port is 1024. same behavior as default linux NAT. */ - min = 1024; - range_size = 65535 - min + 1; - } - - if ((range->flags & NF_NAT_RANGE_PROTO_RANDOM) - || (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)) { - /* for now we do the same thing for both --random and --random-fully */ - - /* select a random starting point */ - start = (uint16_t)(prandom_u32() % (u32)range_size); - } else { - - if ((original_port >= min && original_port <= min + range_size - 1) - || !(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) { - /* 1. try to preserve the port if it's available */ - mapping = get_mapping(original_port, 0); - if (mapping == NULL || !(is_mapping_active(mapping, ct))) { - return original_port; - } - } - - /* otherwise, we start from zero */ - start = 0; - } - - for (i = 0; i < range_size; i++) { - /* 2. try to find an available port */ - selected = min + ((start + i) % range_size); - mapping = get_mapping(selected, 0); - if (mapping == NULL || !(is_mapping_active(mapping, ct))) { - return selected; - } - } - - /* 3. at least we tried. rewrite a privous mapping. */ - return min + start; -} - -static unsigned int fullconenat_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - const struct nf_nat_ipv4_multi_range_compat *mr; - const struct nf_nat_ipv4_range *range; - - struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - struct nf_conntrack_tuple *ct_tuple, *ct_tuple_origin; - - struct natmapping *mapping, *src_mapping; - unsigned int ret; - struct nf_nat_range newrange; - - __be32 new_ip, ip; - uint16_t port, original_port, want_port; - uint8_t protonum; - - ip = 0; - original_port = 0; - - mr = par->targinfo; - range = &mr->range[0]; - - mapping = NULL; - ret = XT_CONTINUE; - - ct = nf_ct_get(skb, &ctinfo); - - clear_inactive_mappings(ct); - - memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); - memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); - newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; - newrange.min_proto = mr->range[0].min; - newrange.max_proto = mr->range[0].max; - - if (xt_hooknum(par) == NF_INET_PRE_ROUTING) { - /* inbound packets */ - ct_tuple = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - - protonum = (ct_tuple->dst).protonum; - if (protonum != IPPROTO_UDP) { - return ret; - } - ip = (ct_tuple->src).u3.ip; - port = be16_to_cpu((ct_tuple->dst).u.udp.port); - - spin_lock(&fullconenat_lock); - - /* find an active mapping based on the inbound port */ - mapping = get_mapping(port, 0); - if (mapping == NULL) { - spin_unlock(&fullconenat_lock); - return ret; - } - if (is_mapping_active(mapping, ct)) { - newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED; - newrange.min_addr.ip = mapping->int_addr; - newrange.max_addr.ip = mapping->int_addr; - newrange.min_proto.udp.port = cpu_to_be16(mapping->int_port); - newrange.max_proto = newrange.min_proto; - - ret = nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); - } - spin_unlock(&fullconenat_lock); - return ret; - - - } else if (xt_hooknum(par) == NF_INET_POST_ROUTING) { - /* outbound packets */ - spin_lock(&fullconenat_lock); - - ct_tuple_origin = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - protonum = (ct_tuple_origin->dst).protonum; - - if (protonum == IPPROTO_UDP) { - ip = (ct_tuple_origin->src).u3.ip; - original_port = be16_to_cpu((ct_tuple_origin->src).u.udp.port); - - src_mapping = get_mapping_by_original_src(ip, original_port); - if (src_mapping != NULL && is_mapping_active(src_mapping, ct)) { - - /* outbound nat: if a previously established mapping is active, - we will reuse that mapping. */ - - newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED; - newrange.min_proto.udp.port = cpu_to_be16(src_mapping->port); - newrange.max_proto = newrange.min_proto; - - } else { - want_port = find_appropriate_port(original_port, range, ct); - - newrange.flags = NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED; - newrange.min_proto.udp.port = cpu_to_be16(want_port); - newrange.max_proto = newrange.min_proto; - - } - } - - new_ip = get_device_ip(skb->dev); - newrange.min_addr.ip = new_ip; - newrange.max_addr.ip = new_ip; - - ret = nf_nat_setup_info(ct, &newrange, HOOK2MANIP(xt_hooknum(par))); - - if (protonum != IPPROTO_UDP || ret != NF_ACCEPT) { - spin_unlock(&fullconenat_lock); - return ret; - } - - /* the reply tuple contains the mapped port. */ - ct_tuple = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple); - - port = be16_to_cpu((ct_tuple->dst).u.udp.port); - - /* store the mapping information to our mapping table */ - mapping = get_mapping(port, 1); - if (mapping == NULL) { - spin_unlock(&fullconenat_lock); - return ret; - } - mapping->int_addr = ip; - mapping->int_port = original_port; - /* save the original source tuple */ - memcpy(&mapping->original_tuple, ct_tuple_origin, sizeof(struct nf_conntrack_tuple)); - - spin_unlock(&fullconenat_lock); - - return ret; - } - - return ret; -} - -static int fullconenat_tg_check(const struct xt_tgchk_param *par) -{ - - return 0; -} - -static struct xt_target tg_reg[] __read_mostly = { - { - .name = "FULLCONENAT", - .family = NFPROTO_IPV4, - .revision = 0, - .target = fullconenat_tg, - .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), - .table = "nat", - .hooks = (1 << NF_INET_PRE_ROUTING) | - (1 << NF_INET_POST_ROUTING), - .checkentry = fullconenat_tg_check, - .destroy = fullconenat_tg_destroy, - .me = THIS_MODULE, - }, -}; - -static int __init tg_init(void) -{ - return xt_register_targets(tg_reg, ARRAY_SIZE(tg_reg)); -} - -static void tg_exit(void) -{ - xt_unregister_targets(tg_reg, ARRAY_SIZE(tg_reg)); - - destroy_mappings(); -} - -module_init(tg_init); -module_exit(tg_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Xtables: implementation of RFC3489 full cone NAT"); -MODULE_AUTHOR("Chion Tang <tech@chionlab.moe>"); -MODULE_ALIAS("ipt_FULLCONENAT"); |