summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2011-11-10 23:03:45 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2011-11-10 23:03:45 +0100
commit0d03a6f3467d93f1ae7b04e3fed6fc11a1a9f9e4 (patch)
tree1f9150119579ec4f981beaf7446fe29c9e539e5b
parent8790aa53a3d0959ba318fea1ecb9de5a4de4cac5 (diff)
downloadNPTv6-0d03a6f3467d93f1ae7b04e3fed6fc11a1a9f9e4.tar
NPTv6-0d03a6f3467d93f1ae7b04e3fed6fc11a1a9f9e4.zip
Add ICMP errors for untranslatable addresses
-rw-r--r--ip6t_DNPTV6.c2
-rw-r--r--ip6t_NPTV6_common.h38
-rw-r--r--ip6t_SNPTV6.c2
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;
}