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/icmpv6.h>
30 #include <asm/uaccess.h>
31 #include <linux/mutex.h>
32 #include <linux/proc_fs.h>
33 #include <linux/cpumask.h>
35 #include <linux/netfilter_ipv6/ip6_tables.h>
36 #include <linux/netfilter/x_tables.h>
38 MODULE_LICENSE("GPL");
39 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
40 MODULE_DESCRIPTION("IPv6 packet filter");
42 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
43 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
45 /*#define DEBUG_IP_FIREWALL*/
46 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
47 /*#define DEBUG_IP_FIREWALL_USER*/
49 #ifdef DEBUG_IP_FIREWALL
50 #define dprintf(format, args...) printk(format , ## args)
52 #define dprintf(format, args...)
55 #ifdef DEBUG_IP_FIREWALL_USER
56 #define duprintf(format, args...) printk(format , ## args)
58 #define duprintf(format, args...)
61 #ifdef CONFIG_NETFILTER_DEBUG
62 #define IP_NF_ASSERT(x) \
65 printk("IP_NF_ASSERT: %s:%s:%u\n", \
66 __FUNCTION__, __FILE__, __LINE__); \
69 #define IP_NF_ASSERT(x)
73 #include <linux/netfilter_ipv4/listhelp.h>
76 /* All the better to debug you with... */
82 We keep a set of rules for each CPU, so we can avoid write-locking
83 them in the softirq when updating the counters and therefore
84 only need to read-lock in the softirq; doing a write_lock_bh() in user
85 context stops packets coming through and allows user context to read
86 the counters or update the rules.
88 Hence the start of any table is given by get_table() below. */
91 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
92 #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; })
93 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
96 /* Check for an extension */
98 ip6t_ext_hdr(u8 nexthdr)
100 return ( (nexthdr == IPPROTO_HOPOPTS) ||
101 (nexthdr == IPPROTO_ROUTING) ||
102 (nexthdr == IPPROTO_FRAGMENT) ||
103 (nexthdr == IPPROTO_ESP) ||
104 (nexthdr == IPPROTO_AH) ||
105 (nexthdr == IPPROTO_NONE) ||
106 (nexthdr == IPPROTO_DSTOPTS) );
109 /* Returns whether matches rule or not. */
111 ip6_packet_match(const struct sk_buff *skb,
114 const struct ip6t_ip6 *ip6info,
115 unsigned int *protoff,
120 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
122 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
124 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
125 &ip6info->src), IP6T_INV_SRCIP)
126 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
127 &ip6info->dst), IP6T_INV_DSTIP)) {
128 dprintf("Source or dest mismatch.\n");
130 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
131 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
132 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
133 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
134 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
135 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
139 /* Look for ifname matches; this should unroll nicely. */
140 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
141 ret |= (((const unsigned long *)indev)[i]
142 ^ ((const unsigned long *)ip6info->iniface)[i])
143 & ((const unsigned long *)ip6info->iniface_mask)[i];
146 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
147 dprintf("VIA in mismatch (%s vs %s).%s\n",
148 indev, ip6info->iniface,
149 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
153 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
154 ret |= (((const unsigned long *)outdev)[i]
155 ^ ((const unsigned long *)ip6info->outiface)[i])
156 & ((const unsigned long *)ip6info->outiface_mask)[i];
159 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
160 dprintf("VIA out mismatch (%s vs %s).%s\n",
161 outdev, ip6info->outiface,
162 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
166 /* ... might want to do something with class and flowlabel here ... */
168 /* look for the desired protocol header */
169 if((ip6info->flags & IP6T_F_PROTO)) {
171 unsigned short _frag_off;
173 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,
226 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
232 int do_match(struct ip6t_entry_match *m,
233 const struct sk_buff *skb,
234 const struct net_device *in,
235 const struct net_device *out,
237 unsigned int protoff,
240 /* Stop iteration if it doesn't match */
241 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
242 offset, protoff, hotdrop))
248 static inline struct ip6t_entry *
249 get_entry(void *base, unsigned int offset)
251 return (struct ip6t_entry *)(base + offset);
254 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
256 ip6t_do_table(struct sk_buff **pskb,
258 const struct net_device *in,
259 const struct net_device *out,
260 struct xt_table *table,
263 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
265 unsigned int protoff = 0;
267 /* Initializing verdict to NF_DROP keeps gcc happy. */
268 unsigned int verdict = NF_DROP;
269 const char *indev, *outdev;
271 struct ip6t_entry *e, *back;
272 struct xt_table_info *private;
275 indev = in ? in->name : nulldevname;
276 outdev = out ? out->name : nulldevname;
277 /* We handle fragments by dealing with the first fragment as
278 * if it was a normal packet. All other fragments are treated
279 * normally, except that they will NEVER match rules that ask
280 * things we don't know, ie. tcp syn flag or ports). If the
281 * rule is also a fragment-specific rule, non-fragments won't
284 read_lock_bh(&table->lock);
285 private = table->private;
286 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
287 table_base = (void *)private->entries[smp_processor_id()];
288 e = get_entry(table_base, private->hook_entry[hook]);
290 /* For return from builtin chain */
291 back = get_entry(table_base, private->underflow[hook]);
296 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
297 &protoff, &offset)) {
298 struct ip6t_entry_target *t;
300 if (IP6T_MATCH_ITERATE(e, do_match,
302 offset, protoff, &hotdrop) != 0)
305 ADD_COUNTER(e->counters,
306 ntohs((*pskb)->nh.ipv6h->payload_len)
310 t = ip6t_get_target(e);
311 IP_NF_ASSERT(t->u.kernel.target);
312 /* Standard target? */
313 if (!t->u.kernel.target->target) {
316 v = ((struct ip6t_standard_target *)t)->verdict;
318 /* Pop from stack? */
319 if (v != IP6T_RETURN) {
320 verdict = (unsigned)(-v) - 1;
324 back = get_entry(table_base,
328 if (table_base + v != (void *)e + e->next_offset
329 && !(e->ipv6.flags & IP6T_F_GOTO)) {
330 /* Save old back ptr in next entry */
331 struct ip6t_entry *next
332 = (void *)e + e->next_offset;
334 = (void *)back - table_base;
335 /* set back pointer to next entry */
339 e = get_entry(table_base, v);
341 /* Targets which reenter must return
343 #ifdef CONFIG_NETFILTER_DEBUG
344 ((struct ip6t_entry *)table_base)->comefrom
347 verdict = t->u.kernel.target->target(pskb,
354 #ifdef CONFIG_NETFILTER_DEBUG
355 if (((struct ip6t_entry *)table_base)->comefrom
357 && verdict == IP6T_CONTINUE) {
358 printk("Target %s reentered!\n",
359 t->u.kernel.target->name);
362 ((struct ip6t_entry *)table_base)->comefrom
365 if (verdict == IP6T_CONTINUE)
366 e = (void *)e + e->next_offset;
374 e = (void *)e + e->next_offset;
378 #ifdef CONFIG_NETFILTER_DEBUG
379 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
381 read_unlock_bh(&table->lock);
383 #ifdef DEBUG_ALLOW_ALL
392 /* All zeroes == unconditional rule. */
394 unconditional(const struct ip6t_ip6 *ipv6)
398 for (i = 0; i < sizeof(*ipv6); i++)
399 if (((char *)ipv6)[i])
402 return (i == sizeof(*ipv6));
405 /* Figures out from what hook each rule can be called: returns 0 if
406 there are loops. Puts hook bitmask in comefrom. */
408 mark_source_chains(struct xt_table_info *newinfo,
409 unsigned int valid_hooks, void *entry0)
413 /* No recursion; use packet counter to save back ptrs (reset
414 to 0 as we leave), and comefrom to save source hook bitmask */
415 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
416 unsigned int pos = newinfo->hook_entry[hook];
418 = (struct ip6t_entry *)(entry0 + pos);
420 if (!(valid_hooks & (1 << hook)))
423 /* Set initial back pointer. */
424 e->counters.pcnt = pos;
427 struct ip6t_standard_target *t
428 = (void *)ip6t_get_target(e);
430 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
431 printk("iptables: loop hook %u pos %u %08X.\n",
432 hook, pos, e->comefrom);
436 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
438 /* Unconditional return/END. */
439 if (e->target_offset == sizeof(struct ip6t_entry)
440 && (strcmp(t->target.u.user.name,
441 IP6T_STANDARD_TARGET) == 0)
443 && unconditional(&e->ipv6)) {
444 unsigned int oldpos, size;
446 /* Return: backtrack through the last
449 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
450 #ifdef DEBUG_IP_FIREWALL_USER
452 & (1 << NF_IP6_NUMHOOKS)) {
453 duprintf("Back unset "
460 pos = e->counters.pcnt;
461 e->counters.pcnt = 0;
463 /* We're at the start. */
467 e = (struct ip6t_entry *)
469 } while (oldpos == pos + e->next_offset);
472 size = e->next_offset;
473 e = (struct ip6t_entry *)
474 (entry0 + pos + size);
475 e->counters.pcnt = pos;
478 int newpos = t->verdict;
480 if (strcmp(t->target.u.user.name,
481 IP6T_STANDARD_TARGET) == 0
483 /* This a jump; chase it. */
484 duprintf("Jump rule %u -> %u\n",
487 /* ... this is a fallthru */
488 newpos = pos + e->next_offset;
490 e = (struct ip6t_entry *)
492 e->counters.pcnt = pos;
497 duprintf("Finished chain %u\n", hook);
503 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
505 if (i && (*i)-- == 0)
508 if (m->u.kernel.match->destroy)
509 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
510 m->u.match_size - sizeof(*m));
511 module_put(m->u.kernel.match->me);
516 standard_check(const struct ip6t_entry_target *t,
517 unsigned int max_offset)
519 struct ip6t_standard_target *targ = (void *)t;
521 /* Check standard info. */
522 if (targ->verdict >= 0
523 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
524 duprintf("ip6t_standard_check: bad verdict (%i)\n",
528 if (targ->verdict < -NF_MAX_VERDICT - 1) {
529 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
537 check_match(struct ip6t_entry_match *m,
539 const struct ip6t_ip6 *ipv6,
540 unsigned int hookmask,
543 struct ip6t_match *match;
546 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
548 "ip6t_%s", m->u.user.name);
549 if (IS_ERR(match) || !match) {
550 duprintf("check_match: `%s' not found\n", m->u.user.name);
551 return match ? PTR_ERR(match) : -ENOENT;
553 m->u.kernel.match = match;
555 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
556 name, hookmask, ipv6->proto,
557 ipv6->invflags & IP6T_INV_PROTO);
561 if (m->u.kernel.match->checkentry
562 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
563 m->u.match_size - sizeof(*m),
565 duprintf("ip_tables: check failed for `%s'.\n",
566 m->u.kernel.match->name);
574 module_put(m->u.kernel.match->me);
578 static struct ip6t_target ip6t_standard_target;
581 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
584 struct ip6t_entry_target *t;
585 struct ip6t_target *target;
589 if (!ip6_checkentry(&e->ipv6)) {
590 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
595 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
597 goto cleanup_matches;
599 t = ip6t_get_target(e);
600 target = try_then_request_module(xt_find_target(AF_INET6,
603 "ip6t_%s", t->u.user.name);
604 if (IS_ERR(target) || !target) {
605 duprintf("check_entry: `%s' not found\n", t->u.user.name);
606 ret = target ? PTR_ERR(target) : -ENOENT;
607 goto cleanup_matches;
609 t->u.kernel.target = target;
611 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
612 name, e->comefrom, e->ipv6.proto,
613 e->ipv6.invflags & IP6T_INV_PROTO);
617 if (t->u.kernel.target == &ip6t_standard_target) {
618 if (!standard_check(t, size)) {
620 goto cleanup_matches;
622 } else if (t->u.kernel.target->checkentry
623 && !t->u.kernel.target->checkentry(name, e, target, t->data,
627 duprintf("ip_tables: check failed for `%s'.\n",
628 t->u.kernel.target->name);
636 module_put(t->u.kernel.target->me);
638 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
643 check_entry_size_and_hooks(struct ip6t_entry *e,
644 struct xt_table_info *newinfo,
646 unsigned char *limit,
647 const unsigned int *hook_entries,
648 const unsigned int *underflows,
653 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
654 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
655 duprintf("Bad offset %p\n", e);
660 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
661 duprintf("checking: element %p size %u\n",
666 /* Check hooks & underflows */
667 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
668 if ((unsigned char *)e - base == hook_entries[h])
669 newinfo->hook_entry[h] = hook_entries[h];
670 if ((unsigned char *)e - base == underflows[h])
671 newinfo->underflow[h] = underflows[h];
674 /* FIXME: underflows must be unconditional, standard verdicts
675 < 0 (not IP6T_RETURN). --RR */
677 /* Clear counters and comefrom */
678 e->counters = ((struct xt_counters) { 0, 0 });
686 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
688 struct ip6t_entry_target *t;
690 if (i && (*i)-- == 0)
693 /* Cleanup all matches */
694 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
695 t = ip6t_get_target(e);
696 if (t->u.kernel.target->destroy)
697 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
698 t->u.target_size - sizeof(*t));
699 module_put(t->u.kernel.target->me);
703 /* Checks and translates the user-supplied table segment (held in
706 translate_table(const char *name,
707 unsigned int valid_hooks,
708 struct xt_table_info *newinfo,
712 const unsigned int *hook_entries,
713 const unsigned int *underflows)
718 newinfo->size = size;
719 newinfo->number = number;
721 /* Init all hooks to impossible value. */
722 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
723 newinfo->hook_entry[i] = 0xFFFFFFFF;
724 newinfo->underflow[i] = 0xFFFFFFFF;
727 duprintf("translate_table: size %u\n", newinfo->size);
729 /* Walk through entries, checking offsets. */
730 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
731 check_entry_size_and_hooks,
735 hook_entries, underflows, &i);
740 duprintf("translate_table: %u not %u entries\n",
745 /* Check hooks all assigned */
746 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
747 /* Only hooks which are valid */
748 if (!(valid_hooks & (1 << i)))
750 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
751 duprintf("Invalid hook entry %u %u\n",
755 if (newinfo->underflow[i] == 0xFFFFFFFF) {
756 duprintf("Invalid underflow %u %u\n",
762 if (!mark_source_chains(newinfo, valid_hooks, entry0))
765 /* Finally, each sanity check must pass */
767 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
768 check_entry, name, size, &i);
771 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
776 /* And one copy for every other CPU */
777 for_each_possible_cpu(i) {
778 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
779 memcpy(newinfo->entries[i], entry0, newinfo->size);
787 add_entry_to_counter(const struct ip6t_entry *e,
788 struct xt_counters total[],
791 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
798 set_entry_to_counter(const struct ip6t_entry *e,
799 struct ip6t_counters total[],
802 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
809 get_counters(const struct xt_table_info *t,
810 struct xt_counters counters[])
816 /* Instead of clearing (by a previous call to memset())
817 * the counters and using adds, we set the counters
818 * with data used by 'current' CPU
819 * We dont care about preemption here.
821 curcpu = raw_smp_processor_id();
824 IP6T_ENTRY_ITERATE(t->entries[curcpu],
826 set_entry_to_counter,
830 for_each_possible_cpu(cpu) {
834 IP6T_ENTRY_ITERATE(t->entries[cpu],
836 add_entry_to_counter,
843 copy_entries_to_user(unsigned int total_size,
844 struct xt_table *table,
845 void __user *userptr)
847 unsigned int off, num, countersize;
848 struct ip6t_entry *e;
849 struct xt_counters *counters;
850 struct xt_table_info *private = table->private;
854 /* We need atomic snapshot of counters: rest doesn't change
855 (other than comefrom, which userspace doesn't care
857 countersize = sizeof(struct xt_counters) * private->number;
858 counters = vmalloc(countersize);
860 if (counters == NULL)
863 /* First, sum counters... */
864 write_lock_bh(&table->lock);
865 get_counters(private, counters);
866 write_unlock_bh(&table->lock);
868 /* choose the copy that is on ourc node/cpu */
869 loc_cpu_entry = private->entries[raw_smp_processor_id()];
870 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
875 /* FIXME: use iterator macros --RR */
876 /* ... then go back and fix counters and names */
877 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
879 struct ip6t_entry_match *m;
880 struct ip6t_entry_target *t;
882 e = (struct ip6t_entry *)(loc_cpu_entry + off);
883 if (copy_to_user(userptr + off
884 + offsetof(struct ip6t_entry, counters),
886 sizeof(counters[num])) != 0) {
891 for (i = sizeof(struct ip6t_entry);
892 i < e->target_offset;
893 i += m->u.match_size) {
896 if (copy_to_user(userptr + off + i
897 + offsetof(struct ip6t_entry_match,
899 m->u.kernel.match->name,
900 strlen(m->u.kernel.match->name)+1)
907 t = ip6t_get_target(e);
908 if (copy_to_user(userptr + off + e->target_offset
909 + offsetof(struct ip6t_entry_target,
911 t->u.kernel.target->name,
912 strlen(t->u.kernel.target->name)+1) != 0) {
924 get_entries(const struct ip6t_get_entries *entries,
925 struct ip6t_get_entries __user *uptr)
930 t = xt_find_table_lock(AF_INET6, entries->name);
931 if (t && !IS_ERR(t)) {
932 struct xt_table_info *private = t->private;
933 duprintf("t->private->number = %u\n", private->number);
934 if (entries->size == private->size)
935 ret = copy_entries_to_user(private->size,
936 t, uptr->entrytable);
938 duprintf("get_entries: I've got %u not %u!\n",
939 private->size, entries->size);
945 ret = t ? PTR_ERR(t) : -ENOENT;
951 do_replace(void __user *user, unsigned int len)
954 struct ip6t_replace tmp;
956 struct xt_table_info *newinfo, *oldinfo;
957 struct xt_counters *counters;
958 void *loc_cpu_entry, *loc_cpu_old_entry;
960 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
964 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
967 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
970 newinfo = xt_alloc_table_info(tmp.size);
974 /* choose the copy that is on our node/cpu */
975 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
976 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
982 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
988 ret = translate_table(tmp.name, tmp.valid_hooks,
989 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
990 tmp.hook_entry, tmp.underflow);
992 goto free_newinfo_counters;
994 duprintf("ip_tables: Translated table\n");
996 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
997 "ip6table_%s", tmp.name);
998 if (!t || IS_ERR(t)) {
999 ret = t ? PTR_ERR(t) : -ENOENT;
1000 goto free_newinfo_counters_untrans;
1004 if (tmp.valid_hooks != t->valid_hooks) {
1005 duprintf("Valid hook crap: %08X vs %08X\n",
1006 tmp.valid_hooks, t->valid_hooks);
1011 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1015 /* Update module usage count based on number of rules */
1016 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1017 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1018 if ((oldinfo->number > oldinfo->initial_entries) ||
1019 (newinfo->number <= oldinfo->initial_entries))
1021 if ((oldinfo->number > oldinfo->initial_entries) &&
1022 (newinfo->number <= oldinfo->initial_entries))
1025 /* Get the old counters. */
1026 get_counters(oldinfo, counters);
1027 /* Decrease module usage counts and free resource */
1028 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1029 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1030 xt_free_table_info(oldinfo);
1031 if (copy_to_user(tmp.counters, counters,
1032 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1041 free_newinfo_counters_untrans:
1042 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1043 free_newinfo_counters:
1046 xt_free_table_info(newinfo);
1050 /* We're lazy, and add to the first CPU; overflow works its fey magic
1051 * and everything is OK. */
1053 add_counter_to_entry(struct ip6t_entry *e,
1054 const struct xt_counters addme[],
1058 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1060 (long unsigned int)e->counters.pcnt,
1061 (long unsigned int)e->counters.bcnt,
1062 (long unsigned int)addme[*i].pcnt,
1063 (long unsigned int)addme[*i].bcnt);
1066 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1073 do_add_counters(void __user *user, unsigned int len)
1076 struct xt_counters_info tmp, *paddc;
1077 struct xt_table_info *private;
1080 void *loc_cpu_entry;
1082 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1085 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1088 paddc = vmalloc(len);
1092 if (copy_from_user(paddc, user, len) != 0) {
1097 t = xt_find_table_lock(AF_INET6, tmp.name);
1098 if (!t || IS_ERR(t)) {
1099 ret = t ? PTR_ERR(t) : -ENOENT;
1103 write_lock_bh(&t->lock);
1104 private = t->private;
1105 if (private->number != tmp.num_counters) {
1107 goto unlock_up_free;
1111 /* Choose the copy that is on our node */
1112 loc_cpu_entry = private->entries[smp_processor_id()];
1113 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1115 add_counter_to_entry,
1119 write_unlock_bh(&t->lock);
1129 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1133 if (!capable(CAP_NET_ADMIN))
1137 case IP6T_SO_SET_REPLACE:
1138 ret = do_replace(user, len);
1141 case IP6T_SO_SET_ADD_COUNTERS:
1142 ret = do_add_counters(user, len);
1146 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1154 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1158 if (!capable(CAP_NET_ADMIN))
1162 case IP6T_SO_GET_INFO: {
1163 char name[IP6T_TABLE_MAXNAMELEN];
1166 if (*len != sizeof(struct ip6t_getinfo)) {
1167 duprintf("length %u != %u\n", *len,
1168 sizeof(struct ip6t_getinfo));
1173 if (copy_from_user(name, user, sizeof(name)) != 0) {
1177 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1179 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1180 "ip6table_%s", name);
1181 if (t && !IS_ERR(t)) {
1182 struct ip6t_getinfo info;
1183 struct xt_table_info *private = t->private;
1185 info.valid_hooks = t->valid_hooks;
1186 memcpy(info.hook_entry, private->hook_entry,
1187 sizeof(info.hook_entry));
1188 memcpy(info.underflow, private->underflow,
1189 sizeof(info.underflow));
1190 info.num_entries = private->number;
1191 info.size = private->size;
1192 memcpy(info.name, name, sizeof(info.name));
1194 if (copy_to_user(user, &info, *len) != 0)
1201 ret = t ? PTR_ERR(t) : -ENOENT;
1205 case IP6T_SO_GET_ENTRIES: {
1206 struct ip6t_get_entries get;
1208 if (*len < sizeof(get)) {
1209 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1211 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1213 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1214 duprintf("get_entries: %u != %u\n", *len,
1215 sizeof(struct ip6t_get_entries) + get.size);
1218 ret = get_entries(&get, user);
1222 case IP6T_SO_GET_REVISION_MATCH:
1223 case IP6T_SO_GET_REVISION_TARGET: {
1224 struct ip6t_get_revision rev;
1227 if (*len != sizeof(rev)) {
1231 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1236 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1241 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1244 "ip6t_%s", rev.name);
1249 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1256 int ip6t_register_table(struct xt_table *table,
1257 const struct ip6t_replace *repl)
1260 struct xt_table_info *newinfo;
1261 static struct xt_table_info bootstrap
1262 = { 0, 0, 0, { 0 }, { 0 }, { } };
1263 void *loc_cpu_entry;
1265 newinfo = xt_alloc_table_info(repl->size);
1269 /* choose the copy on our node/cpu */
1270 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1271 memcpy(loc_cpu_entry, repl->entries, repl->size);
1273 ret = translate_table(table->name, table->valid_hooks,
1274 newinfo, loc_cpu_entry, repl->size,
1279 xt_free_table_info(newinfo);
1283 ret = xt_register_table(table, &bootstrap, newinfo);
1285 xt_free_table_info(newinfo);
1292 void ip6t_unregister_table(struct xt_table *table)
1294 struct xt_table_info *private;
1295 void *loc_cpu_entry;
1297 private = xt_unregister_table(table);
1299 /* Decrease module usage counts and free resources */
1300 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1301 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1302 xt_free_table_info(private);
1305 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1307 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1308 u_int8_t type, u_int8_t code,
1311 return (type == test_type && code >= min_code && code <= max_code)
1316 icmp6_match(const struct sk_buff *skb,
1317 const struct net_device *in,
1318 const struct net_device *out,
1319 const struct xt_match *match,
1320 const void *matchinfo,
1322 unsigned int protoff,
1325 struct icmp6hdr _icmp, *ic;
1326 const struct ip6t_icmp *icmpinfo = matchinfo;
1328 /* Must not be a fragment. */
1332 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1334 /* We've been asked to examine this packet, and we
1335 can't. Hence, no choice but to drop. */
1336 duprintf("Dropping evil ICMP tinygram.\n");
1341 return icmp6_type_code_match(icmpinfo->type,
1344 ic->icmp6_type, ic->icmp6_code,
1345 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1348 /* Called when user tries to insert an entry of this type. */
1350 icmp6_checkentry(const char *tablename,
1352 const struct xt_match *match,
1354 unsigned int matchsize,
1355 unsigned int hook_mask)
1357 const struct ip6t_icmp *icmpinfo = matchinfo;
1359 /* Must specify no unknown invflags */
1360 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1363 /* The built-in targets: standard (NULL) and error. */
1364 static struct ip6t_target ip6t_standard_target = {
1365 .name = IP6T_STANDARD_TARGET,
1366 .targetsize = sizeof(int),
1370 static struct ip6t_target ip6t_error_target = {
1371 .name = IP6T_ERROR_TARGET,
1372 .target = ip6t_error,
1373 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1377 static struct nf_sockopt_ops ip6t_sockopts = {
1379 .set_optmin = IP6T_BASE_CTL,
1380 .set_optmax = IP6T_SO_SET_MAX+1,
1381 .set = do_ip6t_set_ctl,
1382 .get_optmin = IP6T_BASE_CTL,
1383 .get_optmax = IP6T_SO_GET_MAX+1,
1384 .get = do_ip6t_get_ctl,
1387 static struct ip6t_match icmp6_matchstruct = {
1389 .match = &icmp6_match,
1390 .matchsize = sizeof(struct ip6t_icmp),
1391 .checkentry = icmp6_checkentry,
1392 .proto = IPPROTO_ICMPV6,
1396 static int __init ip6_tables_init(void)
1400 xt_proto_init(AF_INET6);
1402 /* Noone else will be downing sem now, so we won't sleep */
1403 xt_register_target(&ip6t_standard_target);
1404 xt_register_target(&ip6t_error_target);
1405 xt_register_match(&icmp6_matchstruct);
1407 /* Register setsockopt */
1408 ret = nf_register_sockopt(&ip6t_sockopts);
1410 duprintf("Unable to register sockopts.\n");
1411 xt_proto_fini(AF_INET6);
1415 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1419 static void __exit ip6_tables_fini(void)
1421 nf_unregister_sockopt(&ip6t_sockopts);
1422 xt_unregister_match(&icmp6_matchstruct);
1423 xt_unregister_target(&ip6t_error_target);
1424 xt_unregister_target(&ip6t_standard_target);
1425 xt_proto_fini(AF_INET6);
1429 * find the offset to specified header or the protocol number of last header
1430 * if target < 0. "last header" is transport protocol header, ESP, or
1433 * If target header is found, its offset is set in *offset and return protocol
1434 * number. Otherwise, return -1.
1436 * Note that non-1st fragment is special case that "the protocol number
1437 * of last header" is "next header" field in Fragment header. In this case,
1438 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1442 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1443 int target, unsigned short *fragoff)
1445 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1446 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1447 unsigned int len = skb->len - start;
1452 while (nexthdr != target) {
1453 struct ipv6_opt_hdr _hdr, *hp;
1454 unsigned int hdrlen;
1456 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1462 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1465 if (nexthdr == NEXTHDR_FRAGMENT) {
1466 unsigned short _frag_off, *fp;
1467 fp = skb_header_pointer(skb,
1468 start+offsetof(struct frag_hdr,
1475 _frag_off = ntohs(*fp) & ~0x7;
1478 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1479 nexthdr == NEXTHDR_NONE)) {
1481 *fragoff = _frag_off;
1487 } else if (nexthdr == NEXTHDR_AUTH)
1488 hdrlen = (hp->hdrlen + 2) << 2;
1490 hdrlen = ipv6_optlen(hp);
1492 nexthdr = hp->nexthdr;
1501 EXPORT_SYMBOL(ip6t_register_table);
1502 EXPORT_SYMBOL(ip6t_unregister_table);
1503 EXPORT_SYMBOL(ip6t_do_table);
1504 EXPORT_SYMBOL(ip6t_ext_hdr);
1505 EXPORT_SYMBOL(ipv6_find_hdr);
1507 module_init(ip6_tables_init);
1508 module_exit(ip6_tables_fini);