diff options
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | ip6t_DNPTV6.c | 83 | ||||
-rw-r--r-- | ip6t_MAP66.c | 381 | ||||
-rw-r--r-- | ip6t_MAP66.h | 30 | ||||
-rw-r--r-- | ip6t_NPTV6.h | 16 | ||||
-rw-r--r-- | ip6t_NPTV6_common.h | 88 | ||||
-rw-r--r-- | ip6t_SNPTV6.c | 83 | ||||
-rw-r--r-- | libip6t_DNPTV6.c | 46 | ||||
-rw-r--r-- | libip6t_MAP66.c | 227 | ||||
-rw-r--r-- | libip6t_NPTV6.c | 62 | ||||
-rw-r--r-- | libip6t_NPTV6.h | 29 | ||||
-rw-r--r-- | libip6t_SNPTV6.c | 46 |
13 files changed, 479 insertions, 653 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2748eec --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.o +*~ +*.so +*.ko +*.mod.c +.* +Module.symvers +modules.order @@ -1,30 +1,33 @@ -obj-m := ip6t_MAP66.o +obj-m := ip6t_SNPTV6.o ip6t_DNPTV6.o KVERSION := $(shell uname -r) KPATH := /lib/modules/$(KVERSION)/build -IPTABLES_VERSION := $(shell (/sbin/ip6tables --version 2>&- || ip6tables --version)|sed 's/^.*\([[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+\).*/\1/') -IPTABLES_VERSION_CODE := $(shell echo $$(( $$(echo $(IPTABLES_VERSION)|sed 's/^.*\([[:digit:]]\+\)\.\([[:digit:]]\+\)\.\([[:digit:]]\+\).*/\1 * 65536 + \2 * 256 + \3/') ))) ifeq ($(DEBUG),1) EXTRA_CFLAGS := -DDEBUG endif -all: libip6t_MAP66.so +all: module libip6t_SNPTV6.so libip6t_DNPTV6.so + +module: $(MAKE) -C $(KPATH) M=$(PWD) modules -libip6t_MAP66.so: libip6t_MAP66.o - gcc -shared -o $@ $< +libip6t_SNPTV6.so: libip6t_SNPTV6.o libip6t_NPTV6.o + gcc -shared -o $@ $^ -libip6t_MAP66.o: libip6t_MAP66.c ip6t_MAP66.h Makefile - gcc $(CFLAGS) -DIPTABLES_VERSION=\"$(IPTABLES_VERSION)\" -DIPTABLES_VERSION_CODE=$(IPTABLES_VERSION_CODE) -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT -Werror -Wall -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Winline -pipe -DXTABLES_LIBDIR=\"/usr/local/libexec/xtables\" -D_INIT=libip6t_MAP66_init -DPIC -fPIC -g -O2 -o $@ -c $< +libip6t_DNPTV6.so: libip6t_DNPTV6.o libip6t_NPTV6.o + gcc -shared -o $@ $^ -clean: - $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) clean - rm -f *.so - rm -f *~ +libip6t_NPTV6.o: libip6t_NPTV6.c libip6t_NPTV6.h ip6t_NPTV6.h Makefile + gcc $(CFLAGS) -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT -Werror -Wall -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Winline -pipe -DXTABLES_LIBDIR=\"/usr/lib/iptables\" -DPIC -fPIC -g -O2 -o $@ -c $< -install: /lib/xtables/libip6t_MAP66.so +libip6t_SNPTV6.o: libip6t_SNPTV6.c libip6t_NPTV6.h ip6t_NPTV6.h Makefile + gcc $(CFLAGS) -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT -Werror -Wall -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Winline -pipe -DXTABLES_LIBDIR=\"/usr/lib/iptables\" -DPIC -fPIC -g -O2 -o $@ -c $< -/lib/xtables/libip6t_MAP66.so: libip6t_MAP66.so - cp $< $@ +libip6t_DNPTV6.o: libip6t_DNPTV6.c libip6t_NPTV6.h ip6t_NPTV6.h Makefile + gcc $(CFLAGS) -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT -Werror -Wall -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Winline -pipe -DXTABLES_LIBDIR=\"/usr/lib/iptables\" -DPIC -fPIC -g -O2 -o $@ -c $< + +clean: + $(MAKE) -C $(KPATH) M=$(PWD) clean + rm -f libip6t_SNPTV6.so libip6t_DNPTV6.so *.o README.txt: README.dbk xmlto text README.dbk diff --git a/ip6t_DNPTV6.c b/ip6t_DNPTV6.c new file mode 100644 index 0000000..96d16e8 --- /dev/null +++ b/ip6t_DNPTV6.c @@ -0,0 +1,83 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <net/ipv6.h> + +#include "ip6t_NPTV6_common.h" + +MODULE_AUTHOR("Matthias Schiffer <mschiffer()universe-factory.net>"); +MODULE_DESCRIPTION("Xtables: Destination NPTv6 - IPv6-to-IPv6 Network Prefix Translation"); +MODULE_LICENSE("GPL"); + + +static unsigned int dnptv6_tg6(struct sk_buff *skb, const struct xt_action_param *par) +{ + struct ipv6hdr* hdr = ipv6_hdr(skb); + const struct ip6t_nptv6_info *info = par->targinfo; + + pr_devel("DNPTV6: enter in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", + NULL != par->in ? par->in->name : "", + NULL != par->out ? par->out->name : "", + NIP6(hdr->saddr), NIP6(hdr->daddr)); + + if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) { + pr_devel("DNPTV6: unwriteable, dropped\n"); + return NF_DROP; + } + hdr = ipv6_hdr(skb); + + if (!translate_address(&hdr->daddr, &info->nptv6_prefix, info->nptv6_prefix_len)) { + pr_devel("DNPTV6: untranslatable address\n"); + return NF_DROP; + } + + pr_devel("DNPTV6: exit in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", + NULL != par->in ? par->in->name : "", + NULL != par->out ? par->out->name : "", + NIP6(hdr->saddr), NIP6(hdr->daddr)); + + return NF_ACCEPT; +} + +static int dnptv6_tg6_check(const struct xt_tgchk_param *par) +{ + const struct ip6t_nptv6_info *info = par->targinfo; + + if (info->nptv6_prefix_len > 64) { + printk("DNPTV6: Prefix length longer than 64 given\n"); + return -EINVAL; + } + + return 0; +} + +static struct xt_target dnptv6_tg6_reg __read_mostly = { + .name = "DNPTV6", + .family = NFPROTO_IPV6, + .target = dnptv6_tg6, + .checkentry = dnptv6_tg6_check, + .targetsize = sizeof(struct ip6t_nptv6_info), + .table = "mangle", + .hooks = (1 << NF_INET_PRE_ROUTING), + .me = THIS_MODULE, +}; + +static int __init dnptv6_tg6_init(void) +{ + return xt_register_target(&dnptv6_tg6_reg); +} + +static void __exit dnptv6_tg6_exit(void) +{ + xt_unregister_target(&dnptv6_tg6_reg); +} + +module_init(dnptv6_tg6_init); +module_exit(dnptv6_tg6_exit); diff --git a/ip6t_MAP66.c b/ip6t_MAP66.c deleted file mode 100644 index 1711757..0000000 --- a/ip6t_MAP66.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * MAP66: Network Address Translation IPv6-to-IPv6 as - * proposed in the IETF's second NAT66 draft document. - * (c) 2010 sven-ola()gmx.de - */ - -#include <linux/module.h> -#include <linux/version.h> -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <net/ipv6.h> - -#include <linux/tcp.h> -#include <linux/udp.h> -#include <linux/icmpv6.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) -# include <linux/dccp.h> -#endif - -#include "ip6t_MAP66.h" - -MODULE_AUTHOR("Sven-Ola <sven-ola()gmx.de>"); -MODULE_DESCRIPTION("Xtables: MAP66 - IPv6 to IPv6 SNAT"); -MODULE_LICENSE("GPL"); - -/* One's complement add */ -static inline u_int16_t add16( - u_int16_t a, - u_int16_t b) -{ - a += b; - return a + (a < b); -} - -/* Calc one's complement csum */ -static inline u_int16_t csum16( - const u_int16_t *buf, - int len) -{ - u_int16_t csum = 0; - while(len--) csum = add16(csum, *buf++); - return csum; -} - -/* Perform mapping with csum update, see RFC 1624 */ -static void map16( - u_int16_t *dest, - const u_int16_t *source, - int len, - u_int16_t csum, - u_int16_t* pcsum) -{ - if (NULL == pcsum) { - pcsum = dest + len; - } - *pcsum = ~add16( - add16( - ~(*pcsum), - ~csum16(dest, len) - ), - csum - ); - memcpy(dest, source, len * sizeof(u_int16_t)); -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -# define rcu_dereference(p) p -# define ipv6_addr_equal(a, b) 0 == ipv6_addr_cmp(a, b) -# define ipv6_hdr(skb) skb->nh.ipv6h -# ifndef bool -# define bool int -# define false 0 -# define true 1 -# endif -# define xt_target ip6t_target -# define __read_mostly -# define xt_register_target ip6t_register_target -# define xt_unregister_target ip6t_unregister_target -#endif - -#ifndef pr_devel -# ifdef DEBUG -# define pr_devel(fmt, ...) printk(fmt, ##__VA_ARGS__) -# else -# define pr_devel(fmt, ...) ({ if (0); }) -# endif -#endif - -#ifndef NIP6_FMT -# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" -# define NIP6(addr) \ - ntohs((addr).s6_addr16[0]), \ - ntohs((addr).s6_addr16[1]), \ - ntohs((addr).s6_addr16[2]), \ - ntohs((addr).s6_addr16[3]), \ - ntohs((addr).s6_addr16[4]), \ - ntohs((addr).s6_addr16[5]), \ - ntohs((addr).s6_addr16[6]), \ - ntohs((addr).s6_addr16[7]) -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) -# define NF_INET_PRE_ROUTING NF_IP6_PRE_ROUTING -# define NF_INET_POST_ROUTING NF_IP6_POST_ROUTING -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,26) - -struct xt_target_param { - const struct net_device *in, *out; - const void *targinfo; - unsigned int hooknum; -}; - -struct xt_tgchk_param { - void *targinfo; -}; - -#endif - -static bool is_my_ipv6_addr( - const struct net_device *dev, - const struct in6_addr *addr) -{ - if (NULL != dev) { - const struct inet6_ifaddr *ifa; - const struct inet6_dev *idev = rcu_dereference(dev->ip6_ptr); - for (ifa = idev->addr_list; NULL != ifa; ifa = ifa->if_next) { - if (ipv6_addr_equal(&ifa->addr, addr)) return true; - } - } - return false; -} - -static unsigned int MAP66_tg6( - struct sk_buff *skb, - const struct xt_target_param *par) -{ - struct ipv6hdr* hdr = ipv6_hdr(skb); - unsigned char* transport = (unsigned char* )(hdr + 1); - u8 nexthdr = 0; - u_int16_t* pcsum = NULL; - const struct ip6t_MAP66_info *info = par->targinfo; - - pr_devel("MAP66: enter in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", - NULL != par->in ? par->in->name : "", - NULL != par->out ? par->out->name : "", - NIP6(hdr->saddr), NIP6(hdr->daddr)); - -#if 0 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if (skb_cloned(skb) && !skb->sk) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) { - pr_devel("MAP66: cannot copy, dropped\n"); - return NF_DROP; - } - kfree_skb(skb); - skb = nskb; - } -#else - if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) { - pr_devel("MAP66: unwriteable, dropped\n"); - return NF_DROP; - } -#endif - hdr = ipv6_hdr(skb); -#endif - - if (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags)) { - nexthdr = hdr->nexthdr; - if (ipv6_ext_hdr(nexthdr)) { - int hoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - , skb->len - sizeof(struct ipv6hdr) -#endif - ); - if (hoff < 0) { - pr_devel("MAP66: Unsupported packet dropped\n"); - return NF_DROP; - } - transport += hoff; - } - switch(nexthdr) { - case IPPROTO_TCP: - pcsum = &((struct tcphdr*)transport)->check; - break; - case IPPROTO_UDP: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) - case IPPROTO_UDPLITE: -#endif - pcsum = &((struct udphdr*)transport)->check; - break; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) - case IPPROTO_DCCP: - pcsum = &((struct dccp_hdr*)transport)->dccph_checksum; - break; -#endif - case IPPROTO_ICMPV6: - pcsum = &((struct icmp6hdr*)transport)->icmp6_cksum; - break; - default: - pr_devel("MAP66: Unsupported protocol %d dropped\n", nexthdr); - return NF_DROP; - } - } - - if (0 != (IP6T_MAP66_OPT_DST_TO & info->mapflags)) { - if (0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags) || !is_my_ipv6_addr( - NF_INET_PRE_ROUTING == par->hooknum ? par->in : par->out, &hdr->daddr)) - { - map16((u_int16_t *)&hdr->daddr, (u_int16_t *)&info->pfix_dst_to, - info->pfix_dst_len, info->pfix_dst_csum, pcsum); - if (NULL != pcsum && IPPROTO_ICMPV6 == nexthdr && 128 > ((struct icmp6hdr*)transport)->icmp6_type) { - printk("Need to change returning ICMPv6 dest addr for traceroute\n"); - } - } - } - - if (0 != (IP6T_MAP66_OPT_SRC_TO & info->mapflags)) { - map16((u_int16_t *)&hdr->saddr, (u_int16_t *)&info->pfix_src_to, - info->pfix_src_len, info->pfix_src_csum, pcsum); - if (0 == (IP6T_MAP66_OPT_NOCHECK & info->mapflags) && is_my_ipv6_addr( - NF_INET_PRE_ROUTING == par->hooknum ? par->in : par->out, &hdr->saddr)) - { - return NF_DROP; - } - } - - pr_devel("MAP66: exit in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", - NULL != par->in ? par->in->name : "", - NULL != par->out ? par->out->name : "", - NIP6(hdr->saddr), NIP6(hdr->daddr)); - - return IP6T_CONTINUE; -} - -static bool MAP66_tg6_check( - const struct xt_tgchk_param *par) -{ - const struct ip6t_MAP66_info *info = par->targinfo; - - if (0 == ((IP6T_MAP66_OPT_DST_TO | IP6T_MAP66_OPT_SRC_TO) & info->mapflags)) { - printk("MAP66: No --" IP6T_MAP66_DST_TO " nor --" IP6T_MAP66_SRC_TO "\n"); - return false; - } - - if (0 != (IP6T_MAP66_OPT_DST_TO & info->mapflags) && (0 >= info->pfix_dst_len || - (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags) ? 8 : 7) < info->pfix_dst_len)) - { - if (8 == info->pfix_dst_len) { - printk("MAP66: --" IP6T_MAP66_DST_TO " prefix length /%d only " - "possible with --csum\n", 16 * info->pfix_dst_len); - } - else { - printk("MAP66: Unsupported --" IP6T_MAP66_DST_TO " prefix " - "length /%d\n", 16 * info->pfix_dst_len); - } - return false; - } - - if (0 != (IP6T_MAP66_OPT_SRC_TO & info->mapflags) && (0 >= info->pfix_src_len || - (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags) ? 8 : 7) < info->pfix_src_len)) - { - if (8 == info->pfix_src_len) { - printk("MAP66: --" IP6T_MAP66_SRC_TO " prefix length /%d only " - "possible with --csum\n", 16 * info->pfix_src_len); - } - else { - printk("MAP66: Unsupported --" IP6T_MAP66_SRC_TO " prefix " - "length /%d\n", 16 * info->pfix_src_len); - } - return false; - } - return true; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - -static unsigned int MAP66_tg6_24( - struct sk_buff **pskb, - unsigned int hooknum, - const struct net_device *in, - const struct net_device *out, - const void *targinfo, - void *userinfo) -{ - const struct xt_target_param par = { - .in = in, - .out = out, - .hooknum = hooknum, - .targinfo = targinfo, - }; - return MAP66_tg6(*pskb, &par); -} - -static int MAP66_tg6_check_24( - const char *table, - const struct ip6t_entry *entry, - void *targinfo, - unsigned int targinfosize, - unsigned int hook_mask) -{ - const struct xt_tgchk_param par = { - .targinfo = targinfo, - }; - if (0 != (hook_mask & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_POST_ROUTING)))) { - printk("MAP66: Only valid for PRE_ROUTING or POST_ROUTING.\n"); - return 0; - } - return MAP66_tg6_check(&par); -} - -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - -static unsigned int MAP66_tg6_26( - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const struct xt_target *target, - const void *targinfo) -{ - const struct xt_target_param par = { - .in = in, - .out = out, - .hooknum = hooknum, - .targinfo = targinfo, - }; - return MAP66_tg6(skb, &par); -} - -static bool MAP66_tg6_check_26( - const char *table, - const void *entryinfo, - const struct xt_target *target, - void *targinfo, - unsigned int hook_mask) -{ - const struct xt_tgchk_param par = { - .targinfo = targinfo, - }; - return MAP66_tg6_check(&par); -} - -#endif - -static struct xt_target MAP66_tg6_reg __read_mostly = { - .name = "MAP66", -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - .target = MAP66_tg6_24, - .checkentry = MAP66_tg6_check_24, -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - .family = AF_INET6, - .target = MAP66_tg6_26, - .checkentry = MAP66_tg6_check_26, - .destroy = NULL, -#else - .family = NFPROTO_IPV6, - .target = MAP66_tg6, - .checkentry = MAP66_tg6_check, -#endif - .targetsize = sizeof(struct ip6t_MAP66_info), - .table = "mangle", - .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_PRE_ROUTING), -#endif - .me = THIS_MODULE, -}; - -static int __init MAP66_tg6_init(void) -{ - return xt_register_target(&MAP66_tg6_reg); -} - -static void __exit MAP66_tg6_exit(void) -{ - xt_unregister_target(&MAP66_tg6_reg); -} - -module_init(MAP66_tg6_init); -module_exit(MAP66_tg6_exit); diff --git a/ip6t_MAP66.h b/ip6t_MAP66.h deleted file mode 100644 index b29592c..0000000 --- a/ip6t_MAP66.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * MAP66: Network Address Translation IPv6-to-IPv6 as - * proposed in the IETF's second NAT66 draft document. - * (c) 2010 sven-ola()gmx.de - */ - -#ifndef _IP6T_MAP66_H -#define _IP6T_MAP66_H - -#define IP6T_MAP66_DST_TO "dst-to" -#define IP6T_MAP66_SRC_TO "src-to" - -#define IP6T_MAP66_OPT_DST_TO 0x01 -#define IP6T_MAP66_OPT_SRC_TO 0x02 -#define IP6T_MAP66_OPT_NOCHECK 0x04 -#define IP6T_MAP66_OPT_CSUM 0x08 - -struct ip6t_MAP66_info { - struct in6_addr pfix_dst_to; /* The prefix to map destination addrs to */ - u_int16_t pfix_dst_len; /* Destination addrs prefix length DIV 16 */ - u_int16_t pfix_dst_csum; /* Pre-calculated csum for destination addrs */ - struct in6_addr pfix_src_to; /* The prefix to map source addrs from */ - u_int16_t pfix_src_len; /* Source addrs prefix length DIV 16 */ - u_int16_t pfix_src_csum; /* Pre-calculated csum for source addrs */ - u_int16_t mapflags; /* Some flags */ -}; - -extern void _init(void); - -#endif /*_IPT_MAP66_H*/ diff --git a/ip6t_NPTV6.h b/ip6t_NPTV6.h new file mode 100644 index 0000000..a1e5e77 --- /dev/null +++ b/ip6t_NPTV6.h @@ -0,0 +1,16 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#ifndef _IP6T_NPTV6_H +#define _IP6T_NPTV6_H + +struct ip6t_nptv6_info { + struct in6_addr nptv6_prefix; /* Adress prefix to map to/from */ + u_int16_t nptv6_prefix_len; /* Address prefix length */ +}; + +#endif /*_IP6T_NPTV6_H*/ diff --git a/ip6t_NPTV6_common.h b/ip6t_NPTV6_common.h new file mode 100644 index 0000000..86b297c --- /dev/null +++ b/ip6t_NPTV6_common.h @@ -0,0 +1,88 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#ifndef _IP6T_NPTV6_COMMON_H +#define _IP6T_NPTV6_COMMON_H + +#include "ip6t_NPTV6.h" +#include <net/ipv6.h> + + +#ifndef pr_devel +# ifdef DEBUG +# define pr_devel(fmt, ...) printk(fmt, ##__VA_ARGS__) +# else +# define pr_devel(fmt, ...) ({ if (0); }) +# endif +#endif + +#ifndef NIP6_FMT +# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +# define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) +#endif + + +/* Ones' complement add */ +static inline u_int16_t add16(u_int16_t a, u_int16_t b) +{ + a += b; + return a + (a < b); +} + +static bool translate_address(struct in6_addr *addr, const struct in6_addr *prefix, u_int16_t plen) { + u_int16_t csum = 0; + int o = plen / 16, b = plen % 16; + int i; + + for (i = 0; i < o; i++) { + csum = add16(csum, addr->s6_addr16[i]); + csum = add16(csum, ~prefix->s6_addr16[i]); + + addr->s6_addr16[i] = prefix->s6_addr16[i]; + } + + if (b != 0) { + u_int16_t bmask = 0xffff << (16-b); + csum = add16(csum, addr->s6_addr16[o] & bmask); + csum = add16(csum, ~(prefix->s6_addr16[o] & bmask)); + + addr->s6_addr16[o] &= bmask; + addr->s6_addr16[o] |= (prefix->s6_addr16[o] & bmask); + } + + /* Fix checksum like specified in RFC 6296 */ + if (plen <= 48) { + i = 3; + } + else { + for (i = (plen+15)/16; i < 7; i++) { + if (addr->s6_addr16[i] != 0xffff) + break; + } + } + + if (addr->s6_addr16[i] == 0xffff) { + return false; + } + + addr->s6_addr16[i] = add16(addr->s6_addr16[i], csum); + if (addr->s6_addr16[i] == 0xffff) { + addr->s6_addr16[i] = 0; + } + + return true; +} + +#endif /*_IP6T_NPTV6_COMMON_H*/ diff --git a/ip6t_SNPTV6.c b/ip6t_SNPTV6.c new file mode 100644 index 0000000..5651382 --- /dev/null +++ b/ip6t_SNPTV6.c @@ -0,0 +1,83 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <net/ipv6.h> + +#include "ip6t_NPTV6_common.h" + +MODULE_AUTHOR("Matthias Schiffer <mschiffer()universe-factory.net>"); +MODULE_DESCRIPTION("Xtables: Source NPTv6 - IPv6-to-IPv6 Network Prefix Translation"); +MODULE_LICENSE("GPL"); + + +static unsigned int snptv6_tg6(struct sk_buff *skb, const struct xt_action_param *par) +{ + struct ipv6hdr* hdr = ipv6_hdr(skb); + const struct ip6t_nptv6_info *info = par->targinfo; + + pr_devel("SNPTV6: enter in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", + NULL != par->in ? par->in->name : "", + NULL != par->out ? par->out->name : "", + NIP6(hdr->saddr), NIP6(hdr->daddr)); + + if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) { + pr_devel("SNPTV6: unwriteable, dropped\n"); + return NF_DROP; + } + hdr = ipv6_hdr(skb); + + if (!translate_address(&hdr->saddr, &info->nptv6_prefix, info->nptv6_prefix_len)) { + pr_devel("SNPTV6: untranslatable address\n"); + return NF_DROP; + } + + pr_devel("SNPTV6: exit in=%s, out=%s, saddr=" NIP6_FMT ", daddr=" NIP6_FMT "\n", + NULL != par->in ? par->in->name : "", + NULL != par->out ? par->out->name : "", + NIP6(hdr->saddr), NIP6(hdr->daddr)); + + return NF_ACCEPT; +} + +static int snptv6_tg6_check(const struct xt_tgchk_param *par) +{ + const struct ip6t_nptv6_info *info = par->targinfo; + + if (info->nptv6_prefix_len > 64) { + printk("SNPTV6: Prefix length longer than 64 given\n"); + return -EINVAL; + } + + return 0; +} + +static struct xt_target snptv6_tg6_reg __read_mostly = { + .name = "SNPTV6", + .family = NFPROTO_IPV6, + .target = snptv6_tg6, + .checkentry = snptv6_tg6_check, + .targetsize = sizeof(struct ip6t_nptv6_info), + .table = "mangle", + .hooks = (1 << NF_INET_POST_ROUTING), + .me = THIS_MODULE, +}; + +static int __init snptv6_tg6_init(void) +{ + return xt_register_target(&snptv6_tg6_reg); +} + +static void __exit snptv6_tg6_exit(void) +{ + xt_unregister_target(&snptv6_tg6_reg); +} + +module_init(snptv6_tg6_init); +module_exit(snptv6_tg6_exit); diff --git a/libip6t_DNPTV6.c b/libip6t_DNPTV6.c new file mode 100644 index 0000000..ad937ae --- /dev/null +++ b/libip6t_DNPTV6.c @@ -0,0 +1,46 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#include "libip6t_NPTV6.h" + + +static void DNPTV6_help(void) +{ + printf( +"DNPTV6 target options\n" +" --to-destination ipv6addr/prefixlength (Prefix to map IPv6 destination address to)\n"); + NPTV6_help_note(); +} + +static void DNPTV6_save(const void *ip, const struct xt_entry_target *target) +{ + const struct ip6t_nptv6_info* info = (struct ip6t_nptv6_info*)target->data; + printf(" --to-destination %s/%d ", xtables_ip6addr_to_numeric(&info->nptv6_prefix), info->nptv6_prefix_len); +} + +static const struct xt_option_entry DNPTV6_opts[] = { + {.name = "to-destination", .id = 0, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, + XTOPT_TABLEEND, +}; + +static struct xtables_target DNPTV6_tg6_reg = { + .name = "DNPTV6", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_nptv6_info)), + .userspacesize = XT_ALIGN(sizeof(struct ip6t_nptv6_info)), + .help = DNPTV6_help, + .x6_parse = NPTV6_parse, + .print = NPTV6_print, + .save = DNPTV6_save, + .x6_options = DNPTV6_opts, +}; + +void _init(void) +{ + xtables_register_target(&DNPTV6_tg6_reg); +} diff --git a/libip6t_MAP66.c b/libip6t_MAP66.c deleted file mode 100644 index 466e5d0..0000000 --- a/libip6t_MAP66.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * MAP66: Network Address Translation IPv6-to-IPv6 as - * proposed in the IETF's second NAT66 draft document. - * (c) 2010 sven-ola()gmx.de - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <arpa/inet.h> - -#define IPTABLES_VERSION_CMP(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -#if IPTABLES_VERSION_CODE < IPTABLES_VERSION_CMP(1,4,0) -# include <ip6tables.h> -# define xt_entry_target ip6t_entry_target -# define void_entry struct ip6t_entry -# define void_ip6 struct ip6t_ip6 -#else -# include <xtables.h> -# define void_entry void -# define void_ip6 void -#endif - -#if IPTABLES_VERSION_CODE < IPTABLES_VERSION_CMP(1,4,1) -# define xtables_target ip6tables_target -# define XTABLES_VERSION IPTABLES_VERSION -# define xtables_register_target register_target6 -#endif - -#if IPTABLES_VERSION_CODE < IPTABLES_VERSION_CMP(1,4,3) -# define xtables_error exit_error -# define xtables_check_inverse check_inverse -# define NFPROTO_IPV6 PF_INET6 -#endif - -#ifndef XT_ALIGN -# define XT_ALIGN IP6T_ALIGN -#endif - -#include "ip6t_MAP66.h" - -/* One's complement add */ -static inline u_int16_t add16( - u_int16_t a, - u_int16_t b) -{ - a += b; - return a + (a < b); -} - -/* Calc one's complement csum */ -static inline u_int16_t csum16(const u_int16_t *buf, int len) -{ - u_int16_t csum = 0; - while(len--) csum = add16(csum, *buf++); - return csum; -} - -static void MAP66_help(void) -{ - printf( -"MAP66 target options\n" -" --" IP6T_MAP66_DST_TO " ipv6addr/prefixlength (Prefix to map IPv6 destination address to)\n" -" --" IP6T_MAP66_SRC_TO " ipv6addr/prefixlength (Prefix to map IPv6 source address to)\n" -" --nocheck (Disables the do-not-map-to-my-addr check)\n" -" --csum (No csum neutral address change, calc csum)\n" -"\n" -"Note: you need two ip6tables rules to map an internal network\n" -"using ULAs to/from external network with official IPv6 address.\n" -"\n" -"Example:\n" -"\n" -"ip6tables -t mangle -I PREROUTING -i eth0 -d 2001:0DB8:0001::/48 -j MAP66 --" IP6T_MAP66_DST_TO " FD01:0203:0405::/48\n" -"ip6tables -t mangle -I POSTROUTING -o eth0 -s FD01:0203:0405::/48 -j MAP66 --" IP6T_MAP66_SRC_TO " 2001:0DB8:0001::/48\n"); -} - -static int MAP66_parse( - int c, - char **argv, - int invert, - unsigned int *flags, - const void_entry *entry, - struct xt_entry_target **target) -{ - int i; - char *p; - struct ip6t_MAP66_info* info = (struct ip6t_MAP66_info*)(*target)->data; - - switch(c) { - case '1': - if (!optarg) { - xtables_error(PARAMETER_PROBLEM, "--" IP6T_MAP66_DST_TO ": You must specify a value"); - } - if (xtables_check_inverse(optarg, &invert, NULL, 0 -#if IPTABLES_VERSION_CODE >= IPTABLES_VERSION_CMP(1,4,6) - ,argv -#endif - )) { - xtables_error(PARAMETER_PROBLEM, "Unexpected `!' after --" IP6T_MAP66_DST_TO); - } - if (0 != (IP6T_MAP66_OPT_DST_TO & *flags)) { - xtables_error(PARAMETER_PROBLEM, "Multiple --" IP6T_MAP66_DST_TO " not supported"); - } - *flags |= IP6T_MAP66_OPT_DST_TO; - info->mapflags |= IP6T_MAP66_OPT_DST_TO; - if (NULL == (p = strchr(optarg, '/'))) { - xtables_error(PARAMETER_PROBLEM, "Missing '/' character in --" IP6T_MAP66_DST_TO ": \"%s\"", optarg); - } - *p = '\0'; - if (1 != inet_pton(AF_INET6, optarg, &info->pfix_dst_to)) { - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 address in --" IP6T_MAP66_DST_TO ": \"%s\"", optarg); - } - i = atoi(p + 1); - if (0 >= i || 128 < i || 0 != i % 16) { - xtables_error(PARAMETER_PROBLEM, "Invalid prefix length in --" IP6T_MAP66_DST_TO ": \"%s\" (use /128, /112, /96 .. /16)", p + 1); - } - info->pfix_dst_len = i / 16; - info->pfix_dst_csum = csum16((const u_int16_t *)&info->pfix_dst_to, info->pfix_dst_len); - return 1; - break; - case '2': - if (!optarg) { - xtables_error(PARAMETER_PROBLEM, "--" IP6T_MAP66_SRC_TO ": You must specify a value"); - } - if (xtables_check_inverse(optarg, &invert, NULL, 0 -#if IPTABLES_VERSION_CODE >= IPTABLES_VERSION_CMP(1,4,6) - ,argv -#endif - )) { - xtables_error(PARAMETER_PROBLEM, "Unexpected `!' after --" IP6T_MAP66_SRC_TO); - } - if (0 != (IP6T_MAP66_OPT_SRC_TO & *flags)) { - xtables_error(PARAMETER_PROBLEM, "Multiple --" IP6T_MAP66_SRC_TO " not supported"); - } - *flags |= IP6T_MAP66_OPT_SRC_TO; - info->mapflags |= IP6T_MAP66_OPT_SRC_TO; - if (NULL == (p = strchr(optarg, '/'))) { - xtables_error(PARAMETER_PROBLEM, "Missing '/' character in --" IP6T_MAP66_SRC_TO ": \"%s\"", optarg); - } - *p = '\0'; - if (1 != inet_pton(AF_INET6, optarg, &info->pfix_src_to)) { - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 address in --" IP6T_MAP66_SRC_TO ": \"%s\"", optarg); - } - i = atoi(p + 1); - if (0 >= i || 128 < i || 0 != i % 16) { - xtables_error(PARAMETER_PROBLEM, "Invalid prefix length in --" IP6T_MAP66_SRC_TO ": \"%s\" (use /128, /112, /96 .. /16)", p + 1); - } - info->pfix_src_len = i / 16; - info->pfix_src_csum = csum16((const u_int16_t *)&info->pfix_src_to, info->pfix_src_len); - return 1; - break; - case '3': - if (0 != (IP6T_MAP66_OPT_NOCHECK & *flags)) { - xtables_error(PARAMETER_PROBLEM, "Multiple --nocheck not supported"); - } - info->mapflags |= IP6T_MAP66_OPT_NOCHECK; - *flags |= IP6T_MAP66_OPT_NOCHECK; - return 1; - break; - case '4': - if (0 != (IP6T_MAP66_OPT_CSUM & *flags)) { - xtables_error(PARAMETER_PROBLEM, "Multiple --csum not supported"); - } - info->mapflags |= IP6T_MAP66_OPT_CSUM; - *flags |= IP6T_MAP66_OPT_CSUM; - return 1; - break; - } - return 0; -} - -static void MAP66_check(unsigned int flags) -{ - if (0 == ((IP6T_MAP66_OPT_DST_TO | IP6T_MAP66_OPT_SRC_TO) & flags)) { - xtables_error(PARAMETER_PROBLEM, "You must specify --" IP6T_MAP66_DST_TO " or --" IP6T_MAP66_SRC_TO); - } -} - -static void MAP66_save( - const void_ip6 *ip, - const struct xt_entry_target *target) -{ - char s[50+1]; - const struct ip6t_MAP66_info* info = (struct ip6t_MAP66_info*)target->data; - if (0 != (IP6T_MAP66_OPT_DST_TO & info->mapflags)) { - printf("--" IP6T_MAP66_DST_TO " %s/%d ", inet_ntop(AF_INET6, &info->pfix_dst_to, s, sizeof(s)), 16 * info->pfix_dst_len); - } - if (0 != (IP6T_MAP66_OPT_SRC_TO & info->mapflags)) { - printf("--" IP6T_MAP66_SRC_TO " %s/%d ", inet_ntop(AF_INET6, &info->pfix_src_to, s, sizeof(s)), 16 * info->pfix_src_len); - } - if (0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags)) { - printf("--nocheck "); - } - if (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags)) { - printf("--csum "); - } -} - -static struct option MAP66_opts[] = { - { .name = IP6T_MAP66_DST_TO, .has_arg = 1, .flag = NULL, .val = '1' }, - { .name = IP6T_MAP66_SRC_TO, .has_arg = 1, .flag = NULL, .val = '2' }, - { .name = "nocheck", .has_arg = 0, .flag = NULL, .val = '3' }, - { .name = "csum", .has_arg = 0, .flag = NULL, .val = '4' }, - { .name = NULL } -}; - -static struct xtables_target MAP66_tg6_reg = { - .name = "MAP66", - .version = XTABLES_VERSION, -#if IPTABLES_VERSION_CODE >= IPTABLES_VERSION_CMP(1,4,1) - .family = NFPROTO_IPV6, -#endif - .size = XT_ALIGN(sizeof(struct ip6t_MAP66_info)), - .userspacesize = XT_ALIGN(sizeof(struct ip6t_MAP66_info)), - .help = MAP66_help, - .parse = MAP66_parse, - .final_check = MAP66_check, - .save = MAP66_save, - .extra_opts = MAP66_opts, -}; - -void _init(void) -{ - xtables_register_target(&MAP66_tg6_reg); -} diff --git a/libip6t_NPTV6.c b/libip6t_NPTV6.c new file mode 100644 index 0000000..4c7aae7 --- /dev/null +++ b/libip6t_NPTV6.c @@ -0,0 +1,62 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#include "libip6t_NPTV6.h" + + +void NPTV6_help_note(void) +{ + printf( +"\n" +"Note: you need two ip6tables rules to map an internal network\n" +"using ULAs to/from external network with official IPv6 address.\n" +"\n" +"Example:\n" +"\n" +"ip6tables -t mangle -I PREROUTING -i eth0 -d 2001:0DB8:0001::/48 -j DNPTV6 --to-destination FD01:0203:0405::/48\n" +"ip6tables -t mangle -I POSTROUTING -o eth0 -s FD01:0203:0405::/48 -j SNPTV6 --to-source 2001:0DB8:0001::/48\n"); +} + +static void parse_to(const char *orig_arg, struct ip6t_nptv6_info *info) +{ + char *arg, *slash; + + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); + + slash = strchr(arg, '/'); + if (!slash) + xtables_error(PARAMETER_PROBLEM, "No prefix length given\n"); + + info->nptv6_prefix_len = atoi(slash+1); + if (info->nptv6_prefix_len <= 0 || info->nptv6_prefix_len > 64) + xtables_error(PARAMETER_PROBLEM, "Prefix length `%s' not valid\n", slash+1); + + *slash = 0; + info->nptv6_prefix = *xtables_numeric_to_ip6addr(arg); + + free(arg); +} + +void NPTV6_parse(struct xt_option_call *cb) +{ + struct ip6t_nptv6_info* info = (struct ip6t_nptv6_info*)cb->data; + + xtables_option_parse(cb); + switch(cb->entry->id) { + case 0: + parse_to(cb->arg, info); + break; + } +} + +void NPTV6_print(const void *ip, const struct xt_entry_target *target, int numeric) +{ + const struct ip6t_nptv6_info* info = (struct ip6t_nptv6_info*)target->data; + printf(" to: %s/%d", xtables_ip6addr_to_numeric(&info->nptv6_prefix), info->nptv6_prefix_len); +} diff --git a/libip6t_NPTV6.h b/libip6t_NPTV6.h new file mode 100644 index 0000000..d091de6 --- /dev/null +++ b/libip6t_NPTV6.h @@ -0,0 +1,29 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#ifndef _LIBIP6T_NPTV6_H +#define _LIBIP6T_NPTV6_H + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <limits.h> +#include <arpa/inet.h> +#include <xtables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> + +#include "ip6t_NPTV6.h" + + +void NPTV6_help_note(void); +void NPTV6_parse(struct xt_option_call *cb); +void NPTV6_print(const void *ip, const struct xt_entry_target *target, int numeric); + +void _init(void); + +#endif /*_LIBIP6T_NPTV6_H*/ diff --git a/libip6t_SNPTV6.c b/libip6t_SNPTV6.c new file mode 100644 index 0000000..3bcc66e --- /dev/null +++ b/libip6t_SNPTV6.c @@ -0,0 +1,46 @@ +/* + * NATv6: IPv6-to-IPv6 Network Prefix Translation as + * proposed in RFC 6296. + * Based on MAP66 (c) 2010 sven-ola()gmx.de + * (c) 2011 mschiffer()universe-factory.net "I'm the one to blame for any problems with this version ;P" + */ + +#include "libip6t_NPTV6.h" + + +static void SNPTV6_help(void) +{ + printf( +"SNPTV6 target options\n" +" --to-source ipv6addr/prefixlength (Prefix to map IPv6 source address to)\n"); + NPTV6_help_note(); +} + +static void SNPTV6_save(const void *ip, const struct xt_entry_target *target) +{ + const struct ip6t_nptv6_info* info = (struct ip6t_nptv6_info*)target->data; + printf(" --to-source %s/%d ", xtables_ip6addr_to_numeric(&info->nptv6_prefix), info->nptv6_prefix_len); +} + +static const struct xt_option_entry SNPTV6_opts[] = { + {.name = "to-source", .id = 0, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, + XTOPT_TABLEEND, +}; + +static struct xtables_target SNPTV6_tg6_reg = { + .name = "SNPTV6", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_nptv6_info)), + .userspacesize = XT_ALIGN(sizeof(struct ip6t_nptv6_info)), + .help = SNPTV6_help, + .x6_parse = NPTV6_parse, + .print = NPTV6_print, + .save = SNPTV6_save, + .x6_options = SNPTV6_opts, +}; + +void _init(void) +{ + xtables_register_target(&SNPTV6_tg6_reg); +} |