diff options
Diffstat (limited to 'net/ipv6/netfilter')
31 files changed, 993 insertions, 2015 deletions
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 04912f9b35c3..2d6f8ecbc27b 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -41,6 +41,7 @@ config IP6_NF_QUEUE config IP6_NF_IPTABLES tristate "IP6 tables support (required for filtering/masq/NAT)" + depends on NETFILTER_XTABLES help ip6tables is a general, extensible packet identification framework. Currently only the packet filtering and packet mangling subsystem @@ -50,25 +51,6 @@ config IP6_NF_IPTABLES To compile it as a module, choose M here. If unsure, say N. # The simple matches. -config IP6_NF_MATCH_LIMIT - tristate "limit match support" - depends on IP6_NF_IPTABLES - help - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_MAC - tristate "MAC address match support" - depends on IP6_NF_IPTABLES - help - mac matching allows you to match packets based on the source - Ethernet address of the packet. - - To compile it as a module, choose M here. If unsure, say N. - config IP6_NF_MATCH_RT tristate "Routing header match support" depends on IP6_NF_IPTABLES @@ -124,16 +106,6 @@ config IP6_NF_MATCH_OWNER To compile it as a module, choose M here. If unsure, say N. -config IP6_NF_MATCH_MARK - tristate "netfilter MARK match support" - depends on IP6_NF_IPTABLES - help - Netfilter mark matching allows you to match packets based on the - `nfmark' value in the packet. This can be set by the MARK target - (see below). - - To compile it as a module, choose M here. If unsure, say N. - config IP6_NF_MATCH_IPV6HEADER tristate "IPv6 Extension Headers Match" depends on IP6_NF_IPTABLES @@ -151,15 +123,6 @@ config IP6_NF_MATCH_AHESP To compile it as a module, choose M here. If unsure, say N. -config IP6_NF_MATCH_LENGTH - tristate "Packet Length match support" - depends on IP6_NF_IPTABLES - help - This option allows you to match the length of a packet against a - specific value or range of values. - - To compile it as a module, choose M here. If unsure, say N. - config IP6_NF_MATCH_EUI64 tristate "EUI64 address check" depends on IP6_NF_IPTABLES @@ -170,12 +133,13 @@ config IP6_NF_MATCH_EUI64 To compile it as a module, choose M here. If unsure, say N. -config IP6_NF_MATCH_PHYSDEV - tristate "Physdev match support" - depends on IP6_NF_IPTABLES && BRIDGE_NETFILTER +config IP6_NF_MATCH_POLICY + tristate "IPsec policy match support" + depends on IP6_NF_IPTABLES && XFRM help - Physdev packet matching matches against the physical bridge ports - the IP packet arrived on or will leave by. + Policy matching allows you to match packets based on the + IPsec policy that was used during decapsulation/will + be used during encapsulation. To compile it as a module, choose M here. If unsure, say N. @@ -209,17 +173,6 @@ config IP6_NF_TARGET_REJECT To compile it as a module, choose M here. If unsure, say N. -config IP6_NF_TARGET_NFQUEUE - tristate "NFQUEUE Target Support" - depends on IP6_NF_IPTABLES - help - This Target replaced the old obsolete QUEUE target. - - As opposed to QUEUE, it supports 65535 different queues, - not just one. - - To compile it as a module, choose M here. If unsure, say N. - config IP6_NF_MANGLE tristate "Packet mangling" depends on IP6_NF_IPTABLES @@ -230,19 +183,6 @@ config IP6_NF_MANGLE To compile it as a module, choose M here. If unsure, say N. -config IP6_NF_TARGET_MARK - tristate "MARK target support" - depends on IP6_NF_MANGLE - help - This option adds a `MARK' target, which allows you to create rules - in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change - the routing method (see `Use netfilter MARK value as routing - key') and can also be used by other subsystems to change their - behavior. - - 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 diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 9ab5b2ca1f59..db6073c94163 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -4,24 +4,18 @@ # Link order matters here. obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o -obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o -obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o -obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o -obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o +obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o -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_TARGET_NFQUEUE) += ip6t_NFQUEUE.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/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 95d469271c4d..847068fd3367 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -13,15 +13,19 @@ * a table * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu> * - new extension header parser code + * 15 Oct 2005 Harald Welte <laforge@netfilter.org> + * - Unification of {ip,ip6}_tables into x_tables + * - Removed tcp and udp code, since it's not ipv6 specific */ + +#include <linux/capability.h> #include <linux/config.h> +#include <linux/in.h> #include <linux/skbuff.h> #include <linux/kmod.h> #include <linux/vmalloc.h> #include <linux/netdevice.h> #include <linux/module.h> -#include <linux/tcp.h> -#include <linux/udp.h> #include <linux/icmpv6.h> #include <net/ipv6.h> #include <asm/uaccess.h> @@ -30,6 +34,7 @@ #include <linux/cpumask.h> #include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/x_tables.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); @@ -64,13 +69,8 @@ do { \ #else #define IP_NF_ASSERT(x) #endif -#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) -static DECLARE_MUTEX(ip6t_mutex); -/* Must have mutex */ -#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) -#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0) #include <linux/netfilter_ipv4/listhelp.h> #if 0 @@ -86,55 +86,22 @@ static DECLARE_MUTEX(ip6t_mutex); context stops packets coming through and allows user context to read the counters or update the rules. - To be cache friendly on SMP, we arrange them like so: - [ n-entries ] - ... cache-align padding ... - [ n-entries ] - Hence the start of any table is given by get_table() below. */ -/* The table itself */ -struct ip6t_table_info -{ - /* Size per table */ - unsigned int size; - /* Number of entries: FIXME. --RR */ - unsigned int number; - /* Initial number of entries. Needed for module usage count */ - unsigned int initial_entries; - - /* Entry points and underflows */ - unsigned int hook_entry[NF_IP6_NUMHOOKS]; - unsigned int underflow[NF_IP6_NUMHOOKS]; - - /* ip6t_entry tables: one per CPU */ - char entries[0] ____cacheline_aligned; -}; - -static LIST_HEAD(ip6t_target); -static LIST_HEAD(ip6t_match); -static LIST_HEAD(ip6t_tables); -#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0) - -#ifdef CONFIG_SMP -#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p)) -#else -#define TABLE_OFFSET(t,p) 0 -#endif - #if 0 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0) #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; }) #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) #endif -static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask, - struct in6_addr addr2) +int +ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask, + const struct in6_addr *addr2) { int i; for( i = 0; i < 16; i++){ - if((addr1.s6_addr[i] & mask.s6_addr[i]) != - (addr2.s6_addr[i] & mask.s6_addr[i])) + if((addr1->s6_addr[i] & mask->s6_addr[i]) != + (addr2->s6_addr[i] & mask->s6_addr[i])) return 1; } return 0; @@ -168,10 +135,10 @@ ip6_packet_match(const struct sk_buff *skb, #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) - if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src), - IP6T_INV_SRCIP) - || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst), - IP6T_INV_DSTIP)) { + if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, + &ip6info->src), IP6T_INV_SRCIP) + || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, + &ip6info->dst), IP6T_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); /* dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, @@ -214,69 +181,21 @@ ip6_packet_match(const struct sk_buff *skb, /* look for the desired protocol header */ if((ip6info->flags & IP6T_F_PROTO)) { - u_int8_t currenthdr = ipv6->nexthdr; - struct ipv6_opt_hdr _hdr, *hp; - u_int16_t ptr; /* Header offset in skb */ - u_int16_t hdrlen; /* Header */ - u_int16_t _fragoff = 0, *fp = NULL; - - ptr = IPV6_HDR_LEN; - - while (ip6t_ext_hdr(currenthdr)) { - /* Is there enough space for the next ext header? */ - if (skb->len - ptr < IPV6_OPTHDR_LEN) - return 0; - - /* NONE or ESP: there isn't protocol part */ - /* If we want to count these packets in '-p all', - * we will change the return 0 to 1*/ - if ((currenthdr == IPPROTO_NONE) || - (currenthdr == IPPROTO_ESP)) - break; - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Size calculation */ - if (currenthdr == IPPROTO_FRAGMENT) { - fp = skb_header_pointer(skb, - ptr+offsetof(struct frag_hdr, - frag_off), - sizeof(_fragoff), - &_fragoff); - if (fp == NULL) - return 0; - - _fragoff = ntohs(*fp) & ~0x7; - hdrlen = 8; - } else if (currenthdr == IPPROTO_AH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - currenthdr = hp->nexthdr; - ptr += hdrlen; - /* ptr is too large */ - if ( ptr > skb->len ) - return 0; - if (_fragoff) { - if (ip6t_ext_hdr(currenthdr)) - return 0; - break; - } - } + int protohdr; + unsigned short _frag_off; - *protoff = ptr; - *fragoff = _fragoff; + protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); + if (protohdr < 0) + return 0; - /* currenthdr contains the protocol header */ + *fragoff = _frag_off; dprintf("Packet protocol %hi ?= %s%hi.\n", - currenthdr, + protohdr, ip6info->invflags & IP6T_INV_PROTO ? "!":"", ip6info->proto); - if (ip6info->proto == currenthdr) { + if (ip6info->proto == protohdr) { if(ip6info->invflags & IP6T_INV_PROTO) { return 0; } @@ -351,7 +270,7 @@ ip6t_do_table(struct sk_buff **pskb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct ip6t_table *table, + struct xt_table *table, void *userdata) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); @@ -363,6 +282,7 @@ ip6t_do_table(struct sk_buff **pskb, const char *indev, *outdev; void *table_base; struct ip6t_entry *e, *back; + struct xt_table_info *private; /* Initialization */ indev = in ? in->name : nulldevname; @@ -375,10 +295,10 @@ ip6t_do_table(struct sk_buff **pskb, * match it. */ read_lock_bh(&table->lock); + private = table->private; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); - table_base = (void *)table->private->entries - + TABLE_OFFSET(table->private, smp_processor_id()); - e = get_entry(table_base, table->private->hook_entry[hook]); + table_base = (void *)private->entries[smp_processor_id()]; + e = get_entry(table_base, private->hook_entry[hook]); #ifdef CONFIG_NETFILTER_DEBUG /* Check noone else using our table */ @@ -394,7 +314,7 @@ ip6t_do_table(struct sk_buff **pskb, #endif /* For return from builtin chain */ - back = get_entry(table_base, table->private->underflow[hook]); + back = get_entry(table_base, private->underflow[hook]); do { IP_NF_ASSERT(e); @@ -494,145 +414,6 @@ ip6t_do_table(struct sk_buff **pskb, #endif } -/* - * These are weird, but module loading must not be done with mutex - * held (since they will register), and we have to have a single - * function to use try_then_request_module(). - */ - -/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ -static inline struct ip6t_table *find_table_lock(const char *name) -{ - struct ip6t_table *t; - - if (down_interruptible(&ip6t_mutex) != 0) - return ERR_PTR(-EINTR); - - list_for_each_entry(t, &ip6t_tables, list) - if (strcmp(t->name, name) == 0 && try_module_get(t->me)) - return t; - up(&ip6t_mutex); - return NULL; -} - -/* Find match, grabs ref. Returns ERR_PTR() on error. */ -static inline struct ip6t_match *find_match(const char *name, u8 revision) -{ - struct ip6t_match *m; - int err = 0; - - if (down_interruptible(&ip6t_mutex) != 0) - return ERR_PTR(-EINTR); - - list_for_each_entry(m, &ip6t_match, list) { - if (strcmp(m->name, name) == 0) { - if (m->revision == revision) { - if (try_module_get(m->me)) { - up(&ip6t_mutex); - return m; - } - } else - err = -EPROTOTYPE; /* Found something. */ - } - } - up(&ip6t_mutex); - return ERR_PTR(err); -} - -/* Find target, grabs ref. Returns ERR_PTR() on error. */ -static inline struct ip6t_target *find_target(const char *name, u8 revision) -{ - struct ip6t_target *t; - int err = 0; - - if (down_interruptible(&ip6t_mutex) != 0) - return ERR_PTR(-EINTR); - - list_for_each_entry(t, &ip6t_target, list) { - if (strcmp(t->name, name) == 0) { - if (t->revision == revision) { - if (try_module_get(t->me)) { - up(&ip6t_mutex); - return t; - } - } else - err = -EPROTOTYPE; /* Found something. */ - } - } - up(&ip6t_mutex); - return ERR_PTR(err); -} - -struct ip6t_target *ip6t_find_target(const char *name, u8 revision) -{ - struct ip6t_target *target; - - target = try_then_request_module(find_target(name, revision), - "ip6t_%s", name); - if (IS_ERR(target) || !target) - return NULL; - return target; -} - -static int match_revfn(const char *name, u8 revision, int *bestp) -{ - struct ip6t_match *m; - int have_rev = 0; - - list_for_each_entry(m, &ip6t_match, list) { - if (strcmp(m->name, name) == 0) { - if (m->revision > *bestp) - *bestp = m->revision; - if (m->revision == revision) - have_rev = 1; - } - } - return have_rev; -} - -static int target_revfn(const char *name, u8 revision, int *bestp) -{ - struct ip6t_target *t; - int have_rev = 0; - - list_for_each_entry(t, &ip6t_target, list) { - if (strcmp(t->name, name) == 0) { - if (t->revision > *bestp) - *bestp = t->revision; - if (t->revision == revision) - have_rev = 1; - } - } - return have_rev; -} - -/* Returns true or fals (if no such extension at all) */ -static inline int find_revision(const char *name, u8 revision, - int (*revfn)(const char *, u8, int *), - int *err) -{ - int have_rev, best = -1; - - if (down_interruptible(&ip6t_mutex) != 0) { - *err = -EINTR; - return 1; - } - have_rev = revfn(name, revision, &best); - up(&ip6t_mutex); - - /* Nothing at all? Return 0 to try loading module. */ - if (best == -1) { - *err = -ENOENT; - return 0; - } - - *err = best; - if (!have_rev) - *err = -EPROTONOSUPPORT; - return 1; -} - - /* All zeroes == unconditional rule. */ static inline int unconditional(const struct ip6t_ip6 *ipv6) @@ -649,7 +430,8 @@ unconditional(const struct ip6t_ip6 *ipv6) /* Figures out from what hook each rule can be called: returns 0 if there are loops. Puts hook bitmask in comefrom. */ static int -mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks) +mark_source_chains(struct xt_table_info *newinfo, + unsigned int valid_hooks, void *entry0) { unsigned int hook; @@ -658,7 +440,7 @@ mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks) for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) { unsigned int pos = newinfo->hook_entry[hook]; struct ip6t_entry *e - = (struct ip6t_entry *)(newinfo->entries + pos); + = (struct ip6t_entry *)(entry0 + pos); if (!(valid_hooks & (1 << hook))) continue; @@ -708,13 +490,13 @@ mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks) goto next; e = (struct ip6t_entry *) - (newinfo->entries + pos); + (entry0 + pos); } while (oldpos == pos + e->next_offset); /* Move along one */ size = e->next_offset; e = (struct ip6t_entry *) - (newinfo->entries + pos + size); + (entry0 + pos + size); e->counters.pcnt = pos; pos += size; } else { @@ -731,7 +513,7 @@ mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks) newpos = pos + e->next_offset; } e = (struct ip6t_entry *) - (newinfo->entries + newpos); + (entry0 + newpos); e->counters.pcnt = pos; pos = newpos; } @@ -794,11 +576,11 @@ check_match(struct ip6t_entry_match *m, { struct ip6t_match *match; - match = try_then_request_module(find_match(m->u.user.name, - m->u.user.revision), + match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, + m->u.user.revision), "ip6t_%s", m->u.user.name); if (IS_ERR(match) || !match) { - duprintf("check_match: `%s' not found\n", m->u.user.name); + duprintf("check_match: `%s' not found\n", m->u.user.name); return match ? PTR_ERR(match) : -ENOENT; } m->u.kernel.match = match; @@ -839,8 +621,9 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, goto cleanup_matches; t = ip6t_get_target(e); - target = try_then_request_module(find_target(t->u.user.name, - t->u.user.revision), + target = try_then_request_module(xt_find_target(AF_INET6, + t->u.user.name, + t->u.user.revision), "ip6t_%s", t->u.user.name); if (IS_ERR(target) || !target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); @@ -876,7 +659,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, static inline int check_entry_size_and_hooks(struct ip6t_entry *e, - struct ip6t_table_info *newinfo, + struct xt_table_info *newinfo, unsigned char *base, unsigned char *limit, const unsigned int *hook_entries, @@ -910,7 +693,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, < 0 (not IP6T_RETURN). --RR */ /* Clear counters and comefrom */ - e->counters = ((struct ip6t_counters) { 0, 0 }); + e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; (*i)++; @@ -940,7 +723,8 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) static int translate_table(const char *name, unsigned int valid_hooks, - struct ip6t_table_info *newinfo, + struct xt_table_info *newinfo, + void *entry0, unsigned int size, unsigned int number, const unsigned int *hook_entries, @@ -961,11 +745,11 @@ translate_table(const char *name, duprintf("translate_table: size %u\n", newinfo->size); i = 0; /* Walk through entries, checking offsets. */ - ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, + ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, check_entry_size_and_hooks, newinfo, - newinfo->entries, - newinfo->entries + size, + entry0, + entry0 + size, hook_entries, underflows, &i); if (ret != 0) return ret; @@ -993,95 +777,79 @@ translate_table(const char *name, } } - if (!mark_source_chains(newinfo, valid_hooks)) + if (!mark_source_chains(newinfo, valid_hooks, entry0)) return -ELOOP; /* Finally, each sanity check must pass */ i = 0; - ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, + ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, check_entry, name, size, &i); if (ret != 0) { - IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, + IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); return ret; } /* And one copy for every other CPU */ for_each_cpu(i) { - if (i == 0) - continue; - memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i, - newinfo->entries, - SMP_ALIGN(newinfo->size)); + if (newinfo->entries[i] && newinfo->entries[i] != entry0) + memcpy(newinfo->entries[i], entry0, newinfo->size); } return ret; } -static struct ip6t_table_info * -replace_table(struct ip6t_table *table, - unsigned int num_counters, - struct ip6t_table_info *newinfo, - int *error) +/* Gets counters. */ +static inline int +add_entry_to_counter(const struct ip6t_entry *e, + struct xt_counters total[], + unsigned int *i) { - struct ip6t_table_info *oldinfo; - -#ifdef CONFIG_NETFILTER_DEBUG - { - struct ip6t_entry *table_base; - unsigned int i; - - for_each_cpu(i) { - table_base = - (void *)newinfo->entries - + TABLE_OFFSET(newinfo, i); - - table_base->comefrom = 0xdead57ac; - } - } -#endif - - /* Do the substitution. */ - write_lock_bh(&table->lock); - /* Check inside lock: is the old number correct? */ - if (num_counters != table->private->number) { - duprintf("num_counters != table->private->number (%u/%u)\n", - num_counters, table->private->number); - write_unlock_bh(&table->lock); - *error = -EAGAIN; - return NULL; - } - oldinfo = table->private; - table->private = newinfo; - newinfo->initial_entries = oldinfo->initial_entries; - write_unlock_bh(&table->lock); + ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); - return oldinfo; + (*i)++; + return 0; } -/* Gets counters. */ static inline int -add_entry_to_counter(const struct ip6t_entry *e, +set_entry_to_counter(const struct ip6t_entry *e, struct ip6t_counters total[], unsigned int *i) { - ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); + SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); (*i)++; return 0; } static void -get_counters(const struct ip6t_table_info *t, - struct ip6t_counters counters[]) +get_counters(const struct xt_table_info *t, + struct xt_counters counters[]) { unsigned int cpu; unsigned int i; + unsigned int curcpu; + + /* Instead of clearing (by a previous call to memset()) + * the counters and using adds, we set the counters + * with data used by 'current' CPU + * We dont care about preemption here. + */ + curcpu = raw_smp_processor_id(); + + i = 0; + IP6T_ENTRY_ITERATE(t->entries[curcpu], + t->size, + set_entry_to_counter, + counters, + &i); for_each_cpu(cpu) { + if (cpu == curcpu) + continue; i = 0; - IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu), + IP6T_ENTRY_ITERATE(t->entries[cpu], t->size, add_entry_to_counter, counters, @@ -1091,31 +859,33 @@ get_counters(const struct ip6t_table_info *t, static int copy_entries_to_user(unsigned int total_size, - struct ip6t_table *table, + struct xt_table *table, void __user *userptr) { unsigned int off, num, countersize; struct ip6t_entry *e; - struct ip6t_counters *counters; + struct xt_counters *counters; + struct xt_table_info *private = table->private; int ret = 0; + void *loc_cpu_entry; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care about). */ - countersize = sizeof(struct ip6t_counters) * table->private->number; + countersize = sizeof(struct xt_counters) * private->number; counters = vmalloc(countersize); if (counters == NULL) return -ENOMEM; /* First, sum counters... */ - memset(counters, 0, countersize); write_lock_bh(&table->lock); - get_counters(table->private, counters); + get_counters(private, counters); write_unlock_bh(&table->lock); - /* ... then copy entire thing from CPU 0... */ - if (copy_to_user(userptr, table->private->entries, total_size) != 0) { + /* choose the copy that is on ourc node/cpu */ + loc_cpu_entry = private->entries[raw_smp_processor_id()]; + if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) { ret = -EFAULT; goto free_counters; } @@ -1127,7 +897,7 @@ copy_entries_to_user(unsigned int total_size, struct ip6t_entry_match *m; struct ip6t_entry_target *t; - e = (struct ip6t_entry *)(table->private->entries + off); + e = (struct ip6t_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off + offsetof(struct ip6t_entry, counters), &counters[num], @@ -1173,23 +943,22 @@ get_entries(const struct ip6t_get_entries *entries, struct ip6t_get_entries __user *uptr) { int ret; - struct ip6t_table *t; + struct xt_table *t; - t = find_table_lock(entries->name); + t = xt_find_table_lock(AF_INET6, entries->name); if (t && !IS_ERR(t)) { - duprintf("t->private->number = %u\n", - t->private->number); - if (entries->size == t->private->size) - ret = copy_entries_to_user(t->private->size, + struct xt_table_info *private = t->private; + duprintf("t->private->number = %u\n", private->number); + if (entries->size == private->size) + ret = copy_entries_to_user(private->size, t, uptr->entrytable); else { duprintf("get_entries: I've got %u not %u!\n", - t->private->size, - entries->size); + private->size, entries->size); ret = -EINVAL; } module_put(t->me); - up(&ip6t_mutex); + xt_table_unlock(t); } else ret = t ? PTR_ERR(t) : -ENOENT; @@ -1201,45 +970,41 @@ do_replace(void __user *user, unsigned int len) { int ret; struct ip6t_replace tmp; - struct ip6t_table *t; - struct ip6t_table_info *newinfo, *oldinfo; - struct ip6t_counters *counters; + struct xt_table *t; + struct xt_table_info *newinfo, *oldinfo; + struct xt_counters *counters; + void *loc_cpu_entry, *loc_cpu_old_entry; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; - /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ - if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages) - return -ENOMEM; - - newinfo = vmalloc(sizeof(struct ip6t_table_info) - + SMP_ALIGN(tmp.size) * - (highest_possible_processor_id()+1)); + newinfo = xt_alloc_table_info(tmp.size); if (!newinfo) return -ENOMEM; - if (copy_from_user(newinfo->entries, user + sizeof(tmp), + /* choose the copy that is on our node/cpu */ + loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; + if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) { ret = -EFAULT; goto free_newinfo; } - counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters)); + counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters)); if (!counters) { ret = -ENOMEM; goto free_newinfo; } - memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters)); ret = translate_table(tmp.name, tmp.valid_hooks, - newinfo, tmp.size, tmp.num_entries, + newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) goto free_newinfo_counters; duprintf("ip_tables: Translated table\n"); - t = try_then_request_module(find_table_lock(tmp.name), + t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name), "ip6table_%s", tmp.name); if (!t || IS_ERR(t)) { ret = t ? PTR_ERR(t) : -ENOENT; @@ -1254,7 +1019,7 @@ do_replace(void __user *user, unsigned int len) goto put_module; } - oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); + oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret); if (!oldinfo) goto put_module; @@ -1271,24 +1036,25 @@ do_replace(void __user *user, unsigned int len) /* Get the old counters. */ get_counters(oldinfo, counters); /* Decrease module usage counts and free resource */ - IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL); - vfree(oldinfo); + loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; + IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL); + xt_free_table_info(oldinfo); if (copy_to_user(tmp.counters, counters, - sizeof(struct ip6t_counters) * tmp.num_counters) != 0) + sizeof(struct xt_counters) * tmp.num_counters) != 0) ret = -EFAULT; vfree(counters); - up(&ip6t_mutex); + xt_table_unlock(t); return ret; put_module: module_put(t->me); - up(&ip6t_mutex); + xt_table_unlock(t); free_newinfo_counters_untrans: - IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL); + IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL); free_newinfo_counters: vfree(counters); free_newinfo: - vfree(newinfo); + xt_free_table_info(newinfo); return ret; } @@ -1296,7 +1062,7 @@ do_replace(void __user *user, unsigned int len) * and everything is OK. */ static inline int add_counter_to_entry(struct ip6t_entry *e, - const struct ip6t_counters addme[], + const struct xt_counters addme[], unsigned int *i) { #if 0 @@ -1318,14 +1084,16 @@ static int do_add_counters(void __user *user, unsigned int len) { unsigned int i; - struct ip6t_counters_info tmp, *paddc; - struct ip6t_table *t; + struct xt_counters_info tmp, *paddc; + struct xt_table_info *private; + struct xt_table *t; int ret = 0; + void *loc_cpu_entry; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; - if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters)) + if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters)) return -EINVAL; paddc = vmalloc(len); @@ -1337,27 +1105,30 @@ do_add_counters(void __user *user, unsigned int len) goto free; } - t = find_table_lock(tmp.name); + t = xt_find_table_lock(AF_INET6, tmp.name); if (!t || IS_ERR(t)) { ret = t ? PTR_ERR(t) : -ENOENT; goto free; } write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + private = t->private; + if (private->number != paddc->num_counters) { ret = -EINVAL; goto unlock_up_free; } i = 0; - IP6T_ENTRY_ITERATE(t->private->entries, - t->private->size, + /* Choose the copy that is on our node */ + loc_cpu_entry = private->entries[smp_processor_id()]; + IP6T_ENTRY_ITERATE(loc_cpu_entry, + private->size, add_counter_to_entry, paddc->counters, &i); unlock_up_free: write_unlock_bh(&t->lock); - up(&ip6t_mutex); + xt_table_unlock(t); module_put(t->me); free: vfree(paddc); @@ -1401,7 +1172,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IP6T_SO_GET_INFO: { char name[IP6T_TABLE_MAXNAMELEN]; - struct ip6t_table *t; + struct xt_table *t; if (*len != sizeof(struct ip6t_getinfo)) { duprintf("length %u != %u\n", *len, @@ -1416,25 +1187,26 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) } name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; - t = try_then_request_module(find_table_lock(name), + t = try_then_request_module(xt_find_table_lock(AF_INET6, name), "ip6table_%s", name); if (t && !IS_ERR(t)) { struct ip6t_getinfo info; + struct xt_table_info *private = t->private; info.valid_hooks = t->valid_hooks; - memcpy(info.hook_entry, t->private->hook_entry, + memcpy(info.hook_entry, private->hook_entry, sizeof(info.hook_entry)); - memcpy(info.underflow, t->private->underflow, + memcpy(info.underflow, private->underflow, sizeof(info.underflow)); - info.num_entries = t->private->number; - info.size = t->private->size; + info.num_entries = private->number; + info.size = private->size; memcpy(info.name, name, sizeof(info.name)); if (copy_to_user(user, &info, *len) != 0) ret = -EFAULT; else ret = 0; - up(&ip6t_mutex); + xt_table_unlock(t); module_put(t->me); } else ret = t ? PTR_ERR(t) : -ENOENT; @@ -1461,7 +1233,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) case IP6T_SO_GET_REVISION_MATCH: case IP6T_SO_GET_REVISION_TARGET: { struct ip6t_get_revision rev; - int (*revfn)(const char *, u8, int *); + int target; if (*len != sizeof(rev)) { ret = -EINVAL; @@ -1473,12 +1245,13 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) } if (cmd == IP6T_SO_GET_REVISION_TARGET) - revfn = target_revfn; + target = 1; else - revfn = match_revfn; + target = 0; - try_then_request_module(find_revision(rev.name, rev.revision, - revfn, &ret), + try_then_request_module(xt_find_revision(AF_INET6, rev.name, + rev.revision, + target, &ret), "ip6t_%s", rev.name); break; } @@ -1491,308 +1264,52 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) return ret; } -/* Registration hooks for targets. */ -int -ip6t_register_target(struct ip6t_target *target) -{ - int ret; - - ret = down_interruptible(&ip6t_mutex); - if (ret != 0) - return ret; - list_add(&target->list, &ip6t_target); - up(&ip6t_mutex); - return ret; -} - -void -ip6t_unregister_target(struct ip6t_target *target) -{ - down(&ip6t_mutex); - LIST_DELETE(&ip6t_target, target); - up(&ip6t_mutex); -} - -int -ip6t_register_match(struct ip6t_match *match) -{ - int ret; - - ret = down_interruptible(&ip6t_mutex); - if (ret != 0) - return ret; - - list_add(&match->list, &ip6t_match); - up(&ip6t_mutex); - - return ret; -} - -void -ip6t_unregister_match(struct ip6t_match *match) -{ - down(&ip6t_mutex); - LIST_DELETE(&ip6t_match, match); - up(&ip6t_mutex); -} - -int ip6t_register_table(struct ip6t_table *table, +int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl) { int ret; - struct ip6t_table_info *newinfo; - static struct ip6t_table_info bootstrap + struct xt_table_info *newinfo; + static struct xt_table_info bootstrap = { 0, 0, 0, { 0 }, { 0 }, { } }; + void *loc_cpu_entry; - newinfo = vmalloc(sizeof(struct ip6t_table_info) - + SMP_ALIGN(repl->size) * - (highest_possible_processor_id()+1)); + newinfo = xt_alloc_table_info(repl->size); if (!newinfo) return -ENOMEM; - memcpy(newinfo->entries, repl->entries, repl->size); + /* choose the copy on our node/cpu */ + loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; + memcpy(loc_cpu_entry, repl->entries, repl->size); ret = translate_table(table->name, table->valid_hooks, - newinfo, repl->size, + newinfo, loc_cpu_entry, repl->size, repl->num_entries, repl->hook_entry, repl->underflow); if (ret != 0) { - vfree(newinfo); + xt_free_table_info(newinfo); return ret; } - ret = down_interruptible(&ip6t_mutex); - if (ret != 0) { - vfree(newinfo); + if (xt_register_table(table, &bootstrap, newinfo) != 0) { + xt_free_table_info(newinfo); return ret; } - /* Don't autoload: we'd eat our tail... */ - if (list_named_find(&ip6t_tables, table->name)) { - ret = -EEXIST; - goto free_unlock; - } - - /* Simplifies replace_table code. */ - table->private = &bootstrap; - if (!replace_table(table, 0, newinfo, &ret)) - goto free_unlock; - - duprintf("table->private->number = %u\n", - table->private->number); - - /* save number of initial entries */ - table->private->initial_entries = table->private->number; - - rwlock_init(&table->lock); - list_prepend(&ip6t_tables, table); - - unlock: - up(&ip6t_mutex); - return ret; - - free_unlock: - vfree(newinfo); - goto unlock; -} - -void ip6t_unregister_table(struct ip6t_table *table) -{ - down(&ip6t_mutex); - LIST_DELETE(&ip6t_tables, table); - up(&ip6t_mutex); - - /* Decrease module usage counts and free resources */ - IP6T_ENTRY_ITERATE(table->private->entries, table->private->size, - cleanup_entry, NULL); - vfree(table->private); -} - -/* Returns 1 if the port is matched by the range, 0 otherwise */ -static inline int -port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert) -{ - int ret; - - ret = (port >= min && port <= max) ^ invert; - return ret; -} - -static int -tcp_find_option(u_int8_t option, - const struct sk_buff *skb, - unsigned int tcpoff, - unsigned int optlen, - int invert, - int *hotdrop) -{ - /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ - u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; - unsigned int i; - - duprintf("tcp_match: finding option\n"); - if (!optlen) - return invert; - /* If we don't have the whole header, drop packet. */ - op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen, - _opt); - if (op == NULL) { - *hotdrop = 1; - return 0; - } - - for (i = 0; i < optlen; ) { - if (op[i] == option) return !invert; - if (op[i] < 2) i++; - else i += op[i+1]?:1; - } - - return invert; -} - -static int -tcp_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - struct tcphdr _tcph, *th; - const struct ip6t_tcp *tcpinfo = matchinfo; - - if (offset) { - /* To quote Alan: - - Don't allow a fragment of TCP 8 bytes in. Nobody normal - causes this. Its a cracker trying to break in by doing a - flag overwrite to pass the direction checks. - */ - if (offset == 1) { - duprintf("Dropping evil TCP offset=1 frag.\n"); - *hotdrop = 1; - } - /* Must not be a fragment. */ - return 0; - } - -#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) - - th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); - if (th == NULL) { - /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - duprintf("Dropping evil TCP offset=0 tinygram.\n"); - *hotdrop = 1; - return 0; - } - - if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], - ntohs(th->source), - !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))) - return 0; - if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], - ntohs(th->dest), - !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))) - return 0; - if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) - == tcpinfo->flg_cmp, - IP6T_TCP_INV_FLAGS)) - return 0; - if (tcpinfo->option) { - if (th->doff * 4 < sizeof(_tcph)) { - *hotdrop = 1; - return 0; - } - if (!tcp_find_option(tcpinfo->option, skb, protoff, - th->doff*4 - sizeof(*th), - tcpinfo->invflags & IP6T_TCP_INV_OPTION, - hotdrop)) - return 0; - } - return 1; -} - -/* Called when user tries to insert an entry of this type. */ -static int -tcp_checkentry(const char *tablename, - const struct ip6t_ip6 *ipv6, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - const struct ip6t_tcp *tcpinfo = matchinfo; - - /* Must specify proto == TCP, and no unknown invflags */ - return ipv6->proto == IPPROTO_TCP - && !(ipv6->invflags & IP6T_INV_PROTO) - && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp)) - && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK); + return 0; } -static int -udp_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) +void ip6t_unregister_table(struct xt_table *table) { - struct udphdr _udph, *uh; - const struct ip6t_udp *udpinfo = matchinfo; + struct xt_table_info *private; + void *loc_cpu_entry; - /* Must not be a fragment. */ - if (offset) - return 0; - - uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph); - if (uh == NULL) { - /* We've been asked to examine this packet, and we - can't. Hence, no choice but to drop. */ - duprintf("Dropping evil UDP tinygram.\n"); - *hotdrop = 1; - return 0; - } - - return port_match(udpinfo->spts[0], udpinfo->spts[1], - ntohs(uh->source), - !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT)) - && port_match(udpinfo->dpts[0], udpinfo->dpts[1], - ntohs(uh->dest), - !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT)); -} - -/* Called when user tries to insert an entry of this type. */ -static int -udp_checkentry(const char *tablename, - const struct ip6t_ip6 *ipv6, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) -{ - const struct ip6t_udp *udpinfo = matchinfo; + private = xt_unregister_table(table); - /* Must specify proto == UDP, and no unknown invflags */ - if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) { - duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto, - IPPROTO_UDP); - return 0; - } - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) { - duprintf("ip6t_udp: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp))); - return 0; - } - if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) { - duprintf("ip6t_udp: unknown flags %X\n", - udpinfo->invflags); - return 0; - } - - return 1; + /* Decrease module usage counts and free resources */ + loc_cpu_entry = private->entries[raw_smp_processor_id()]; + IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); + xt_free_table_info(private); } /* Returns 1 if the type and code is matched by the range, 0 otherwise */ @@ -1840,11 +1357,12 @@ icmp6_match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int icmp6_checkentry(const char *tablename, - const struct ip6t_ip6 *ipv6, + const void *entry, void *matchinfo, unsigned int matchsize, unsigned int hook_mask) { + const struct ip6t_ip6 *ipv6 = entry; const struct ip6t_icmp *icmpinfo = matchinfo; /* Must specify proto == ICMP, and no unknown invflags */ @@ -1874,187 +1392,78 @@ static struct nf_sockopt_ops ip6t_sockopts = { .get = do_ip6t_get_ctl, }; -static struct ip6t_match tcp_matchstruct = { - .name = "tcp", - .match = &tcp_match, - .checkentry = &tcp_checkentry, -}; - -static struct ip6t_match udp_matchstruct = { - .name = "udp", - .match = &udp_match, - .checkentry = &udp_checkentry, -}; - static struct ip6t_match icmp6_matchstruct = { .name = "icmp6", .match = &icmp6_match, .checkentry = &icmp6_checkentry, }; -#ifdef CONFIG_PROC_FS -static inline int print_name(const char *i, - off_t start_offset, char *buffer, int length, - off_t *pos, unsigned int *count) -{ - if ((*count)++ >= start_offset) { - unsigned int namelen; - - namelen = sprintf(buffer + *pos, "%s\n", - i + sizeof(struct list_head)); - if (*pos + namelen > length) { - /* Stop iterating */ - return 1; - } - *pos += namelen; - } - return 0; -} - -static inline int print_target(const struct ip6t_target *t, - off_t start_offset, char *buffer, int length, - off_t *pos, unsigned int *count) -{ - if (t == &ip6t_standard_target || t == &ip6t_error_target) - return 0; - return print_name((char *)t, start_offset, buffer, length, pos, count); -} - -static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length) -{ - off_t pos = 0; - unsigned int count = 0; - - if (down_interruptible(&ip6t_mutex) != 0) - return 0; - - LIST_FIND(&ip6t_tables, print_name, char *, - offset, buffer, length, &pos, &count); - - up(&ip6t_mutex); - - /* `start' hack - see fs/proc/generic.c line ~105 */ - *start=(char *)((unsigned long)count-offset); - return pos; -} - -static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length) -{ - off_t pos = 0; - unsigned int count = 0; - - if (down_interruptible(&ip6t_mutex) != 0) - return 0; - - LIST_FIND(&ip6t_target, print_target, struct ip6t_target *, - offset, buffer, length, &pos, &count); - - up(&ip6t_mutex); - - *start = (char *)((unsigned long)count - offset); - return pos; -} - -static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length) -{ - off_t pos = 0; - unsigned int count = 0; - - if (down_interruptible(&ip6t_mutex) != 0) - return 0; - - LIST_FIND(&ip6t_match, print_name, char *, - offset, buffer, length, &pos, &count); - - up(&ip6t_mutex); - - *start = (char *)((unsigned long)count - offset); - return pos; -} - -static const struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] = -{ { "ip6_tables_names", ip6t_get_tables }, - { "ip6_tables_targets", ip6t_get_targets }, - { "ip6_tables_matches", ip6t_get_matches }, - { NULL, NULL} }; -#endif /*CONFIG_PROC_FS*/ - static int __init init(void) { int ret; + xt_proto_init(AF_INET6); + /* Noone else will be downing sem now, so we won't sleep */ - down(&ip6t_mutex); - list_append(&ip6t_target, &ip6t_standard_target); - list_append(&ip6t_target, &ip6t_error_target); - list_append(&ip6t_match, &tcp_matchstruct); - list_append(&ip6t_match, &udp_matchstruct); - list_append(&ip6t_match, &icmp6_matchstruct); - up(&ip6t_mutex); + xt_register_target(AF_INET6, &ip6t_standard_target); + xt_register_target(AF_INET6, &ip6t_error_target); + xt_register_match(AF_INET6, &icmp6_matchstruct); /* Register setsockopt */ ret = nf_register_sockopt(&ip6t_sockopts); if (ret < 0) { duprintf("Unable to register sockopts.\n"); + xt_proto_fini(AF_INET6); return ret; } -#ifdef CONFIG_PROC_FS - { - struct proc_dir_entry *proc; - int i; - - for (i = 0; ip6t_proc_entry[i].name; i++) { - proc = proc_net_create(ip6t_proc_entry[i].name, 0, - ip6t_proc_entry[i].get_info); - if (!proc) { - while (--i >= 0) - proc_net_remove(ip6t_proc_entry[i].name); - nf_unregister_sockopt(&ip6t_sockopts); - return -ENOMEM; - } - proc->owner = THIS_MODULE; - } - } -#endif - - printk("ip6_tables: (C) 2000-2002 Netfilter core team\n"); + printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n"); return 0; } static void __exit fini(void) { nf_unregister_sockopt(&ip6t_sockopts); -#ifdef CONFIG_PROC_FS - { - int i; - for (i = 0; ip6t_proc_entry[i].name; i++) - proc_net_remove(ip6t_proc_entry[i].name); - } -#endif + xt_unregister_match(AF_INET6, &icmp6_matchstruct); + xt_unregister_target(AF_INET6, &ip6t_error_target); + xt_unregister_target(AF_INET6, &ip6t_standard_target); + xt_proto_fini(AF_INET6); } /* - * find specified header up to transport protocol header. - * If found target header, the offset to the header is set to *offset - * and return 0. otherwise, return -1. + * find the offset to specified header or the protocol number of last header + * if target < 0. "last header" is transport protocol header, ESP, or + * "No next header". + * + * If target header is found, its offset is set in *offset and return protocol + * number. Otherwise, return -1. + * + * Note that non-1st fragment is special case that "the protocol number + * of last header" is "next header" field in Fragment header. In this case, + * *offset is meaningless and fragment offset is stored in *fragoff if fragoff + * isn't NULL. * - * Notes: - non-1st Fragment Header isn't skipped. - * - ESP header isn't skipped. - * - The target header may be trancated. */ -int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) +int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, + int target, unsigned short *fragoff) { unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; u8 nexthdr = skb->nh.ipv6h->nexthdr; unsigned int len = skb->len - start; + if (fragoff) + *fragoff = 0; + while (nexthdr != target) { struct ipv6_opt_hdr _hdr, *hp; unsigned int hdrlen; - if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) + if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { + if (target < 0) + break; return -1; + } + hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); if (hp == NULL) return -1; @@ -2068,8 +1477,17 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) if (fp == NULL) return -1; - if (ntohs(*fp) & ~0x7) + _frag_off = ntohs(*fp) & ~0x7; + if (_frag_off) { + if (target < 0 && + ((!ipv6_ext_hdr(hp->nexthdr)) || + nexthdr == NEXTHDR_NONE)) { + if (fragoff) + *fragoff = _frag_off; + return hp->nexthdr; + } return -1; + } hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) hdrlen = (hp->hdrlen + 2) << 2; @@ -2082,18 +1500,15 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) } *offset = start; - return 0; + return nexthdr; } EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); -EXPORT_SYMBOL(ip6t_register_match); -EXPORT_SYMBOL(ip6t_unregister_match); -EXPORT_SYMBOL(ip6t_register_target); -EXPORT_SYMBOL(ip6t_unregister_target); EXPORT_SYMBOL(ip6t_ext_hdr); EXPORT_SYMBOL(ipv6_find_hdr); +EXPORT_SYMBOL(ip6_masked_addrcmp); module_init(init); module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index 8f5549b72720..306200c35057 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c @@ -62,7 +62,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, } static int ip6t_hl_checkentry(const char *tablename, - const struct ip6t_entry *e, + const void *entry, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0cd1d1bd9033..77c725832dec 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/skbuff.h> +#include <linux/if_arp.h> #include <linux/ip.h> #include <linux/spinlock.h> #include <linux/icmpv6.h> @@ -62,9 +63,8 @@ static void dump_packet(const struct nf_loginfo *info, return; } - /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */ - printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->saddr)); - printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->daddr)); + /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ + printk("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr)); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", @@ -443,7 +443,7 @@ ip6t_log_target(struct sk_buff **pskb, static int ip6t_log_checkentry(const char *tablename, - const struct ip6t_entry *e, + const void *entry, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c deleted file mode 100644 index eab8fb864ee0..000000000000 --- a/net/ipv6/netfilter/ip6t_MARK.c +++ /dev/null @@ -1,81 +0,0 @@ -/* This is a module which is used for setting the NFMARK field of an skb. */ - -/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/ip.h> -#include <net/checksum.h> - -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter_ipv6/ip6t_MARK.h> - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); - -static unsigned int -target(struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const void *targinfo, - void *userinfo) -{ - const struct ip6t_mark_target_info *markinfo = targinfo; - - if((*pskb)->nfmark != markinfo->mark) - (*pskb)->nfmark = markinfo->mark; - - return IP6T_CONTINUE; -} - -static int -checkentry(const char *tablename, - const struct ip6t_entry *e, - void *targinfo, - unsigned int targinfosize, - unsigned int hook_mask) -{ - if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_mark_target_info))) { - printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", - targinfosize, - IP6T_ALIGN(sizeof(struct ip6t_mark_target_info))); - return 0; - } - - if (strcmp(tablename, "mangle") != 0) { - printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); - return 0; - } - - return 1; -} - -static struct ip6t_target ip6t_mark_reg = { - .name = "MARK", - .target = target, - .checkentry = checkentry, - .me = THIS_MODULE -}; - -static int __init init(void) -{ - printk(KERN_DEBUG "registering ipv6 mark target\n"); - if (ip6t_register_target(&ip6t_mark_reg)) - return -EINVAL; - - return 0; -} - -static void __exit fini(void) -{ - ip6t_unregister_target(&ip6t_mark_reg); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_NFQUEUE.c b/net/ipv6/netfilter/ip6t_NFQUEUE.c deleted file mode 100644 index c6e3730e7409..000000000000 --- a/net/ipv6/netfilter/ip6t_NFQUEUE.c +++ /dev/null @@ -1,70 +0,0 @@ -/* ip6tables module for using new netfilter netlink queue - * - * (C) 2005 by Harald Welte <laforge@netfilter.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/skbuff.h> - -#include <linux/netfilter.h> -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter_ipv4/ipt_NFQUEUE.h> - -MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); -MODULE_DESCRIPTION("ip6tables NFQUEUE target"); -MODULE_LICENSE("GPL"); - -static unsigned int -target(struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const void *targinfo, - void *userinfo) -{ - const struct ipt_NFQ_info *tinfo = targinfo; - - return NF_QUEUE_NR(tinfo->queuenum); -} - -static int -checkentry(const char *tablename, - const struct ip6t_entry *e, - void *targinfo, - unsigned int targinfosize, - unsigned int hook_mask) -{ - if (targinfosize != IP6T_ALIGN(sizeof(struct ipt_NFQ_info))) { - printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n", - targinfosize, - IP6T_ALIGN(sizeof(struct ipt_NFQ_info))); - return 0; - } - - return 1; -} - -static struct ip6t_target ipt_NFQ_reg = { - .name = "NFQUEUE", - .target = target, - .checkentry = checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - return ip6t_register_target(&ipt_NFQ_reg); -} - -static void __exit fini(void) -{ - ip6t_unregister_target(&ipt_NFQ_reg); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index b03e87adca93..c745717b4ce2 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -218,12 +218,13 @@ static unsigned int reject6_target(struct sk_buff **pskb, } static int check(const char *tablename, - const struct ip6t_entry *e, + const void *entry, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) { const struct ip6t_reject_info *rejinfo = targinfo; + const struct ip6t_entry *e = entry; if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize); diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index dde37793d20b..219a30365dff 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/skbuff.h> +#include <linux/ip.h> #include <linux/ipv6.h> #include <linux/types.h> #include <net/checksum.h> @@ -53,7 +54,7 @@ match(const struct sk_buff *skb, unsigned int ptr; unsigned int hdrlen = 0; - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0) return 0; ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); @@ -97,7 +98,7 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, + const void *entry, void *matchinfo, unsigned int matchinfosize, unsigned int hook_mask) diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index c450a635e54b..b4c153a53500 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c @@ -36,19 +36,19 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); #endif /* - * (Type & 0xC0) >> 6 - * 0 -> ignorable - * 1 -> must drop the packet - * 2 -> send ICMP PARM PROB regardless and drop packet - * 3 -> Send ICMP if not a multicast address and drop packet + * (Type & 0xC0) >> 6 + * 0 -> ignorable + * 1 -> must drop the packet + * 2 -> send ICMP PARM PROB regardless and drop packet + * 3 -> Send ICMP if not a multicast address and drop packet * (Type & 0x20) >> 5 - * 0 -> invariant - * 1 -> can change the routing + * 0 -> invariant + * 1 -> can change the routing * (Type & 0x1F) Type - * 0 -> Pad1 (only 1 byte!) - * 1 -> PadN LENGTH info (total length = length + 2) - * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) - * 5 -> RTALERT 2 x x + * 0 -> Pad1 (only 1 byte!) + * 1 -> PadN LENGTH info (total length = length + 2) + * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) + * 5 -> RTALERT 2 x x */ static int @@ -60,59 +60,58 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ipv6_opt_hdr _optsh, *oh; - const struct ip6t_opts *optinfo = matchinfo; - unsigned int temp; - unsigned int ptr; - unsigned int hdrlen = 0; - unsigned int ret = 0; - u8 _opttype, *tp = NULL; - u8 _optlen, *lp = NULL; - unsigned int optlen; - + struct ipv6_opt_hdr _optsh, *oh; + const struct ip6t_opts *optinfo = matchinfo; + unsigned int temp; + unsigned int ptr; + unsigned int hdrlen = 0; + unsigned int ret = 0; + u8 _opttype, *tp = NULL; + u8 _optlen, *lp = NULL; + unsigned int optlen; + #if HOPBYHOP - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) #else - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) #endif return 0; - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); - if (oh == NULL){ - *hotdrop = 1; - return 0; - } - - hdrlen = ipv6_optlen(oh); - if (skb->len - ptr < hdrlen){ - /* Packet smaller than it's length field */ - return 0; - } - - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); - - DEBUGP("len %02X %04X %02X ", - optinfo->hdrlen, hdrlen, - (!(optinfo->flags & IP6T_OPTS_LEN) || - ((optinfo->hdrlen == hdrlen) ^ - !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); - - ret = (oh != NULL) - && - (!(optinfo->flags & IP6T_OPTS_LEN) || - ((optinfo->hdrlen == hdrlen) ^ - !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); - - ptr += 2; - hdrlen -= 2; - if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ - return ret; + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + if (oh == NULL) { + *hotdrop = 1; + return 0; + } + + hdrlen = ipv6_optlen(oh); + if (skb->len - ptr < hdrlen) { + /* Packet smaller than it's length field */ + return 0; + } + + DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); + + DEBUGP("len %02X %04X %02X ", + optinfo->hdrlen, hdrlen, + (!(optinfo->flags & IP6T_OPTS_LEN) || + ((optinfo->hdrlen == hdrlen) ^ + !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); + + ret = (oh != NULL) && + (!(optinfo->flags & IP6T_OPTS_LEN) || + ((optinfo->hdrlen == hdrlen) ^ + !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); + + ptr += 2; + hdrlen -= 2; + if (!(optinfo->flags & IP6T_OPTS_OPTS)) { + return ret; } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { DEBUGP("Not strict - not implemented"); } else { DEBUGP("Strict "); - DEBUGP("#%d ",optinfo->optsnr); - for(temp=0; temp<optinfo->optsnr; temp++){ + DEBUGP("#%d ", optinfo->optsnr); + for (temp = 0; temp < optinfo->optsnr; temp++) { /* type field exists ? */ if (hdrlen < 1) break; @@ -122,10 +121,10 @@ match(const struct sk_buff *skb, break; /* Type check */ - if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){ + if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) { DEBUGP("Tbad %02X %02X\n", *tp, - (optinfo->opts[temp] & 0xFF00)>>8); + (optinfo->opts[temp] & 0xFF00) >> 8); return 0; } else { DEBUGP("Tok "); @@ -169,7 +168,8 @@ match(const struct sk_buff *skb, } if (temp == optinfo->optsnr) return ret; - else return 0; + else + return 0; } return 0; @@ -178,25 +178,24 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) + const void *info, + void *matchinfo, + unsigned int matchinfosize, + unsigned int hook_mask) { - const struct ip6t_opts *optsinfo = matchinfo; - - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { - DEBUGP("ip6t_opts: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); - return 0; - } - if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { - DEBUGP("ip6t_opts: unknown flags %X\n", - optsinfo->invflags); - return 0; - } - - return 1; + const struct ip6t_opts *optsinfo = matchinfo; + + if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { + DEBUGP("ip6t_opts: matchsize %u != %u\n", + matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); + return 0; + } + if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { + DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); + return 0; + } + + return 1; } static struct ip6t_match opts_match = { @@ -212,12 +211,12 @@ static struct ip6t_match opts_match = { static int __init init(void) { - return ip6t_register_match(&opts_match); + return ip6t_register_match(&opts_match); } static void __exit cleanup(void) { - ip6t_unregister_match(&opts_match); + ip6t_unregister_match(&opts_match); } module_init(init); diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index 24bc0cde43a1..724285df8711 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/skbuff.h> +#include <linux/ip.h> #include <linux/ipv6.h> #include <linux/types.h> #include <net/checksum.h> @@ -55,7 +56,7 @@ match(const struct sk_buff *skb, /* Make sure this isn't an evil packet */ /*DEBUGP("ipv6_esp entered \n");*/ - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0) return 0; eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); @@ -75,7 +76,7 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, + const void *ip, void *matchinfo, unsigned int matchinfosize, unsigned int hook_mask) diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 616c2cbcd54d..27396ac0b9ed 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -27,45 +27,45 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { + unsigned char eui64[8]; + int i = 0; - unsigned char eui64[8]; - int i=0; - - if ( !(skb->mac.raw >= skb->head - && (skb->mac.raw + ETH_HLEN) <= skb->data) - && offset != 0) { - *hotdrop = 1; - return 0; - } - - memset(eui64, 0, sizeof(eui64)); - - if (eth_hdr(skb)->h_proto == ntohs(ETH_P_IPV6)) { - if (skb->nh.ipv6h->version == 0x6) { - memcpy(eui64, eth_hdr(skb)->h_source, 3); - memcpy(eui64 + 5, eth_hdr(skb)->h_source + 3, 3); - eui64[3]=0xff; - eui64[4]=0xfe; - eui64[0] |= 0x02; - - i=0; - while ((skb->nh.ipv6h->saddr.s6_addr[8+i] == - eui64[i]) && (i<8)) i++; - - if ( i == 8 ) - return 1; - } - } - - return 0; + if (!(skb->mac.raw >= skb->head && + (skb->mac.raw + ETH_HLEN) <= skb->data) && + offset != 0) { + *hotdrop = 1; + return 0; + } + + memset(eui64, 0, sizeof(eui64)); + + if (eth_hdr(skb)->h_proto == ntohs(ETH_P_IPV6)) { + if (skb->nh.ipv6h->version == 0x6) { + memcpy(eui64, eth_hdr(skb)->h_source, 3); + memcpy(eui64 + 5, eth_hdr(skb)->h_source + 3, 3); + eui64[3] = 0xff; + eui64[4] = 0xfe; + eui64[0] |= 0x02; + + i = 0; + while ((skb->nh.ipv6h->saddr.s6_addr[8+i] == eui64[i]) + && (i < 8)) + i++; + + if (i == 8) + return 1; + } + } + + return 0; } static int ip6t_eui64_checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) + const void *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) { if (hook_mask & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 085d5f8eea29..4c14125a0e26 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c @@ -31,12 +31,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); static inline int id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert) { - int r=0; - DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', - min,id,max); - r=(id >= min && id <= max) ^ invert; - DEBUGP(" result %s\n",r? "PASS" : "FAILED"); - return r; + int r = 0; + DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ', + min, id, max); + r = (id >= min && id <= max) ^ invert; + DEBUGP(" result %s\n", r ? "PASS" : "FAILED"); + return r; } static int @@ -48,92 +48,91 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct frag_hdr _frag, *fh; - const struct ip6t_frag *fraginfo = matchinfo; - unsigned int ptr; + struct frag_hdr _frag, *fh; + const struct ip6t_frag *fraginfo = matchinfo; + unsigned int ptr; - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0) return 0; fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); - if (fh == NULL){ + if (fh == NULL) { *hotdrop = 1; return 0; } - DEBUGP("INFO %04X ", fh->frag_off); - DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); - DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); - DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF)); - DEBUGP("ID %u %08X\n", ntohl(fh->identification), - ntohl(fh->identification)); - - DEBUGP("IPv6 FRAG id %02X ", - (id_match(fraginfo->ids[0], fraginfo->ids[1], - ntohl(fh->identification), - !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); - DEBUGP("res %02X %02X%04X %02X ", - (fraginfo->flags & IP6T_FRAG_RES), fh->reserved, - ntohs(fh->frag_off) & 0x6, - !((fraginfo->flags & IP6T_FRAG_RES) - && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); - DEBUGP("first %02X %02X %02X ", - (fraginfo->flags & IP6T_FRAG_FST), - ntohs(fh->frag_off) & ~0x7, - !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(fh->frag_off) & ~0x7))); - DEBUGP("mf %02X %02X %02X ", - (fraginfo->flags & IP6T_FRAG_MF), - ntohs(fh->frag_off) & IP6_MF, - !((fraginfo->flags & IP6T_FRAG_MF) - && !((ntohs(fh->frag_off) & IP6_MF)))); - DEBUGP("last %02X %02X %02X\n", - (fraginfo->flags & IP6T_FRAG_NMF), - ntohs(fh->frag_off) & IP6_MF, - !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(fh->frag_off) & IP6_MF))); - - return (fh != NULL) - && - (id_match(fraginfo->ids[0], fraginfo->ids[1], - ntohl(fh->identification), - !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) - && - !((fraginfo->flags & IP6T_FRAG_RES) - && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) - && - !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(fh->frag_off) & ~0x7)) - && - !((fraginfo->flags & IP6T_FRAG_MF) - && !(ntohs(fh->frag_off) & IP6_MF)) - && - !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(fh->frag_off) & IP6_MF)); + DEBUGP("INFO %04X ", fh->frag_off); + DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); + DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); + DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF)); + DEBUGP("ID %u %08X\n", ntohl(fh->identification), + ntohl(fh->identification)); + + DEBUGP("IPv6 FRAG id %02X ", + (id_match(fraginfo->ids[0], fraginfo->ids[1], + ntohl(fh->identification), + !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))); + DEBUGP("res %02X %02X%04X %02X ", + (fraginfo->flags & IP6T_FRAG_RES), fh->reserved, + ntohs(fh->frag_off) & 0x6, + !((fraginfo->flags & IP6T_FRAG_RES) + && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); + DEBUGP("first %02X %02X %02X ", + (fraginfo->flags & IP6T_FRAG_FST), + ntohs(fh->frag_off) & ~0x7, + !((fraginfo->flags & IP6T_FRAG_FST) + && (ntohs(fh->frag_off) & ~0x7))); + DEBUGP("mf %02X %02X %02X ", + (fraginfo->flags & IP6T_FRAG_MF), + ntohs(fh->frag_off) & IP6_MF, + !((fraginfo->flags & IP6T_FRAG_MF) + && !((ntohs(fh->frag_off) & IP6_MF)))); + DEBUGP("last %02X %02X %02X\n", + (fraginfo->flags & IP6T_FRAG_NMF), + ntohs(fh->frag_off) & IP6_MF, + !((fraginfo->flags & IP6T_FRAG_NMF) + && (ntohs(fh->frag_off) & IP6_MF))); + + return (fh != NULL) + && + (id_match(fraginfo->ids[0], fraginfo->ids[1], + ntohl(fh->identification), + !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))) + && + !((fraginfo->flags & IP6T_FRAG_RES) + && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) + && + !((fraginfo->flags & IP6T_FRAG_FST) + && (ntohs(fh->frag_off) & ~0x7)) + && + !((fraginfo->flags & IP6T_FRAG_MF) + && !(ntohs(fh->frag_off) & IP6_MF)) + && + !((fraginfo->flags & IP6T_FRAG_NMF) + && (ntohs(fh->frag_off) & IP6_MF)); } /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) + const void *ip, + void *matchinfo, + unsigned int matchinfosize, + unsigned int hook_mask) { - const struct ip6t_frag *fraginfo = matchinfo; - - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) { - DEBUGP("ip6t_frag: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag))); - return 0; - } - if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { - DEBUGP("ip6t_frag: unknown flags %X\n", - fraginfo->invflags); - return 0; - } - - return 1; + const struct ip6t_frag *fraginfo = matchinfo; + + if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) { + DEBUGP("ip6t_frag: matchsize %u != %u\n", + matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag))); + return 0; + } + if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { + DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); + return 0; + } + + return 1; } static struct ip6t_match frag_match = { @@ -145,12 +144,12 @@ static struct ip6t_match frag_match = { static int __init init(void) { - return ip6t_register_match(&frag_match); + return ip6t_register_match(&frag_match); } static void __exit cleanup(void) { - ip6t_unregister_match(&frag_match); + ip6t_unregister_match(&frag_match); } module_init(init); diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 1d09485111d0..37a8474a7e0c 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c @@ -36,19 +36,19 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); #endif /* - * (Type & 0xC0) >> 6 - * 0 -> ignorable - * 1 -> must drop the packet - * 2 -> send ICMP PARM PROB regardless and drop packet - * 3 -> Send ICMP if not a multicast address and drop packet + * (Type & 0xC0) >> 6 + * 0 -> ignorable + * 1 -> must drop the packet + * 2 -> send ICMP PARM PROB regardless and drop packet + * 3 -> Send ICMP if not a multicast address and drop packet * (Type & 0x20) >> 5 - * 0 -> invariant - * 1 -> can change the routing + * 0 -> invariant + * 1 -> can change the routing * (Type & 0x1F) Type - * 0 -> Pad1 (only 1 byte!) - * 1 -> PadN LENGTH info (total length = length + 2) - * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) - * 5 -> RTALERT 2 x x + * 0 -> Pad1 (only 1 byte!) + * 1 -> PadN LENGTH info (total length = length + 2) + * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) + * 5 -> RTALERT 2 x x */ static int @@ -60,59 +60,58 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ipv6_opt_hdr _optsh, *oh; - const struct ip6t_opts *optinfo = matchinfo; - unsigned int temp; - unsigned int ptr; - unsigned int hdrlen = 0; - unsigned int ret = 0; - u8 _opttype, *tp = NULL; - u8 _optlen, *lp = NULL; - unsigned int optlen; - + struct ipv6_opt_hdr _optsh, *oh; + const struct ip6t_opts *optinfo = matchinfo; + unsigned int temp; + unsigned int ptr; + unsigned int hdrlen = 0; + unsigned int ret = 0; + u8 _opttype, *tp = NULL; + u8 _optlen, *lp = NULL; + unsigned int optlen; + #if HOPBYHOP - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) #else - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) #endif return 0; - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); - if (oh == NULL){ - *hotdrop = 1; - return 0; - } - - hdrlen = ipv6_optlen(oh); - if (skb->len - ptr < hdrlen){ - /* Packet smaller than it's length field */ - return 0; - } - - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); - - DEBUGP("len %02X %04X %02X ", - optinfo->hdrlen, hdrlen, - (!(optinfo->flags & IP6T_OPTS_LEN) || - ((optinfo->hdrlen == hdrlen) ^ - !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); - - ret = (oh != NULL) - && - (!(optinfo->flags & IP6T_OPTS_LEN) || - ((optinfo->hdrlen == hdrlen) ^ - !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); - - ptr += 2; - hdrlen -= 2; - if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ - return ret; + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + if (oh == NULL) { + *hotdrop = 1; + return 0; + } + + hdrlen = ipv6_optlen(oh); + if (skb->len - ptr < hdrlen) { + /* Packet smaller than it's length field */ + return 0; + } + + DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); + + DEBUGP("len %02X %04X %02X ", + optinfo->hdrlen, hdrlen, + (!(optinfo->flags & IP6T_OPTS_LEN) || + ((optinfo->hdrlen == hdrlen) ^ + !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); + + ret = (oh != NULL) && + (!(optinfo->flags & IP6T_OPTS_LEN) || + ((optinfo->hdrlen == hdrlen) ^ + !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); + + ptr += 2; + hdrlen -= 2; + if (!(optinfo->flags & IP6T_OPTS_OPTS)) { + return ret; } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { DEBUGP("Not strict - not implemented"); } else { DEBUGP("Strict "); - DEBUGP("#%d ",optinfo->optsnr); - for(temp=0; temp<optinfo->optsnr; temp++){ + DEBUGP("#%d ", optinfo->optsnr); + for (temp = 0; temp < optinfo->optsnr; temp++) { /* type field exists ? */ if (hdrlen < 1) break; @@ -122,10 +121,10 @@ match(const struct sk_buff *skb, break; /* Type check */ - if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){ + if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) { DEBUGP("Tbad %02X %02X\n", *tp, - (optinfo->opts[temp] & 0xFF00)>>8); + (optinfo->opts[temp] & 0xFF00) >> 8); return 0; } else { DEBUGP("Tok "); @@ -169,7 +168,8 @@ match(const struct sk_buff *skb, } if (temp == optinfo->optsnr) return ret; - else return 0; + else + return 0; } return 0; @@ -178,25 +178,24 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) + const void *entry, + void *matchinfo, + unsigned int matchinfosize, + unsigned int hook_mask) { - const struct ip6t_opts *optsinfo = matchinfo; - - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { - DEBUGP("ip6t_opts: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); - return 0; - } - if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { - DEBUGP("ip6t_opts: unknown flags %X\n", - optsinfo->invflags); - return 0; - } - - return 1; + const struct ip6t_opts *optsinfo = matchinfo; + + if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { + DEBUGP("ip6t_opts: matchsize %u != %u\n", + matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); + return 0; + } + if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { + DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); + return 0; + } + + return 1; } static struct ip6t_match opts_match = { @@ -212,12 +211,12 @@ static struct ip6t_match opts_match = { static int __init init(void) { - return ip6t_register_match(&opts_match); + return ip6t_register_match(&opts_match); } static void __exit cleanup(void) { - ip6t_unregister_match(&opts_match); + ip6t_unregister_match(&opts_match); } module_init(init); diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c index 0beaff5471dd..c5d9079f2d9d 100644 --- a/net/ipv6/netfilter/ip6t_hl.c +++ b/net/ipv6/netfilter/ip6t_hl.c @@ -48,7 +48,7 @@ static int match(const struct sk_buff *skb, const struct net_device *in, return 0; } -static int checkentry(const char *tablename, const struct ip6t_ip6 *ip, +static int checkentry(const char *tablename, const void *entry, void *matchinfo, unsigned int matchsize, unsigned int hook_mask) { diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 32e67f05845b..83ad6b272f7e 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -50,20 +50,20 @@ ipv6header_match(const struct sk_buff *skb, len = skb->len - ptr; temp = 0; - while (ip6t_ext_hdr(nexthdr)) { + while (ip6t_ext_hdr(nexthdr)) { struct ipv6_opt_hdr _hdr, *hp; - int hdrlen; + int hdrlen; /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; + if (len < (int)sizeof(struct ipv6_opt_hdr)) + return 0; /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { + if (nexthdr == NEXTHDR_NONE) { temp |= MASK_NONE; break; } /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { + if (nexthdr == NEXTHDR_ESP) { temp |= MASK_ESP; break; } @@ -72,43 +72,43 @@ ipv6header_match(const struct sk_buff *skb, BUG_ON(hp == NULL); /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); + if (nexthdr == NEXTHDR_FRAGMENT) { + hdrlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) + hdrlen = (hp->hdrlen + 2) << 2; + else + hdrlen = ipv6_optlen(hp); /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - temp |= MASK_HOPOPTS; - break; - case NEXTHDR_ROUTING: - temp |= MASK_ROUTING; - break; - case NEXTHDR_FRAGMENT: - temp |= MASK_FRAGMENT; - break; - case NEXTHDR_AUTH: - temp |= MASK_AH; - break; - case NEXTHDR_DEST: - temp |= MASK_DSTOPTS; - break; - default: - return 0; - break; + switch (nexthdr) { + case NEXTHDR_HOP: + temp |= MASK_HOPOPTS; + break; + case NEXTHDR_ROUTING: + temp |= MASK_ROUTING; + break; + case NEXTHDR_FRAGMENT: + temp |= MASK_FRAGMENT; + break; + case NEXTHDR_AUTH: + temp |= MASK_AH; + break; + case NEXTHDR_DEST: + temp |= MASK_DSTOPTS; + break; + default: + return 0; + break; } - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; + nexthdr = hp->nexthdr; + len -= hdrlen; + ptr += hdrlen; if (ptr > skb->len) break; - } + } - if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) ) + if ((nexthdr != NEXTHDR_NONE) && (nexthdr != NEXTHDR_ESP)) temp |= MASK_PROTO; if (info->modeflag) @@ -124,7 +124,7 @@ ipv6header_match(const struct sk_buff *skb, static int ipv6header_checkentry(const char *tablename, - const struct ip6t_ip6 *ip, + const void *ip, void *matchinfo, unsigned int matchsize, unsigned int hook_mask) @@ -137,8 +137,8 @@ ipv6header_checkentry(const char *tablename, return 0; /* invflags is 0 or 0xff in hard mode */ - if ((!info->modeflag) && info->invflags != 0x00 - && info->invflags != 0xFF) + if ((!info->modeflag) && info->invflags != 0x00 && + info->invflags != 0xFF) return 0; return 1; @@ -152,7 +152,7 @@ static struct ip6t_match ip6t_ipv6header_match = { .me = THIS_MODULE, }; -static int __init ipv6header_init(void) +static int __init ipv6header_init(void) { return ip6t_register_match(&ip6t_ipv6header_match); } @@ -164,4 +164,3 @@ static void __exit ipv6header_exit(void) module_init(ipv6header_init); module_exit(ipv6header_exit); - diff --git a/net/ipv6/netfilter/ip6t_length.c b/net/ipv6/netfilter/ip6t_length.c deleted file mode 100644 index e0537d3811d5..000000000000 --- a/net/ipv6/netfilter/ip6t_length.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Length Match - IPv6 Port */ - -/* (C) 1999-2001 James Morris <jmorros@intercode.com.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/netfilter_ipv6/ip6t_length.h> -#include <linux/netfilter_ipv6/ip6_tables.h> - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); -MODULE_DESCRIPTION("IPv6 packet length match"); - -static int -match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - const struct ip6t_length_info *info = matchinfo; - u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr); - - return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; -} - -static int -checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info))) - return 0; - - return 1; -} - -static struct ip6t_match length_match = { - .name = "length", - .match = &match, - .checkentry = &checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - return ip6t_register_match(&length_match); -} - -static void __exit fini(void) -{ - ip6t_unregister_match(&length_match); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_limit.c b/net/ipv6/netfilter/ip6t_limit.c deleted file mode 100644 index fb782f610be2..000000000000 --- a/net/ipv6/netfilter/ip6t_limit.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Kernel module to control the rate - * - * 2 September 1999: Changed from the target RATE to the match - * `limit', removed logging. Did I mention that - * Alexey is a fucking genius? - * Rusty Russell (rusty@rustcorp.com.au). */ - -/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> - * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> - -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter_ipv6/ip6t_limit.h> - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); -MODULE_DESCRIPTION("rate limiting within ip6tables"); - -/* The algorithm used is the Simple Token Bucket Filter (TBF) - * see net/sched/sch_tbf.c in the linux source tree - */ - -static DEFINE_SPINLOCK(limit_lock); - -/* Rusty: This is my (non-mathematically-inclined) understanding of - this algorithm. The `average rate' in jiffies becomes your initial - amount of credit `credit' and the most credit you can ever have - `credit_cap'. The `peak rate' becomes the cost of passing the - test, `cost'. - - `prev' tracks the last packet hit: you gain one credit per jiffy. - If you get credit balance more than this, the extra credit is - discarded. Every time the match passes, you lose `cost' credits; - if you don't have that many, the test fails. - - See Alexey's formal explanation in net/sched/sch_tbf.c. - - To avoid underflow, we multiply by 128 (ie. you get 128 credits per - jiffy). Hence a cost of 2^32-1, means one pass per 32768 seconds - at 1024HZ (or one every 9 hours). A cost of 1 means 12800 passes - per second at 100HZ. */ - -#define CREDITS_PER_JIFFY 128 - -static int -ip6t_limit_match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master; - unsigned long now = jiffies; - - spin_lock_bh(&limit_lock); - r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY; - if (r->credit > r->credit_cap) - r->credit = r->credit_cap; - - if (r->credit >= r->cost) { - /* We're not limited. */ - r->credit -= r->cost; - spin_unlock_bh(&limit_lock); - return 1; - } - - spin_unlock_bh(&limit_lock); - return 0; -} - -/* Precision saver. */ -static u_int32_t -user2credits(u_int32_t user) -{ - /* If multiplying would overflow... */ - if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) - /* Divide first. */ - return (user / IP6T_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; - - return (user * HZ * CREDITS_PER_JIFFY) / IP6T_LIMIT_SCALE; -} - -static int -ip6t_limit_checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - struct ip6t_rateinfo *r = matchinfo; - - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rateinfo))) - return 0; - - /* Check for overflow. */ - if (r->burst == 0 - || user2credits(r->avg * r->burst) < user2credits(r->avg)) { - printk("Call rusty: overflow in ip6t_limit: %u/%u\n", - r->avg, r->burst); - return 0; - } - - /* User avg in seconds * IP6T_LIMIT_SCALE: convert to jiffies * - 128. */ - r->prev = jiffies; - r->credit = user2credits(r->avg * r->burst); /* Credits full. */ - r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ - r->cost = user2credits(r->avg); - - /* For SMP, we only want to use one set of counters. */ - r->master = r; - - return 1; -} - -static struct ip6t_match ip6t_limit_reg = { - .name = "limit", - .match = ip6t_limit_match, - .checkentry = ip6t_limit_checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - if (ip6t_register_match(&ip6t_limit_reg)) - return -EINVAL; - return 0; -} - -static void __exit fini(void) -{ - ip6t_unregister_match(&ip6t_limit_reg); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_mac.c b/net/ipv6/netfilter/ip6t_mac.c deleted file mode 100644 index 526d43e37234..000000000000 --- a/net/ipv6/netfilter/ip6t_mac.c +++ /dev/null @@ -1,80 +0,0 @@ -/* Kernel module to match MAC address parameters. */ - -/* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/if_ether.h> - -#include <linux/netfilter_ipv6/ip6t_mac.h> -#include <linux/netfilter_ipv6/ip6_tables.h> - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MAC address matching module for IPv6"); -MODULE_AUTHOR("Netfilter Core Teaam <coreteam@netfilter.org>"); - -static int -match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - const struct ip6t_mac_info *info = matchinfo; - - /* Is mac pointer valid? */ - return (skb->mac.raw >= skb->head - && (skb->mac.raw + ETH_HLEN) <= skb->data - /* If so, compare... */ - && ((memcmp(eth_hdr(skb)->h_source, info->srcaddr, ETH_ALEN) - == 0) ^ info->invert)); -} - -static int -ip6t_mac_checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - if (hook_mask - & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) - | (1 << NF_IP6_FORWARD))) { - printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or" - " FORWARD\n"); - return 0; - } - - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mac_info))) - return 0; - - return 1; -} - -static struct ip6t_match mac_match = { - .name = "mac", - .match = &match, - .checkentry = &ip6t_mac_checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - return ip6t_register_match(&mac_match); -} - -static void __exit fini(void) -{ - ip6t_unregister_match(&mac_match); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_mark.c b/net/ipv6/netfilter/ip6t_mark.c deleted file mode 100644 index affc3de364fc..000000000000 --- a/net/ipv6/netfilter/ip6t_mark.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Kernel module to match NFMARK values. */ - -/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include <linux/module.h> -#include <linux/skbuff.h> - -#include <linux/netfilter_ipv6/ip6t_mark.h> -#include <linux/netfilter_ipv6/ip6_tables.h> - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); -MODULE_DESCRIPTION("ip6tables mark match"); - -static int -match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - const struct ip6t_mark_info *info = matchinfo; - - return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; -} - -static int -checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mark_info))) - return 0; - - return 1; -} - -static struct ip6t_match mark_match = { - .name = "mark", - .match = &match, - .checkentry = &checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - return ip6t_register_match(&mark_match); -} - -static void __exit fini(void) -{ - ip6t_unregister_match(&mark_match); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c index 6e3246153fa3..49f7829dfbc2 100644 --- a/net/ipv6/netfilter/ip6t_multiport.c +++ b/net/ipv6/netfilter/ip6t_multiport.c @@ -84,11 +84,12 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, + const void *info, void *matchinfo, unsigned int matchsize, unsigned int hook_mask) { + const struct ip6t_ip6 *ip = info; const struct ip6t_multiport *multiinfo = matchinfo; if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport))) diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 4de4cdad4b7d..8c8a4c7ec934 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c @@ -36,14 +36,14 @@ match(const struct sk_buff *skb, if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file) return 0; - if(info->match & IP6T_OWNER_UID) { - if((skb->sk->sk_socket->file->f_uid != info->uid) ^ + if (info->match & IP6T_OWNER_UID) { + if ((skb->sk->sk_socket->file->f_uid != info->uid) ^ !!(info->invert & IP6T_OWNER_UID)) return 0; } - if(info->match & IP6T_OWNER_GID) { - if((skb->sk->sk_socket->file->f_gid != info->gid) ^ + if (info->match & IP6T_OWNER_GID) { + if ((skb->sk->sk_socket->file->f_gid != info->gid) ^ !!(info->invert & IP6T_OWNER_GID)) return 0; } @@ -53,23 +53,23 @@ match(const struct sk_buff *skb, static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) + const void *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) { const struct ip6t_owner_info *info = matchinfo; - if (hook_mask - & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) { - printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); - return 0; - } + if (hook_mask + & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) { + printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); + return 0; + } if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info))) return 0; - if (info->match & (IP6T_OWNER_PID|IP6T_OWNER_SID)) { + if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { printk("ipt_owner: pid and sid matching " "not supported anymore\n"); return 0; diff --git a/net/ipv6/netfilter/ip6t_physdev.c b/net/ipv6/netfilter/ip6t_physdev.c deleted file mode 100644 index 71515c86ece1..000000000000 --- a/net/ipv6/netfilter/ip6t_physdev.c +++ /dev/null @@ -1,135 +0,0 @@ -/* Kernel module to match the bridge port in and - * out device for IP packets coming into contact with a bridge. */ - -/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/netfilter_ipv6/ip6t_physdev.h> -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter_bridge.h> -#define MATCH 1 -#define NOMATCH 0 - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); -MODULE_DESCRIPTION("iptables bridge physical device match module"); - -static int -match(const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const void *matchinfo, - int offset, - unsigned int protoff, - int *hotdrop) -{ - int i; - static const char nulldevname[IFNAMSIZ]; - const struct ip6t_physdev_info *info = matchinfo; - unsigned int ret; - const char *indev, *outdev; - struct nf_bridge_info *nf_bridge; - - /* Not a bridged IP packet or no info available yet: - * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if - * the destination device will be a bridge. */ - if (!(nf_bridge = skb->nf_bridge)) { - /* Return MATCH if the invert flags of the used options are on */ - if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) && - !(info->invert & IP6T_PHYSDEV_OP_BRIDGED)) - return NOMATCH; - if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN) && - !(info->invert & IP6T_PHYSDEV_OP_ISIN)) - return NOMATCH; - if ((info->bitmask & IP6T_PHYSDEV_OP_ISOUT) && - !(info->invert & IP6T_PHYSDEV_OP_ISOUT)) - return NOMATCH; - if ((info->bitmask & IP6T_PHYSDEV_OP_IN) && - !(info->invert & IP6T_PHYSDEV_OP_IN)) - return NOMATCH; - if ((info->bitmask & IP6T_PHYSDEV_OP_OUT) && - !(info->invert & IP6T_PHYSDEV_OP_OUT)) - return NOMATCH; - return MATCH; - } - - /* This only makes sense in the FORWARD and POSTROUTING chains */ - if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) && - (!!(nf_bridge->mask & BRNF_BRIDGED) ^ - !(info->invert & IP6T_PHYSDEV_OP_BRIDGED))) - return NOMATCH; - - if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN && - (!nf_bridge->physindev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISIN))) || - (info->bitmask & IP6T_PHYSDEV_OP_ISOUT && - (!nf_bridge->physoutdev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISOUT)))) - return NOMATCH; - - if (!(info->bitmask & IP6T_PHYSDEV_OP_IN)) - goto match_outdev; - indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; - for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { - ret |= (((const unsigned int *)indev)[i] - ^ ((const unsigned int *)info->physindev)[i]) - & ((const unsigned int *)info->in_mask)[i]; - } - - if ((ret == 0) ^ !(info->invert & IP6T_PHYSDEV_OP_IN)) - return NOMATCH; - -match_outdev: - if (!(info->bitmask & IP6T_PHYSDEV_OP_OUT)) - return MATCH; - outdev = nf_bridge->physoutdev ? - nf_bridge->physoutdev->name : nulldevname; - for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) { - ret |= (((const unsigned int *)outdev)[i] - ^ ((const unsigned int *)info->physoutdev)[i]) - & ((const unsigned int *)info->out_mask)[i]; - } - - return (ret != 0) ^ !(info->invert & IP6T_PHYSDEV_OP_OUT); -} - -static int -checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchsize, - unsigned int hook_mask) -{ - const struct ip6t_physdev_info *info = matchinfo; - - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_physdev_info))) - return 0; - if (!(info->bitmask & IP6T_PHYSDEV_OP_MASK) || - info->bitmask & ~IP6T_PHYSDEV_OP_MASK) - return 0; - return 1; -} - -static struct ip6t_match physdev_match = { - .name = "physdev", - .match = &match, - .checkentry = &checkentry, - .me = THIS_MODULE, -}; - -static int __init init(void) -{ - return ip6t_register_match(&physdev_match); -} - -static void __exit fini(void) -{ - ip6t_unregister_match(&physdev_match); -} - -module_init(init); -module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c new file mode 100644 index 000000000000..afe1cc4c18a5 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_policy.c @@ -0,0 +1,175 @@ +/* IP tables module for matching IPsec policy + * + * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <net/xfrm.h> + +#include <linux/netfilter_ipv6.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter_ipv6/ip6t_policy.h> + +MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); +MODULE_DESCRIPTION("IPtables IPsec policy matching module"); +MODULE_LICENSE("GPL"); + + +static inline int +match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e) +{ +#define MATCH_ADDR(x,y,z) (!e->match.x || \ + ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x) +#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) + + return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) && + MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) && + MATCH(proto, x->id.proto) && + MATCH(mode, x->props.mode) && + MATCH(spi, x->id.spi) && + MATCH(reqid, x->props.reqid); +} + +static int +match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info) +{ + const struct ip6t_policy_elem *e; + struct sec_path *sp = skb->sp; + int strict = info->flags & IP6T_POLICY_MATCH_STRICT; + int i, pos; + + if (sp == NULL) + return -1; + if (strict && info->len != sp->len) + return 0; + + for (i = sp->len - 1; i >= 0; i--) { + pos = strict ? i - sp->len + 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(sp->x[i].xvec, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int +match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info) +{ + const struct ip6t_policy_elem *e; + struct dst_entry *dst = skb->dst; + int strict = info->flags & IP6T_POLICY_MATCH_STRICT; + int i, pos; + + if (dst->xfrm == NULL) + return -1; + + for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { + pos = strict ? i : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(dst->xfrm, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + unsigned int protoff, + int *hotdrop) +{ + const struct ip6t_policy_info *info = matchinfo; + int ret; + + if (info->flags & IP6T_POLICY_MATCH_IN) + ret = match_policy_in(skb, info); + else + ret = match_policy_out(skb, info); + + if (ret < 0) + ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0; + else if (info->flags & IP6T_POLICY_MATCH_NONE) + ret = 0; + + return ret; +} + +static int checkentry(const char *tablename, const void *ip_void, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + struct ip6t_policy_info *info = matchinfo; + + if (matchsize != IP6T_ALIGN(sizeof(*info))) { + printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n", + matchsize, IP6T_ALIGN(sizeof(*info))); + return 0; + } + if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) { + printk(KERN_ERR "ip6t_policy: neither incoming nor " + "outgoing policy selected\n"); + return 0; + } + if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN) + && info->flags & IP6T_POLICY_MATCH_OUT) { + printk(KERN_ERR "ip6t_policy: output policy not valid in " + "PRE_ROUTING and INPUT\n"); + return 0; + } + if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT) + && info->flags & IP6T_POLICY_MATCH_IN) { + printk(KERN_ERR "ip6t_policy: input policy not valid in " + "POST_ROUTING and OUTPUT\n"); + return 0; + } + if (info->len > IP6T_POLICY_MAX_ELEM) { + printk(KERN_ERR "ip6t_policy: too many policy elements\n"); + return 0; + } + + return 1; +} + +static struct ip6t_match policy_match = { + .name = "policy", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ip6t_register_match(&policy_match); +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&policy_match); +} + +module_init(init); +module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index beb2fd5cebbb..8f82476dc89e 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -33,12 +33,12 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); static inline int segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert) { - int r=0; - DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', - min,id,max); - r=(id >= min && id <= max) ^ invert; - DEBUGP(" result %s\n",r? "PASS" : "FAILED"); - return r; + int r = 0; + DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x", + invert ? '!' : ' ', min, id, max); + r = (id >= min && id <= max) ^ invert; + DEBUGP(" result %s\n", r ? "PASS" : "FAILED"); + return r; } static int @@ -50,87 +50,93 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ipv6_rt_hdr _route, *rh; - const struct ip6t_rt *rtinfo = matchinfo; - unsigned int temp; - unsigned int ptr; - unsigned int hdrlen = 0; - unsigned int ret = 0; - struct in6_addr *ap, _addr; - - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) + struct ipv6_rt_hdr _route, *rh; + const struct ip6t_rt *rtinfo = matchinfo; + unsigned int temp; + unsigned int ptr; + unsigned int hdrlen = 0; + unsigned int ret = 0; + struct in6_addr *ap, _addr; + + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0) return 0; - rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); - if (rh == NULL){ - *hotdrop = 1; - return 0; - } - - hdrlen = ipv6_optlen(rh); - if (skb->len - ptr < hdrlen){ - /* Pcket smaller than its length field */ - return 0; - } - - DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); - DEBUGP("TYPE %04X ", rh->type); - DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); - - DEBUGP("IPv6 RT segsleft %02X ", - (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], - rh->segments_left, - !!(rtinfo->invflags & IP6T_RT_INV_SGS)))); - DEBUGP("type %02X %02X %02X ", - rtinfo->rt_type, rh->type, - (!(rtinfo->flags & IP6T_RT_TYP) || - ((rtinfo->rt_type == rh->type) ^ - !!(rtinfo->invflags & IP6T_RT_INV_TYP)))); - DEBUGP("len %02X %04X %02X ", - rtinfo->hdrlen, hdrlen, - (!(rtinfo->flags & IP6T_RT_LEN) || - ((rtinfo->hdrlen == hdrlen) ^ - !!(rtinfo->invflags & IP6T_RT_INV_LEN)))); - DEBUGP("res %02X %02X %02X ", - (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->reserved, - !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->reserved))); - - ret = (rh != NULL) - && - (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], - rh->segments_left, - !!(rtinfo->invflags & IP6T_RT_INV_SGS))) - && - (!(rtinfo->flags & IP6T_RT_LEN) || - ((rtinfo->hdrlen == hdrlen) ^ - !!(rtinfo->invflags & IP6T_RT_INV_LEN))) - && - (!(rtinfo->flags & IP6T_RT_TYP) || - ((rtinfo->rt_type == rh->type) ^ - !!(rtinfo->invflags & IP6T_RT_INV_TYP))); + rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); + if (rh == NULL) { + *hotdrop = 1; + return 0; + } + + hdrlen = ipv6_optlen(rh); + if (skb->len - ptr < hdrlen) { + /* Pcket smaller than its length field */ + return 0; + } + + DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); + DEBUGP("TYPE %04X ", rh->type); + DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); + + DEBUGP("IPv6 RT segsleft %02X ", + (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], + rh->segments_left, + !!(rtinfo->invflags & IP6T_RT_INV_SGS)))); + DEBUGP("type %02X %02X %02X ", + rtinfo->rt_type, rh->type, + (!(rtinfo->flags & IP6T_RT_TYP) || + ((rtinfo->rt_type == rh->type) ^ + !!(rtinfo->invflags & IP6T_RT_INV_TYP)))); + DEBUGP("len %02X %04X %02X ", + rtinfo->hdrlen, hdrlen, + (!(rtinfo->flags & IP6T_RT_LEN) || + ((rtinfo->hdrlen == hdrlen) ^ + !!(rtinfo->invflags & IP6T_RT_INV_LEN)))); + DEBUGP("res %02X %02X %02X ", + (rtinfo->flags & IP6T_RT_RES), + ((struct rt0_hdr *)rh)->reserved, + !((rtinfo->flags & IP6T_RT_RES) && + (((struct rt0_hdr *)rh)->reserved))); + + ret = (rh != NULL) + && + (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], + rh->segments_left, + !!(rtinfo->invflags & IP6T_RT_INV_SGS))) + && + (!(rtinfo->flags & IP6T_RT_LEN) || + ((rtinfo->hdrlen == hdrlen) ^ + !!(rtinfo->invflags & IP6T_RT_INV_LEN))) + && + (!(rtinfo->flags & IP6T_RT_TYP) || + ((rtinfo->rt_type == rh->type) ^ + !!(rtinfo->invflags & IP6T_RT_INV_TYP))); if (ret && (rtinfo->flags & IP6T_RT_RES)) { u_int32_t *rp, _reserved; rp = skb_header_pointer(skb, - ptr + offsetof(struct rt0_hdr, reserved), - sizeof(_reserved), &_reserved); + ptr + offsetof(struct rt0_hdr, + reserved), + sizeof(_reserved), + &_reserved); ret = (*rp == 0); } - DEBUGP("#%d ",rtinfo->addrnr); - if ( !(rtinfo->flags & IP6T_RT_FST) ){ - return ret; + DEBUGP("#%d ", rtinfo->addrnr); + if (!(rtinfo->flags & IP6T_RT_FST)) { + return ret; } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) { DEBUGP("Not strict "); - if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ + if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) { DEBUGP("There isn't enough space\n"); return 0; } else { unsigned int i = 0; - DEBUGP("#%d ",rtinfo->addrnr); - for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){ + DEBUGP("#%d ", rtinfo->addrnr); + for (temp = 0; + temp < (unsigned int)((hdrlen - 8) / 16); + temp++) { ap = skb_header_pointer(skb, ptr + sizeof(struct rt0_hdr) @@ -141,24 +147,26 @@ match(const struct sk_buff *skb, BUG_ON(ap == NULL); if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) { - DEBUGP("i=%d temp=%d;\n",i,temp); + DEBUGP("i=%d temp=%d;\n", i, temp); i++; } - if (i==rtinfo->addrnr) break; + if (i == rtinfo->addrnr) + break; } DEBUGP("i=%d #%d\n", i, rtinfo->addrnr); if (i == rtinfo->addrnr) return ret; - else return 0; + else + return 0; } } else { DEBUGP("Strict "); - if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ + if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) { DEBUGP("There isn't enough space\n"); return 0; } else { - DEBUGP("#%d ",rtinfo->addrnr); - for(temp=0; temp<rtinfo->addrnr; temp++){ + DEBUGP("#%d ", rtinfo->addrnr); + for (temp = 0; temp < rtinfo->addrnr; temp++) { ap = skb_header_pointer(skb, ptr + sizeof(struct rt0_hdr) @@ -171,9 +179,11 @@ match(const struct sk_buff *skb, break; } DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr); - if ((temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) + if ((temp == rtinfo->addrnr) && + (temp == (unsigned int)((hdrlen - 8) / 16))) return ret; - else return 0; + else + return 0; } } @@ -183,32 +193,31 @@ match(const struct sk_buff *skb, /* Called when user tries to insert an entry of this type. */ static int checkentry(const char *tablename, - const struct ip6t_ip6 *ip, - void *matchinfo, - unsigned int matchinfosize, - unsigned int hook_mask) + const void *entry, + void *matchinfo, + unsigned int matchinfosize, + unsigned int hook_mask) { - const struct ip6t_rt *rtinfo = matchinfo; - - if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) { - DEBUGP("ip6t_rt: matchsize %u != %u\n", - matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt))); - return 0; - } - if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { - DEBUGP("ip6t_rt: unknown flags %X\n", - rtinfo->invflags); - return 0; - } - if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) && - (!(rtinfo->flags & IP6T_RT_TYP) || - (rtinfo->rt_type != 0) || - (rtinfo->invflags & IP6T_RT_INV_TYP)) ) { - DEBUGP("`--rt-type 0' required before `--rt-0-*'"); - return 0; - } - - return 1; + const struct ip6t_rt *rtinfo = matchinfo; + + if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) { + DEBUGP("ip6t_rt: matchsize %u != %u\n", + matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt))); + return 0; + } + if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { + DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); + return 0; + } + if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) && + (!(rtinfo->flags & IP6T_RT_TYP) || + (rtinfo->rt_type != 0) || + (rtinfo->invflags & IP6T_RT_INV_TYP))) { + DEBUGP("`--rt-type 0' required before `--rt-0-*'"); + return 0; + } + + return 1; } static struct ip6t_match rt_match = { @@ -220,12 +229,12 @@ static struct ip6t_match rt_match = { static int __init init(void) { - return ip6t_register_match(&rt_match); + return ip6t_register_match(&rt_match); } static void __exit cleanup(void) { - ip6t_unregister_match(&rt_match); + ip6t_unregister_match(&rt_match); } module_init(init); diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 4c0028671c20..ce4a968e1f70 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -97,6 +97,7 @@ static struct ip6t_table packet_filter = { .valid_hooks = FILTER_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, .me = THIS_MODULE, + .af = AF_INET6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 85c1e6eada19..30a4627e000d 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -127,6 +127,7 @@ static struct ip6t_table packet_mangler = { .valid_hooks = MANGLE_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, .me = THIS_MODULE, + .af = AF_INET6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index c2982efd14af..db28ba3855e2 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -106,11 +106,12 @@ static struct } }; -static struct ip6t_table packet_raw = { +static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, - .me = THIS_MODULE + .me = THIS_MODULE, + .af = AF_INET6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 753a3ae8502b..ac702a29dd16 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -74,7 +74,7 @@ static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, static int ipv6_print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple) { - return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ", + return seq_printf(s, "src=" NIP6_FMT " dst=" NIP6_FMT " ", NIP6(*((struct in6_addr *)tuple->src.u3.ip6)), NIP6(*((struct in6_addr *)tuple->dst.u3.ip6))); } @@ -335,10 +335,10 @@ static struct nf_hook_ops ipv6_conntrack_local_in_ops = { #ifdef CONFIG_SYSCTL /* From nf_conntrack_proto_icmpv6.c */ -extern unsigned long nf_ct_icmpv6_timeout; +extern unsigned int nf_ct_icmpv6_timeout; /* From nf_conntrack_frag6.c */ -extern unsigned long nf_ct_frag6_timeout; +extern unsigned int nf_ct_frag6_timeout; extern unsigned int nf_ct_frag6_low_thresh; extern unsigned int nf_ct_frag6_high_thresh; @@ -401,6 +401,48 @@ static ctl_table nf_ct_net_table[] = { }; #endif +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nfnetlink_conntrack.h> + +static int ipv6_tuple_to_nfattr(struct sk_buff *skb, + const struct nf_conntrack_tuple *tuple) +{ + NFA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, + &tuple->src.u3.ip6); + NFA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4, + &tuple->dst.u3.ip6); + return 0; + +nfattr_failure: + return -1; +} + +static const size_t cta_min_ip[CTA_IP_MAX] = { + [CTA_IP_V6_SRC-1] = sizeof(u_int32_t)*4, + [CTA_IP_V6_DST-1] = sizeof(u_int32_t)*4, +}; + +static int ipv6_nfattr_to_tuple(struct nfattr *tb[], + struct nf_conntrack_tuple *t) +{ + if (!tb[CTA_IP_V6_SRC-1] || !tb[CTA_IP_V6_DST-1]) + return -EINVAL; + + if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) + return -EINVAL; + + memcpy(&t->src.u3.ip6, NFA_DATA(tb[CTA_IP_V6_SRC-1]), + sizeof(u_int32_t) * 4); + memcpy(&t->dst.u3.ip6, NFA_DATA(tb[CTA_IP_V6_DST-1]), + sizeof(u_int32_t) * 4); + + return 0; +} +#endif + struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { .l3proto = PF_INET6, .name = "ipv6", @@ -409,6 +451,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { .print_tuple = ipv6_print_tuple, .print_conntrack = ipv6_print_conntrack, .prepare = ipv6_prepare, +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + .tuple_to_nfattr = ipv6_tuple_to_nfattr, + .nfattr_to_tuple = ipv6_nfattr_to_tuple, +#endif .get_features = ipv6_get_features, .me = THIS_MODULE, }; @@ -537,7 +584,7 @@ MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); static int __init init(void) { - need_nf_conntrack(); + need_conntrack(); return init_or_cleanup(1); } @@ -548,9 +595,3 @@ static void __exit fini(void) module_init(init); module_exit(fini); - -void need_ip6_conntrack(void) -{ -} - -EXPORT_SYMBOL(need_ip6_conntrack); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index a7e03cfacd06..09945c333055 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -57,17 +57,17 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb, return 1; } +/* Add 1; spaces filled with 0. */ +static u_int8_t invmap[] = { + [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, + [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, + [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, + [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 +}; + static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *orig) { - /* Add 1; spaces filled with 0. */ - static u_int8_t invmap[] = { - [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, - [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, - [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, - [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 - }; - int type = orig->dst.u.icmp.type - 128; if (type < 0 || type >= sizeof(invmap) || !invmap[type]) return 0; @@ -185,7 +185,7 @@ icmpv6_error_message(struct sk_buff *skb, return -NF_ACCEPT; } - inproto = nf_ct_find_proto(PF_INET6, inprotonum); + inproto = __nf_ct_proto_find(PF_INET6, inprotonum); /* Are they talking about one of our connections? */ if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, @@ -255,6 +255,60 @@ skipped: return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); } +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nfnetlink_conntrack.h> +static int icmpv6_tuple_to_nfattr(struct sk_buff *skb, + const struct nf_conntrack_tuple *t) +{ + NFA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t), + &t->src.u.icmp.id); + NFA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t), + &t->dst.u.icmp.type); + NFA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t), + &t->dst.u.icmp.code); + + return 0; + +nfattr_failure: + return -1; +} + +static const size_t cta_min_proto[CTA_PROTO_MAX] = { + [CTA_PROTO_ICMPV6_TYPE-1] = sizeof(u_int8_t), + [CTA_PROTO_ICMPV6_CODE-1] = sizeof(u_int8_t), + [CTA_PROTO_ICMPV6_ID-1] = sizeof(u_int16_t) +}; + +static int icmpv6_nfattr_to_tuple(struct nfattr *tb[], + struct nf_conntrack_tuple *tuple) +{ + if (!tb[CTA_PROTO_ICMPV6_TYPE-1] + || !tb[CTA_PROTO_ICMPV6_CODE-1] + || !tb[CTA_PROTO_ICMPV6_ID-1]) + return -EINVAL; + + if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) + return -EINVAL; + + tuple->dst.u.icmp.type = + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]); + tuple->dst.u.icmp.code = + *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]); + tuple->src.u.icmp.id = + *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]); + + if (tuple->dst.u.icmp.type < 128 + || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) + || !invmap[tuple->dst.u.icmp.type - 128]) + return -EINVAL; + + return 0; +} +#endif + struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = { .l3proto = PF_INET6, @@ -267,6 +321,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = .packet = icmpv6_packet, .new = icmpv6_new, .error = icmpv6_error, +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + .tuple_to_nfattr = icmpv6_tuple_to_nfattr, + .nfattr_to_tuple = icmpv6_nfattr_to_tuple, +#endif }; EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index c2c52af9e560..84ef9a13108d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -70,8 +70,8 @@ struct nf_ct_frag6_skb_cb struct nf_ct_frag6_queue { - struct nf_ct_frag6_queue *next; - struct list_head lru_list; /* lru list member */ + struct hlist_node list; + struct list_head lru_list; /* lru list member */ __u32 id; /* fragment id */ struct in6_addr saddr; @@ -90,24 +90,21 @@ struct nf_ct_frag6_queue #define FIRST_IN 2 #define LAST_IN 1 __u16 nhoffset; - struct nf_ct_frag6_queue **pprev; }; /* Hash table. */ #define FRAG6Q_HASHSZ 64 -static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ]; -static rwlock_t nf_ct_frag6_lock = RW_LOCK_UNLOCKED; +static struct hlist_head nf_ct_frag6_hash[FRAG6Q_HASHSZ]; +static DEFINE_RWLOCK(nf_ct_frag6_lock); static u32 nf_ct_frag6_hash_rnd; static LIST_HEAD(nf_ct_frag6_lru_list); int nf_ct_frag6_nqueues = 0; static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq) { - if (fq->next) - fq->next->pprev = fq->pprev; - *fq->pprev = fq->next; + hlist_del(&fq->list); list_del(&fq->lru_list); nf_ct_frag6_nqueues--; } @@ -158,28 +155,18 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy) get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32)); for (i = 0; i < FRAG6Q_HASHSZ; i++) { struct nf_ct_frag6_queue *q; + struct hlist_node *p, *n; - q = nf_ct_frag6_hash[i]; - while (q) { - struct nf_ct_frag6_queue *next = q->next; + hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], list) { unsigned int hval = ip6qhashfn(q->id, &q->saddr, &q->daddr); - if (hval != i) { - /* Unlink. */ - if (q->next) - q->next->pprev = q->pprev; - *q->pprev = q->next; - + hlist_del(&q->list); /* Relink to new hash chain. */ - if ((q->next = nf_ct_frag6_hash[hval]) != NULL) - q->next->pprev = &q->next; - nf_ct_frag6_hash[hval] = q; - q->pprev = &nf_ct_frag6_hash[hval]; + hlist_add_head(&q->list, + &nf_ct_frag6_hash[hval]); } - - q = next; } } write_unlock(&nf_ct_frag6_lock); @@ -314,15 +301,17 @@ out: /* Creation primitives. */ - static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, struct nf_ct_frag6_queue *fq_in) { struct nf_ct_frag6_queue *fq; +#ifdef CONFIG_SMP + struct hlist_node *n; +#endif write_lock(&nf_ct_frag6_lock); #ifdef CONFIG_SMP - for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) { + hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { if (fq->id == fq_in->id && !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) && !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) { @@ -340,10 +329,7 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, atomic_inc(&fq->refcnt); atomic_inc(&fq->refcnt); - if ((fq->next = nf_ct_frag6_hash[hash]) != NULL) - fq->next->pprev = &fq->next; - nf_ct_frag6_hash[hash] = fq; - fq->pprev = &nf_ct_frag6_hash[hash]; + hlist_add_head(&fq->list, &nf_ct_frag6_hash[hash]); INIT_LIST_HEAD(&fq->lru_list); list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list); nf_ct_frag6_nqueues++; @@ -371,7 +357,7 @@ nf_ct_frag6_create(unsigned int hash, u32 id, struct in6_addr *src, struct init_timer(&fq->timer); fq->timer.function = nf_ct_frag6_expire; fq->timer.data = (long) fq; - fq->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&fq->lock); atomic_set(&fq->refcnt, 1); return nf_ct_frag6_intern(hash, fq); @@ -384,10 +370,11 @@ static __inline__ struct nf_ct_frag6_queue * fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) { struct nf_ct_frag6_queue *fq; + struct hlist_node *n; unsigned int hash = ip6qhashfn(id, src, dst); read_lock(&nf_ct_frag6_lock); - for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) { + hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { if (fq->id == id && !ipv6_addr_cmp(src, &fq->saddr) && !ipv6_addr_cmp(dst, &fq->daddr)) { |