summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--ip6t_MAP66.c67
-rw-r--r--ip6t_MAP66.h19
-rw-r--r--libip6t_MAP66.c83
4 files changed, 114 insertions, 57 deletions
diff --git a/Makefile b/Makefile
index f54abf3..b7710df 100644
--- a/Makefile
+++ b/Makefile
@@ -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 }
};