2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
16 * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
17 * - Unification of {ip,ip6}_tables into x_tables
18 * - Removed tcp and udp code, since it's not ipv6 specific
21 #include <linux/capability.h>
23 #include <linux/skbuff.h>
24 #include <linux/kmod.h>
25 #include <linux/vmalloc.h>
26 #include <linux/netdevice.h>
27 #include <linux/module.h>
28 #include <linux/poison.h>
29 #include <linux/icmpv6.h>
31 #include <asm/uaccess.h>
32 #include <linux/mutex.h>
33 #include <linux/proc_fs.h>
34 #include <linux/cpumask.h>
36 #include <linux/netfilter_ipv6/ip6_tables.h>
37 #include <linux/netfilter/x_tables.h>
39 MODULE_LICENSE("GPL");
40 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
41 MODULE_DESCRIPTION("IPv6 packet filter");
43 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
44 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
46 /*#define DEBUG_IP_FIREWALL*/
47 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
48 /*#define DEBUG_IP_FIREWALL_USER*/
50 #ifdef DEBUG_IP_FIREWALL
51 #define dprintf(format, args...) printk(format , ## args)
53 #define dprintf(format, args...)
56 #ifdef DEBUG_IP_FIREWALL_USER
57 #define duprintf(format, args...) printk(format , ## args)
59 #define duprintf(format, args...)
62 #ifdef CONFIG_NETFILTER_DEBUG
63 #define IP_NF_ASSERT(x) \
66 printk("IP_NF_ASSERT: %s:%s:%u\n", \
67 __FUNCTION__, __FILE__, __LINE__); \
70 #define IP_NF_ASSERT(x)
74 /* All the better to debug you with... */
80 We keep a set of rules for each CPU, so we can avoid write-locking
81 them in the softirq when updating the counters and therefore
82 only need to read-lock in the softirq; doing a write_lock_bh() in user
83 context stops packets coming through and allows user context to read
84 the counters or update the rules.
86 Hence the start of any table is given by get_table() below. */
89 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
90 #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; })
91 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
94 /* Check for an extension */
96 ip6t_ext_hdr(u8 nexthdr)
98 return ( (nexthdr == IPPROTO_HOPOPTS) ||
99 (nexthdr == IPPROTO_ROUTING) ||
100 (nexthdr == IPPROTO_FRAGMENT) ||
101 (nexthdr == IPPROTO_ESP) ||
102 (nexthdr == IPPROTO_AH) ||
103 (nexthdr == IPPROTO_NONE) ||
104 (nexthdr == IPPROTO_DSTOPTS) );
107 /* Returns whether matches rule or not. */
109 ip6_packet_match(const struct sk_buff *skb,
112 const struct ip6t_ip6 *ip6info,
113 unsigned int *protoff,
114 int *fragoff, int *hotdrop)
118 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
120 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
122 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
123 &ip6info->src), IP6T_INV_SRCIP)
124 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
125 &ip6info->dst), IP6T_INV_DSTIP)) {
126 dprintf("Source or dest mismatch.\n");
128 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
129 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
130 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
131 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
132 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
133 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
137 /* Look for ifname matches; this should unroll nicely. */
138 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
139 ret |= (((const unsigned long *)indev)[i]
140 ^ ((const unsigned long *)ip6info->iniface)[i])
141 & ((const unsigned long *)ip6info->iniface_mask)[i];
144 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
145 dprintf("VIA in mismatch (%s vs %s).%s\n",
146 indev, ip6info->iniface,
147 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
151 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
152 ret |= (((const unsigned long *)outdev)[i]
153 ^ ((const unsigned long *)ip6info->outiface)[i])
154 & ((const unsigned long *)ip6info->outiface_mask)[i];
157 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
158 dprintf("VIA out mismatch (%s vs %s).%s\n",
159 outdev, ip6info->outiface,
160 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
164 /* ... might want to do something with class and flowlabel here ... */
166 /* look for the desired protocol header */
167 if((ip6info->flags & IP6T_F_PROTO)) {
169 unsigned short _frag_off;
171 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
177 *fragoff = _frag_off;
179 dprintf("Packet protocol %hi ?= %s%hi.\n",
181 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
184 if (ip6info->proto == protohdr) {
185 if(ip6info->invflags & IP6T_INV_PROTO) {
191 /* We need match for the '-p all', too! */
192 if ((ip6info->proto != 0) &&
193 !(ip6info->invflags & IP6T_INV_PROTO))
199 /* should be ip6 safe */
201 ip6_checkentry(const struct ip6t_ip6 *ipv6)
203 if (ipv6->flags & ~IP6T_F_MASK) {
204 duprintf("Unknown flag bits set: %08X\n",
205 ipv6->flags & ~IP6T_F_MASK);
208 if (ipv6->invflags & ~IP6T_INV_MASK) {
209 duprintf("Unknown invflag bits set: %08X\n",
210 ipv6->invflags & ~IP6T_INV_MASK);
217 ip6t_error(struct sk_buff **pskb,
218 const struct net_device *in,
219 const struct net_device *out,
220 unsigned int hooknum,
221 const struct xt_target *target,
222 const void *targinfo)
225 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
231 int do_match(struct ip6t_entry_match *m,
232 const struct sk_buff *skb,
233 const struct net_device *in,
234 const struct net_device *out,
236 unsigned int protoff,
239 /* Stop iteration if it doesn't match */
240 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
241 offset, protoff, hotdrop))
247 static inline struct ip6t_entry *
248 get_entry(void *base, unsigned int offset)
250 return (struct ip6t_entry *)(base + offset);
253 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
255 ip6t_do_table(struct sk_buff **pskb,
257 const struct net_device *in,
258 const struct net_device *out,
259 struct xt_table *table)
261 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
263 unsigned int protoff = 0;
265 /* Initializing verdict to NF_DROP keeps gcc happy. */
266 unsigned int verdict = NF_DROP;
267 const char *indev, *outdev;
269 struct ip6t_entry *e, *back;
270 struct xt_table_info *private;
273 indev = in ? in->name : nulldevname;
274 outdev = out ? out->name : nulldevname;
275 /* We handle fragments by dealing with the first fragment as
276 * if it was a normal packet. All other fragments are treated
277 * normally, except that they will NEVER match rules that ask
278 * things we don't know, ie. tcp syn flag or ports). If the
279 * rule is also a fragment-specific rule, non-fragments won't
282 read_lock_bh(&table->lock);
283 private = table->private;
284 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
285 table_base = (void *)private->entries[smp_processor_id()];
286 e = get_entry(table_base, private->hook_entry[hook]);
288 /* For return from builtin chain */
289 back = get_entry(table_base, private->underflow[hook]);
294 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
295 &protoff, &offset, &hotdrop)) {
296 struct ip6t_entry_target *t;
298 if (IP6T_MATCH_ITERATE(e, do_match,
300 offset, protoff, &hotdrop) != 0)
303 ADD_COUNTER(e->counters,
304 ntohs((*pskb)->nh.ipv6h->payload_len)
308 t = ip6t_get_target(e);
309 IP_NF_ASSERT(t->u.kernel.target);
310 /* Standard target? */
311 if (!t->u.kernel.target->target) {
314 v = ((struct ip6t_standard_target *)t)->verdict;
316 /* Pop from stack? */
317 if (v != IP6T_RETURN) {
318 verdict = (unsigned)(-v) - 1;
322 back = get_entry(table_base,
326 if (table_base + v != (void *)e + e->next_offset
327 && !(e->ipv6.flags & IP6T_F_GOTO)) {
328 /* Save old back ptr in next entry */
329 struct ip6t_entry *next
330 = (void *)e + e->next_offset;
332 = (void *)back - table_base;
333 /* set back pointer to next entry */
337 e = get_entry(table_base, v);
339 /* Targets which reenter must return
341 #ifdef CONFIG_NETFILTER_DEBUG
342 ((struct ip6t_entry *)table_base)->comefrom
345 verdict = t->u.kernel.target->target(pskb,
351 #ifdef CONFIG_NETFILTER_DEBUG
352 if (((struct ip6t_entry *)table_base)->comefrom
354 && verdict == IP6T_CONTINUE) {
355 printk("Target %s reentered!\n",
356 t->u.kernel.target->name);
359 ((struct ip6t_entry *)table_base)->comefrom
362 if (verdict == IP6T_CONTINUE)
363 e = (void *)e + e->next_offset;
371 e = (void *)e + e->next_offset;
375 #ifdef CONFIG_NETFILTER_DEBUG
376 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
378 read_unlock_bh(&table->lock);
380 #ifdef DEBUG_ALLOW_ALL
389 /* All zeroes == unconditional rule. */
391 unconditional(const struct ip6t_ip6 *ipv6)
395 for (i = 0; i < sizeof(*ipv6); i++)
396 if (((char *)ipv6)[i])
399 return (i == sizeof(*ipv6));
402 /* Figures out from what hook each rule can be called: returns 0 if
403 there are loops. Puts hook bitmask in comefrom. */
405 mark_source_chains(struct xt_table_info *newinfo,
406 unsigned int valid_hooks, void *entry0)
410 /* No recursion; use packet counter to save back ptrs (reset
411 to 0 as we leave), and comefrom to save source hook bitmask */
412 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
413 unsigned int pos = newinfo->hook_entry[hook];
415 = (struct ip6t_entry *)(entry0 + pos);
417 if (!(valid_hooks & (1 << hook)))
420 /* Set initial back pointer. */
421 e->counters.pcnt = pos;
424 struct ip6t_standard_target *t
425 = (void *)ip6t_get_target(e);
427 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
428 printk("iptables: loop hook %u pos %u %08X.\n",
429 hook, pos, e->comefrom);
433 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
435 /* Unconditional return/END. */
436 if (e->target_offset == sizeof(struct ip6t_entry)
437 && (strcmp(t->target.u.user.name,
438 IP6T_STANDARD_TARGET) == 0)
440 && unconditional(&e->ipv6)) {
441 unsigned int oldpos, size;
443 if (t->verdict < -NF_MAX_VERDICT - 1) {
444 duprintf("mark_source_chains: bad "
445 "negative verdict (%i)\n",
450 /* Return: backtrack through the last
453 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
454 #ifdef DEBUG_IP_FIREWALL_USER
456 & (1 << NF_IP6_NUMHOOKS)) {
457 duprintf("Back unset "
464 pos = e->counters.pcnt;
465 e->counters.pcnt = 0;
467 /* We're at the start. */
471 e = (struct ip6t_entry *)
473 } while (oldpos == pos + e->next_offset);
476 size = e->next_offset;
477 e = (struct ip6t_entry *)
478 (entry0 + pos + size);
479 e->counters.pcnt = pos;
482 int newpos = t->verdict;
484 if (strcmp(t->target.u.user.name,
485 IP6T_STANDARD_TARGET) == 0
487 if (newpos > newinfo->size -
488 sizeof(struct ip6t_entry)) {
489 duprintf("mark_source_chains: "
490 "bad verdict (%i)\n",
494 /* This a jump; chase it. */
495 duprintf("Jump rule %u -> %u\n",
498 /* ... this is a fallthru */
499 newpos = pos + e->next_offset;
501 e = (struct ip6t_entry *)
503 e->counters.pcnt = pos;
508 duprintf("Finished chain %u\n", hook);
514 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
516 if (i && (*i)-- == 0)
519 if (m->u.kernel.match->destroy)
520 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
521 module_put(m->u.kernel.match->me);
526 check_match(struct ip6t_entry_match *m,
528 const struct ip6t_ip6 *ipv6,
529 unsigned int hookmask,
532 struct ip6t_match *match;
535 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
537 "ip6t_%s", m->u.user.name);
538 if (IS_ERR(match) || !match) {
539 duprintf("check_match: `%s' not found\n", m->u.user.name);
540 return match ? PTR_ERR(match) : -ENOENT;
542 m->u.kernel.match = match;
544 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
545 name, hookmask, ipv6->proto,
546 ipv6->invflags & IP6T_INV_PROTO);
550 if (m->u.kernel.match->checkentry
551 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
553 duprintf("ip_tables: check failed for `%s'.\n",
554 m->u.kernel.match->name);
562 module_put(m->u.kernel.match->me);
566 static struct ip6t_target ip6t_standard_target;
569 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
572 struct ip6t_entry_target *t;
573 struct ip6t_target *target;
577 if (!ip6_checkentry(&e->ipv6)) {
578 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
582 if (e->target_offset + sizeof(struct ip6t_entry_target) >
587 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
589 goto cleanup_matches;
591 t = ip6t_get_target(e);
593 if (e->target_offset + t->u.target_size > e->next_offset)
594 goto cleanup_matches;
595 target = try_then_request_module(xt_find_target(AF_INET6,
598 "ip6t_%s", t->u.user.name);
599 if (IS_ERR(target) || !target) {
600 duprintf("check_entry: `%s' not found\n", t->u.user.name);
601 ret = target ? PTR_ERR(target) : -ENOENT;
602 goto cleanup_matches;
604 t->u.kernel.target = target;
606 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
607 name, e->comefrom, e->ipv6.proto,
608 e->ipv6.invflags & IP6T_INV_PROTO);
612 if (t->u.kernel.target->checkentry
613 && !t->u.kernel.target->checkentry(name, e, target, t->data,
615 duprintf("ip_tables: check failed for `%s'.\n",
616 t->u.kernel.target->name);
624 module_put(t->u.kernel.target->me);
626 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
631 check_entry_size_and_hooks(struct ip6t_entry *e,
632 struct xt_table_info *newinfo,
634 unsigned char *limit,
635 const unsigned int *hook_entries,
636 const unsigned int *underflows,
641 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
642 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
643 duprintf("Bad offset %p\n", e);
648 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
649 duprintf("checking: element %p size %u\n",
654 /* Check hooks & underflows */
655 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
656 if ((unsigned char *)e - base == hook_entries[h])
657 newinfo->hook_entry[h] = hook_entries[h];
658 if ((unsigned char *)e - base == underflows[h])
659 newinfo->underflow[h] = underflows[h];
662 /* FIXME: underflows must be unconditional, standard verdicts
663 < 0 (not IP6T_RETURN). --RR */
665 /* Clear counters and comefrom */
666 e->counters = ((struct xt_counters) { 0, 0 });
674 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
676 struct ip6t_entry_target *t;
678 if (i && (*i)-- == 0)
681 /* Cleanup all matches */
682 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
683 t = ip6t_get_target(e);
684 if (t->u.kernel.target->destroy)
685 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
686 module_put(t->u.kernel.target->me);
690 /* Checks and translates the user-supplied table segment (held in
693 translate_table(const char *name,
694 unsigned int valid_hooks,
695 struct xt_table_info *newinfo,
699 const unsigned int *hook_entries,
700 const unsigned int *underflows)
705 newinfo->size = size;
706 newinfo->number = number;
708 /* Init all hooks to impossible value. */
709 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
710 newinfo->hook_entry[i] = 0xFFFFFFFF;
711 newinfo->underflow[i] = 0xFFFFFFFF;
714 duprintf("translate_table: size %u\n", newinfo->size);
716 /* Walk through entries, checking offsets. */
717 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
718 check_entry_size_and_hooks,
722 hook_entries, underflows, &i);
727 duprintf("translate_table: %u not %u entries\n",
732 /* Check hooks all assigned */
733 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
734 /* Only hooks which are valid */
735 if (!(valid_hooks & (1 << i)))
737 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
738 duprintf("Invalid hook entry %u %u\n",
742 if (newinfo->underflow[i] == 0xFFFFFFFF) {
743 duprintf("Invalid underflow %u %u\n",
749 if (!mark_source_chains(newinfo, valid_hooks, entry0))
752 /* Finally, each sanity check must pass */
754 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
755 check_entry, name, size, &i);
758 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
763 /* And one copy for every other CPU */
764 for_each_possible_cpu(i) {
765 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
766 memcpy(newinfo->entries[i], entry0, newinfo->size);
774 add_entry_to_counter(const struct ip6t_entry *e,
775 struct xt_counters total[],
778 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
785 set_entry_to_counter(const struct ip6t_entry *e,
786 struct ip6t_counters total[],
789 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
796 get_counters(const struct xt_table_info *t,
797 struct xt_counters counters[])
803 /* Instead of clearing (by a previous call to memset())
804 * the counters and using adds, we set the counters
805 * with data used by 'current' CPU
806 * We dont care about preemption here.
808 curcpu = raw_smp_processor_id();
811 IP6T_ENTRY_ITERATE(t->entries[curcpu],
813 set_entry_to_counter,
817 for_each_possible_cpu(cpu) {
821 IP6T_ENTRY_ITERATE(t->entries[cpu],
823 add_entry_to_counter,
830 copy_entries_to_user(unsigned int total_size,
831 struct xt_table *table,
832 void __user *userptr)
834 unsigned int off, num, countersize;
835 struct ip6t_entry *e;
836 struct xt_counters *counters;
837 struct xt_table_info *private = table->private;
841 /* We need atomic snapshot of counters: rest doesn't change
842 (other than comefrom, which userspace doesn't care
844 countersize = sizeof(struct xt_counters) * private->number;
845 counters = vmalloc(countersize);
847 if (counters == NULL)
850 /* First, sum counters... */
851 write_lock_bh(&table->lock);
852 get_counters(private, counters);
853 write_unlock_bh(&table->lock);
855 /* choose the copy that is on ourc node/cpu */
856 loc_cpu_entry = private->entries[raw_smp_processor_id()];
857 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
862 /* FIXME: use iterator macros --RR */
863 /* ... then go back and fix counters and names */
864 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
866 struct ip6t_entry_match *m;
867 struct ip6t_entry_target *t;
869 e = (struct ip6t_entry *)(loc_cpu_entry + off);
870 if (copy_to_user(userptr + off
871 + offsetof(struct ip6t_entry, counters),
873 sizeof(counters[num])) != 0) {
878 for (i = sizeof(struct ip6t_entry);
879 i < e->target_offset;
880 i += m->u.match_size) {
883 if (copy_to_user(userptr + off + i
884 + offsetof(struct ip6t_entry_match,
886 m->u.kernel.match->name,
887 strlen(m->u.kernel.match->name)+1)
894 t = ip6t_get_target(e);
895 if (copy_to_user(userptr + off + e->target_offset
896 + offsetof(struct ip6t_entry_target,
898 t->u.kernel.target->name,
899 strlen(t->u.kernel.target->name)+1) != 0) {
911 get_entries(const struct ip6t_get_entries *entries,
912 struct ip6t_get_entries __user *uptr)
917 t = xt_find_table_lock(AF_INET6, entries->name);
918 if (t && !IS_ERR(t)) {
919 struct xt_table_info *private = t->private;
920 duprintf("t->private->number = %u\n", private->number);
921 if (entries->size == private->size)
922 ret = copy_entries_to_user(private->size,
923 t, uptr->entrytable);
925 duprintf("get_entries: I've got %u not %u!\n",
926 private->size, entries->size);
932 ret = t ? PTR_ERR(t) : -ENOENT;
938 do_replace(void __user *user, unsigned int len)
941 struct ip6t_replace tmp;
943 struct xt_table_info *newinfo, *oldinfo;
944 struct xt_counters *counters;
945 void *loc_cpu_entry, *loc_cpu_old_entry;
947 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
951 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
954 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
957 newinfo = xt_alloc_table_info(tmp.size);
961 /* choose the copy that is on our node/cpu */
962 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
963 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
969 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
975 ret = translate_table(tmp.name, tmp.valid_hooks,
976 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
977 tmp.hook_entry, tmp.underflow);
979 goto free_newinfo_counters;
981 duprintf("ip_tables: Translated table\n");
983 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
984 "ip6table_%s", tmp.name);
985 if (!t || IS_ERR(t)) {
986 ret = t ? PTR_ERR(t) : -ENOENT;
987 goto free_newinfo_counters_untrans;
991 if (tmp.valid_hooks != t->valid_hooks) {
992 duprintf("Valid hook crap: %08X vs %08X\n",
993 tmp.valid_hooks, t->valid_hooks);
998 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1002 /* Update module usage count based on number of rules */
1003 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1004 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1005 if ((oldinfo->number > oldinfo->initial_entries) ||
1006 (newinfo->number <= oldinfo->initial_entries))
1008 if ((oldinfo->number > oldinfo->initial_entries) &&
1009 (newinfo->number <= oldinfo->initial_entries))
1012 /* Get the old counters. */
1013 get_counters(oldinfo, counters);
1014 /* Decrease module usage counts and free resource */
1015 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1016 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1017 xt_free_table_info(oldinfo);
1018 if (copy_to_user(tmp.counters, counters,
1019 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1028 free_newinfo_counters_untrans:
1029 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1030 free_newinfo_counters:
1033 xt_free_table_info(newinfo);
1037 /* We're lazy, and add to the first CPU; overflow works its fey magic
1038 * and everything is OK. */
1040 add_counter_to_entry(struct ip6t_entry *e,
1041 const struct xt_counters addme[],
1045 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1047 (long unsigned int)e->counters.pcnt,
1048 (long unsigned int)e->counters.bcnt,
1049 (long unsigned int)addme[*i].pcnt,
1050 (long unsigned int)addme[*i].bcnt);
1053 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1060 do_add_counters(void __user *user, unsigned int len)
1063 struct xt_counters_info tmp, *paddc;
1064 struct xt_table_info *private;
1067 void *loc_cpu_entry;
1069 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1072 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1075 paddc = vmalloc(len);
1079 if (copy_from_user(paddc, user, len) != 0) {
1084 t = xt_find_table_lock(AF_INET6, tmp.name);
1085 if (!t || IS_ERR(t)) {
1086 ret = t ? PTR_ERR(t) : -ENOENT;
1090 write_lock_bh(&t->lock);
1091 private = t->private;
1092 if (private->number != tmp.num_counters) {
1094 goto unlock_up_free;
1098 /* Choose the copy that is on our node */
1099 loc_cpu_entry = private->entries[smp_processor_id()];
1100 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1102 add_counter_to_entry,
1106 write_unlock_bh(&t->lock);
1116 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1120 if (!capable(CAP_NET_ADMIN))
1124 case IP6T_SO_SET_REPLACE:
1125 ret = do_replace(user, len);
1128 case IP6T_SO_SET_ADD_COUNTERS:
1129 ret = do_add_counters(user, len);
1133 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1141 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1145 if (!capable(CAP_NET_ADMIN))
1149 case IP6T_SO_GET_INFO: {
1150 char name[IP6T_TABLE_MAXNAMELEN];
1153 if (*len != sizeof(struct ip6t_getinfo)) {
1154 duprintf("length %u != %u\n", *len,
1155 sizeof(struct ip6t_getinfo));
1160 if (copy_from_user(name, user, sizeof(name)) != 0) {
1164 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1166 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1167 "ip6table_%s", name);
1168 if (t && !IS_ERR(t)) {
1169 struct ip6t_getinfo info;
1170 struct xt_table_info *private = t->private;
1172 info.valid_hooks = t->valid_hooks;
1173 memcpy(info.hook_entry, private->hook_entry,
1174 sizeof(info.hook_entry));
1175 memcpy(info.underflow, private->underflow,
1176 sizeof(info.underflow));
1177 info.num_entries = private->number;
1178 info.size = private->size;
1179 memcpy(info.name, name, sizeof(info.name));
1181 if (copy_to_user(user, &info, *len) != 0)
1188 ret = t ? PTR_ERR(t) : -ENOENT;
1192 case IP6T_SO_GET_ENTRIES: {
1193 struct ip6t_get_entries get;
1195 if (*len < sizeof(get)) {
1196 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1198 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1200 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1201 duprintf("get_entries: %u != %u\n", *len,
1202 sizeof(struct ip6t_get_entries) + get.size);
1205 ret = get_entries(&get, user);
1209 case IP6T_SO_GET_REVISION_MATCH:
1210 case IP6T_SO_GET_REVISION_TARGET: {
1211 struct ip6t_get_revision rev;
1214 if (*len != sizeof(rev)) {
1218 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1223 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1228 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1231 "ip6t_%s", rev.name);
1236 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1243 int ip6t_register_table(struct xt_table *table,
1244 const struct ip6t_replace *repl)
1247 struct xt_table_info *newinfo;
1248 static struct xt_table_info bootstrap
1249 = { 0, 0, 0, { 0 }, { 0 }, { } };
1250 void *loc_cpu_entry;
1252 newinfo = xt_alloc_table_info(repl->size);
1256 /* choose the copy on our node/cpu */
1257 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1258 memcpy(loc_cpu_entry, repl->entries, repl->size);
1260 ret = translate_table(table->name, table->valid_hooks,
1261 newinfo, loc_cpu_entry, repl->size,
1266 xt_free_table_info(newinfo);
1270 ret = xt_register_table(table, &bootstrap, newinfo);
1272 xt_free_table_info(newinfo);
1279 void ip6t_unregister_table(struct xt_table *table)
1281 struct xt_table_info *private;
1282 void *loc_cpu_entry;
1284 private = xt_unregister_table(table);
1286 /* Decrease module usage counts and free resources */
1287 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1288 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1289 xt_free_table_info(private);
1292 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1294 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1295 u_int8_t type, u_int8_t code,
1298 return (type == test_type && code >= min_code && code <= max_code)
1303 icmp6_match(const struct sk_buff *skb,
1304 const struct net_device *in,
1305 const struct net_device *out,
1306 const struct xt_match *match,
1307 const void *matchinfo,
1309 unsigned int protoff,
1312 struct icmp6hdr _icmp, *ic;
1313 const struct ip6t_icmp *icmpinfo = matchinfo;
1315 /* Must not be a fragment. */
1319 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1321 /* We've been asked to examine this packet, and we
1322 can't. Hence, no choice but to drop. */
1323 duprintf("Dropping evil ICMP tinygram.\n");
1328 return icmp6_type_code_match(icmpinfo->type,
1331 ic->icmp6_type, ic->icmp6_code,
1332 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1335 /* Called when user tries to insert an entry of this type. */
1337 icmp6_checkentry(const char *tablename,
1339 const struct xt_match *match,
1341 unsigned int hook_mask)
1343 const struct ip6t_icmp *icmpinfo = matchinfo;
1345 /* Must specify no unknown invflags */
1346 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1349 /* The built-in targets: standard (NULL) and error. */
1350 static struct ip6t_target ip6t_standard_target = {
1351 .name = IP6T_STANDARD_TARGET,
1352 .targetsize = sizeof(int),
1356 static struct ip6t_target ip6t_error_target = {
1357 .name = IP6T_ERROR_TARGET,
1358 .target = ip6t_error,
1359 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1363 static struct nf_sockopt_ops ip6t_sockopts = {
1365 .set_optmin = IP6T_BASE_CTL,
1366 .set_optmax = IP6T_SO_SET_MAX+1,
1367 .set = do_ip6t_set_ctl,
1368 .get_optmin = IP6T_BASE_CTL,
1369 .get_optmax = IP6T_SO_GET_MAX+1,
1370 .get = do_ip6t_get_ctl,
1373 static struct ip6t_match icmp6_matchstruct = {
1375 .match = &icmp6_match,
1376 .matchsize = sizeof(struct ip6t_icmp),
1377 .checkentry = icmp6_checkentry,
1378 .proto = IPPROTO_ICMPV6,
1382 static int __init ip6_tables_init(void)
1386 ret = xt_proto_init(AF_INET6);
1390 /* Noone else will be downing sem now, so we won't sleep */
1391 ret = xt_register_target(&ip6t_standard_target);
1394 ret = xt_register_target(&ip6t_error_target);
1397 ret = xt_register_match(&icmp6_matchstruct);
1401 /* Register setsockopt */
1402 ret = nf_register_sockopt(&ip6t_sockopts);
1406 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1410 xt_unregister_match(&icmp6_matchstruct);
1412 xt_unregister_target(&ip6t_error_target);
1414 xt_unregister_target(&ip6t_standard_target);
1416 xt_proto_fini(AF_INET6);
1421 static void __exit ip6_tables_fini(void)
1423 nf_unregister_sockopt(&ip6t_sockopts);
1424 xt_unregister_match(&icmp6_matchstruct);
1425 xt_unregister_target(&ip6t_error_target);
1426 xt_unregister_target(&ip6t_standard_target);
1427 xt_proto_fini(AF_INET6);
1431 * find the offset to specified header or the protocol number of last header
1432 * if target < 0. "last header" is transport protocol header, ESP, or
1435 * If target header is found, its offset is set in *offset and return protocol
1436 * number. Otherwise, return -1.
1438 * If the first fragment doesn't contain the final protocol header or
1439 * NEXTHDR_NONE it is considered invalid.
1441 * Note that non-1st fragment is special case that "the protocol number
1442 * of last header" is "next header" field in Fragment header. In this case,
1443 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1447 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1448 int target, unsigned short *fragoff)
1450 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1451 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1452 unsigned int len = skb->len - start;
1457 while (nexthdr != target) {
1458 struct ipv6_opt_hdr _hdr, *hp;
1459 unsigned int hdrlen;
1461 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1467 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1470 if (nexthdr == NEXTHDR_FRAGMENT) {
1471 unsigned short _frag_off;
1473 fp = skb_header_pointer(skb,
1474 start+offsetof(struct frag_hdr,
1481 _frag_off = ntohs(*fp) & ~0x7;
1484 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1485 hp->nexthdr == NEXTHDR_NONE)) {
1487 *fragoff = _frag_off;
1493 } else if (nexthdr == NEXTHDR_AUTH)
1494 hdrlen = (hp->hdrlen + 2) << 2;
1496 hdrlen = ipv6_optlen(hp);
1498 nexthdr = hp->nexthdr;
1507 EXPORT_SYMBOL(ip6t_register_table);
1508 EXPORT_SYMBOL(ip6t_unregister_table);
1509 EXPORT_SYMBOL(ip6t_do_table);
1510 EXPORT_SYMBOL(ip6t_ext_hdr);
1511 EXPORT_SYMBOL(ipv6_find_hdr);
1513 module_init(ip6_tables_init);
1514 module_exit(ip6_tables_fini);