diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | ip6t_MAP66.c | 67 | ||||
-rw-r--r-- | ip6t_MAP66.h | 19 | ||||
-rw-r--r-- | libip6t_MAP66.c | 83 |
4 files changed, 114 insertions, 57 deletions
@@ -8,7 +8,7 @@ EXTRA_CFLAGS := -DDEBUG endif all: libip6t_MAP66.so - $(MAKE) -C $(KPATH) V=1 M=$(PWD) modules + $(MAKE) -C $(KPATH) M=$(PWD) modules libip6t_MAP66.so: libip6t_MAP66.o gcc -shared -o $@ $< diff --git a/ip6t_MAP66.c b/ip6t_MAP66.c index 239378e..ffe4afa 100644 --- a/ip6t_MAP66.c +++ b/ip6t_MAP66.c @@ -35,17 +35,17 @@ static inline u_int16_t csum16(const u_int16_t *buf, int len) /* Perform checksum neutral mapping */ static void map16( struct in6_addr* addr, - unsigned char mask, const struct in6_addr* to, + int len, u_int16_t csum) { csum = add16( - *((u_int16_t*)addr + mask), - add16(csum16((const u_int16_t *)addr, mask), csum) + *((u_int16_t*)addr + len), + add16(csum16((const u_int16_t *)addr, len), csum) ); if (csum == 0xffff) csum = 0x0000; - *((u_int16_t *)addr + mask) = csum; - memcpy(addr, to, sizeof(u_int16_t) * mask); + *((u_int16_t *)addr + len) = csum; + memcpy(addr, to, sizeof(u_int16_t) * len); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -126,27 +126,23 @@ static unsigned int MAP66_tg6( &hdr->saddr, &hdr->daddr); #endif - switch(par->hooknum) { - case NF_INET_PRE_ROUTING: - pr_devel("MAP66 PRE, check=%d\n", 0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags)); - if (0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags) || - !is_my_ipv6_addr(par->in, &hdr->daddr)) - { - map16(&hdr->daddr, info->prefixlength, &info->prefix, info->prefixcsum); - } - break; - case NF_INET_POST_ROUTING: - pr_devel("MAP66 POST, check=%d\n", 0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags)); - map16(&hdr->saddr, info->prefixlength, &info->prefix, info->prefixcsum); - if (0 == (IP6T_MAP66_OPT_NOCHECK & info->mapflags) && - is_my_ipv6_addr(par->out, &hdr->saddr)) - { - return NF_DROP; - } - break; - default: - pr_devel("MAP66: unsupported hook: %d\n", par->hooknum); - break; + if (0 != (IP6T_MAP66_OPT_DST_TO & info->mapflags)) { + pr_devel("MAP66 DST, check=%d\n", 0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags)); + if (0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags) || + !is_my_ipv6_addr(par->in, &hdr->daddr)) + { + map16(&hdr->daddr, &info->pfix_dst_to, info->pfix_dst_len, info->pfix_dst_csum); + } + } + + if (0 != (IP6T_MAP66_OPT_SRC_TO & info->mapflags)) { + pr_devel("MAP66 SRC, check=%d\n", 0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags)); + map16(&hdr->saddr, &info->pfix_src_to, info->pfix_src_len, info->pfix_src_csum); + if (0 == (IP6T_MAP66_OPT_NOCHECK & info->mapflags) && + is_my_ipv6_addr(par->out, &hdr->saddr)) + { + return NF_DROP; + } } #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) @@ -169,8 +165,23 @@ static bool MAP66_tg6_check( { const struct ip6t_MAP66_info *info = par->targinfo; - if (0 >= info->prefixlength || 8 <= info->prefixlength) { - printk("MAP66: Unsupported prefix length /%d\n", 16 * info->prefixlength); + + 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 || 8 <= info->pfix_dst_len)) + { + printk("MAP66: Unsupported 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 || 8 <= info->pfix_src_len)) + { + printk("MAP66: Unsupported src-to prefix length /%d\n", 16 * info->pfix_src_len); return false; } return true; diff --git a/ip6t_MAP66.h b/ip6t_MAP66.h index 21cb833..70fd5fc 100644 --- a/ip6t_MAP66.h +++ b/ip6t_MAP66.h @@ -7,14 +7,21 @@ #ifndef _IP6T_MAP66_H #define _IP6T_MAP66_H -#define IP6T_MAP66_OPT_TO 0x01 -#define IP6T_MAP66_OPT_NOCHECK 0x02 +#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 struct ip6t_MAP66_info { - struct in6_addr prefix; /* The prefix to map to */ - u_int16_t prefixcsum; /* Pre-calculated csum */ - u_int8_t prefixlength; /* Prefix length DIV sizeof(u_int16_t) */ - u_int8_t mapflags; /* Some flags */ + 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); diff --git a/libip6t_MAP66.c b/libip6t_MAP66.c index 1d56d7f..a3705b6 100644 --- a/libip6t_MAP66.c +++ b/libip6t_MAP66.c @@ -59,16 +59,17 @@ static void MAP66_help(void) { printf( "MAP66 target options\n" -" --to ipv6addr/prefixlength (External IPv6 address)\n" -" --nocheck (Disables check check)\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" "\n" "Note: you need two ip6tables rules to map an internal network\n" -"using ULAs to an external network with official IPv6 address.\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 --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"); +"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( @@ -86,35 +87,65 @@ static int MAP66_parse( switch(c) { case '1': if (!optarg) { - xtables_error(PARAMETER_PROBLEM, "--to: You must specify a value"); + 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 --to"); + xtables_error(PARAMETER_PROBLEM, "Unexpected `!' after " IP6T_MAP66_DST_TO); } - if (0 != (IP6T_MAP66_OPT_TO & *flags)) { - xtables_error(PARAMETER_PROBLEM, "Multiple --to not supported"); + if (0 != (IP6T_MAP66_OPT_DST_TO & *flags)) { + xtables_error(PARAMETER_PROBLEM, "Multiple " IP6T_MAP66_DST_TO " not supported"); } - *flags |= IP6T_MAP66_OPT_TO; + *flags |= IP6T_MAP66_OPT_DST_TO; if (NULL == (p = strchr(optarg, '/'))) { - xtables_error(PARAMETER_PROBLEM, "Missing '/' character in --to: \"%s\"", optarg); + xtables_error(PARAMETER_PROBLEM, "Missing '/' character in " IP6T_MAP66_DST_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); + 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 --to: \"%s\" (use /112, /96 .. /16)", p + 1); + xtables_error(PARAMETER_PROBLEM, "Invalid prefix length in " IP6T_MAP66_DST_TO ": \"%s\" (use /112, /96 .. /16)", p + 1); } - info->prefixlength = i / 16; - info->prefixcsum = ~csum16((const u_int16_t *)&info->prefix, info->prefixlength); + 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; + 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 /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"); } @@ -128,8 +159,8 @@ static int MAP66_parse( static void MAP66_check(unsigned int flags) { - if (!(flags & IP6T_MAP66_OPT_TO)) { - xtables_error(PARAMETER_PROBLEM, "You must specify --to"); + 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); } } @@ -139,13 +170,21 @@ static void MAP66_save( { 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_NOCHECK & info->mapflags)) printf("--nocheck "); + 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 "); + } } static struct option MAP66_opts[] = { - { .name = "to", .has_arg = 1, .flag = NULL, .val = '1' }, - { .name = "nocheck", .has_arg = 0, .flag = NULL, .val = '2' }, + { .name = "dst-to", .has_arg = 1, .flag = NULL, .val = '1' }, + { .name = "src-to", .has_arg = 1, .flag = NULL, .val = '2' }, + { .name = "nocheck", .has_arg = 0, .flag = NULL, .val = '3' }, { .name = NULL } }; |