[NETFILTER6]: Add new ip6tables HOPLIMIT target
Harald Welte [Sun, 28 Aug 2005 05:37:30 +0000 (22:37 -0700)]
This target allows users to modify the hoplimit header field of the
IPv6 header.

Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/linux/netfilter_ipv6/ip6t_HL.h [new file with mode: 0644]
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6t_HL.c [new file with mode: 0644]

diff --git a/include/linux/netfilter_ipv6/ip6t_HL.h b/include/linux/netfilter_ipv6/ip6t_HL.h
new file mode 100644 (file)
index 0000000..afb7813
--- /dev/null
@@ -0,0 +1,22 @@
+/* Hop Limit modification module for ip6tables
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's TTL module */
+
+#ifndef _IP6T_HL_H
+#define _IP6T_HL_H
+
+enum {
+       IP6T_HL_SET = 0,
+       IP6T_HL_INC,
+       IP6T_HL_DEC
+};
+
+#define IP6T_HL_MAXMODE        IP6T_HL_DEC
+
+struct ip6t_HL_info {
+       u_int8_t        mode;
+       u_int8_t        hop_limit;
+};
+
+
+#endif
index 8a10c2d..216fbe1 100644 (file)
@@ -239,6 +239,22 @@ config IP6_NF_TARGET_MARK
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_HL
+       tristate  'HL (hoplimit) target support'
+       depends on IP6_NF_MANGLE
+       help
+         This option adds a `HL' target, which enables the user to decrement
+         the hoplimit value of the IPv6 header or set it to a given (lower)
+         value.
+       
+         While it is safe to decrement the hoplimit value, this option also
+         enables functionality to increment and set the hoplimit value of the
+         IPv6 header to arbitrary values.  This is EXTREMELY DANGEROUS since
+         you can easily create immortal packets that loop forever on the
+         network.  
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 #dep_tristate '  LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
 config IP6_NF_RAW
        tristate  'raw table support (required for TRACE)'
index 70f6ba6..bd9a16a 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_IP6_NF_MATCH_PHYSDEV) += ip6t_physdev.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
new file mode 100644 (file)
index 0000000..8f5549b
--- /dev/null
@@ -0,0 +1,118 @@
+/* 
+ * Hop Limit modification target for ip6tables
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's TTL module
+ *
+ * This software is distributed under the terms of GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_HL.h>
+
+MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
+MODULE_DESCRIPTION("IP tables Hop Limit modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int ip6t_hl_target(struct sk_buff **pskb, 
+                                  const struct net_device *in,
+                                  const struct net_device *out,
+                                  unsigned int hooknum,
+                                  const void *targinfo, void *userinfo)
+{
+       struct ipv6hdr *ip6h;
+       const struct ip6t_HL_info *info = targinfo;
+       u_int16_t diffs[2];
+       int new_hl;
+
+       if (!skb_make_writable(pskb, (*pskb)->len))
+               return NF_DROP;
+
+       ip6h = (*pskb)->nh.ipv6h;
+
+       switch (info->mode) {
+               case IP6T_HL_SET:
+                       new_hl = info->hop_limit;
+                       break;
+               case IP6T_HL_INC:
+                       new_hl = ip6h->hop_limit + info->hop_limit;
+                       if (new_hl > 255)
+                               new_hl = 255;
+                       break;
+               case IP6T_HL_DEC:
+                       new_hl = ip6h->hop_limit - info->hop_limit;
+                       if (new_hl < 0)
+                               new_hl = 0;
+                       break;
+               default:
+                       new_hl = ip6h->hop_limit;
+                       break;
+       }
+
+       if (new_hl != ip6h->hop_limit) {
+               diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
+               ip6h->hop_limit = new_hl;
+               diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
+       }
+
+       return IP6T_CONTINUE;
+}
+
+static int ip6t_hl_checkentry(const char *tablename,
+               const struct ip6t_entry *e,
+               void *targinfo,
+               unsigned int targinfosize,
+               unsigned int hook_mask)
+{
+       struct ip6t_HL_info *info = targinfo;
+
+       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
+               printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n",
+                               targinfosize,
+                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
+               return 0;       
+       }       
+
+       if (strcmp(tablename, "mangle")) {
+               printk(KERN_WARNING "ip6t_HL: can only be called from "
+                       "\"mangle\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       if (info->mode > IP6T_HL_MAXMODE) {
+               printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", 
+                       info->mode);
+               return 0;
+       }
+
+       if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
+               printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
+                       "make sense with value 0\n");
+               return 0;
+       }
+       
+       return 1;
+}
+
+static struct ip6t_target ip6t_HL = { 
+       .name           = "HL", 
+       .target         = ip6t_hl_target, 
+       .checkentry     = ip6t_hl_checkentry, 
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ip6t_register_target(&ip6t_HL);
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_target(&ip6t_HL);
+}
+
+module_init(init);
+module_exit(fini);