/* * MAP66: Network Address Translation IPv6-to-IPv6 as * proposed in the IETF's second NAT66 draft document. * (c) 2010 sven-ola()gmx.de */ #include #include #include #include #include #define IPTABLES_VERSION_CMP(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #if IPTABLES_VERSION_CODE < IPTABLES_VERSION_CMP(1,4,0) # include # define xt_entry_target ip6t_entry_target # define void_entry struct ip6t_entry # define void_ip6 struct ip6t_ip6 # define XT_ALIGN IP6T_ALIGN #else # include # 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 #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" " --to ipv6addr/prefixlength (External IPv6 address)\n" " --nospoof (Disables spoof check)\n" "\n" "Note: you need two ip6tables rules to map an internal network\n" "using ULAs to an 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 --to FD01:0203:0405::/48\n" "ip6tables -t mangle -I POSTROUTING -o eth0 -s FD01:0203:0405::/48 -j MAP66 --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, "--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 --to"); } if (0 != (IP6T_MAP66_OPT_TO & *flags)) { xtables_error(PARAMETER_PROBLEM, "Multiple --to not supported"); } *flags |= IP6T_MAP66_OPT_TO; if (NULL == (p = strchr(optarg, '/'))) { xtables_error(PARAMETER_PROBLEM, "Missing '/' character in --to: \"%s\"", optarg); } *p = '\0'; if (1 != inet_pton(AF_INET6, optarg, &info->prefix)) { xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 address in --to: \"%s\"", optarg); } i = atoi(p + 1); if (0 >= i || 128 <= i || 0 != i % 16) { xtables_error(PARAMETER_PROBLEM, "Invalid prefix length in --to: \"%s\" (use /112, /96 .. /16)", p + 1); } info->prefixlength = i / 16; info->prefixcsum = ~csum16((const u_int16_t *)&info->prefix, info->prefixlength); return 1; break; case '2': if (0 != (IP6T_MAP66_OPT_NOSPOOF & *flags)) { xtables_error(PARAMETER_PROBLEM, "Multiple --nospoof not supported"); } info->mapflags |= IP6T_MAP66_OPT_NOSPOOF; *flags |= IP6T_MAP66_OPT_NOSPOOF; return 1; break; } return 0; } static void MAP66_check(unsigned int flags) { if (!(flags & IP6T_MAP66_OPT_TO)) { xtables_error(PARAMETER_PROBLEM, "You must specify --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; printf("--to %s/%d ", inet_ntop(AF_INET6, &info->prefix, s, sizeof(s)), 16 * info->prefixlength); if (0 != (IP6T_MAP66_OPT_NOSPOOF & info->mapflags)) printf("--nospoof "); } static struct option MAP66_opts[] = { { .name = "to", .has_arg = 1, .flag = NULL, .val = '1' }, { .name = "nospoof", .has_arg = 0, .flag = NULL, .val = '2' }, { .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); }