diff options
-rw-r--r-- | ip6t_DNPTV6.c | 2 | ||||
-rw-r--r-- | ip6t_NPTV6_common.h | 38 | ||||
-rw-r--r-- | ip6t_SNPTV6.c | 2 |
3 files changed, 25 insertions, 17 deletions
diff --git a/ip6t_DNPTV6.c b/ip6t_DNPTV6.c index 96d16e8..506d0a5 100644 --- a/ip6t_DNPTV6.c +++ b/ip6t_DNPTV6.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/version.h> +#include <linux/icmpv6.h> #include <linux/netfilter_ipv6/ip6_tables.h> #include <net/ipv6.h> @@ -35,6 +36,7 @@ static unsigned int dnptv6_tg6(struct sk_buff *skb, const struct xt_action_param if (!translate_address(&hdr->daddr, &info->nptv6_prefix, info->nptv6_prefix_len)) { pr_devel("DNPTV6: untranslatable address\n"); + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0); return NF_DROP; } diff --git a/ip6t_NPTV6_common.h b/ip6t_NPTV6_common.h index 86b297c..9b3aa6f 100644 --- a/ip6t_NPTV6_common.h +++ b/ip6t_NPTV6_common.h @@ -44,8 +44,26 @@ static inline u_int16_t add16(u_int16_t a, u_int16_t 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 fix_word; int i; + /* Fix checksum like specified in RFC 6296 */ + if (plen <= 48) { + fix_word = 3; + } + else { + for (fix_word = (plen+15)/16; fix_word < 7; fix_word++) { + if (addr->s6_addr16[fix_word] != 0xffff) + break; + } + } + + if (addr->s6_addr16[fix_word] == 0xffff) { + /* Fail before the address is translated so the ICMP error can be sent */ + return false; + } + + for (i = 0; i < o; i++) { csum = add16(csum, addr->s6_addr16[i]); csum = add16(csum, ~prefix->s6_addr16[i]); @@ -62,24 +80,10 @@ static bool translate_address(struct in6_addr *addr, const struct in6_addr *pref 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; + addr->s6_addr16[fix_word] = add16(addr->s6_addr16[fix_word], csum); + if (addr->s6_addr16[fix_word] == 0xffff) { + addr->s6_addr16[fix_word] = 0; } return true; diff --git a/ip6t_SNPTV6.c b/ip6t_SNPTV6.c index 5651382..79747ae 100644 --- a/ip6t_SNPTV6.c +++ b/ip6t_SNPTV6.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/version.h> +#include <linux/icmpv6.h> #include <linux/netfilter_ipv6/ip6_tables.h> #include <net/ipv6.h> @@ -35,6 +36,7 @@ static unsigned int snptv6_tg6(struct sk_buff *skb, const struct xt_action_param if (!translate_address(&hdr->saddr, &info->nptv6_prefix, info->nptv6_prefix_len)) { pr_devel("SNPTV6: untranslatable address\n"); + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0); return NF_DROP; } |