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 #include <linux/netfilter_ipv4/listhelp.h>
77 /* All the better to debug you with... */
83 We keep a set of rules for each CPU, so we can avoid write-locking
84 them in the softirq when updating the counters and therefore
85 only need to read-lock in the softirq; doing a write_lock_bh() in user
86 context stops packets coming through and allows user context to read
87 the counters or update the rules.
89 Hence the start of any table is given by get_table() below. */
92 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
93 #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; })
94 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
97 /* Check for an extension */
99 ip6t_ext_hdr(u8 nexthdr)
101 return ( (nexthdr == IPPROTO_HOPOPTS) ||
102 (nexthdr == IPPROTO_ROUTING) ||
103 (nexthdr == IPPROTO_FRAGMENT) ||
104 (nexthdr == IPPROTO_ESP) ||
105 (nexthdr == IPPROTO_AH) ||
106 (nexthdr == IPPROTO_NONE) ||
107 (nexthdr == IPPROTO_DSTOPTS) );
110 /* Returns whether matches rule or not. */
112 ip6_packet_match(const struct sk_buff *skb,
115 const struct ip6t_ip6 *ip6info,
116 unsigned int *protoff,
121 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
123 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
125 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
126 &ip6info->src), IP6T_INV_SRCIP)
127 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
128 &ip6info->dst), IP6T_INV_DSTIP)) {
129 dprintf("Source or dest mismatch.\n");
131 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
132 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
133 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
134 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
135 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
136 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
140 /* Look for ifname matches; this should unroll nicely. */
141 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
142 ret |= (((const unsigned long *)indev)[i]
143 ^ ((const unsigned long *)ip6info->iniface)[i])
144 & ((const unsigned long *)ip6info->iniface_mask)[i];
147 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
148 dprintf("VIA in mismatch (%s vs %s).%s\n",
149 indev, ip6info->iniface,
150 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
154 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
155 ret |= (((const unsigned long *)outdev)[i]
156 ^ ((const unsigned long *)ip6info->outiface)[i])
157 & ((const unsigned long *)ip6info->outiface_mask)[i];
160 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
161 dprintf("VIA out mismatch (%s vs %s).%s\n",
162 outdev, ip6info->outiface,
163 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
167 /* ... might want to do something with class and flowlabel here ... */
169 /* look for the desired protocol header */
170 if((ip6info->flags & IP6T_F_PROTO)) {
172 unsigned short _frag_off;
174 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
178 *fragoff = _frag_off;
180 dprintf("Packet protocol %hi ?= %s%hi.\n",
182 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
185 if (ip6info->proto == protohdr) {
186 if(ip6info->invflags & IP6T_INV_PROTO) {
192 /* We need match for the '-p all', too! */
193 if ((ip6info->proto != 0) &&
194 !(ip6info->invflags & IP6T_INV_PROTO))
200 /* should be ip6 safe */
202 ip6_checkentry(const struct ip6t_ip6 *ipv6)
204 if (ipv6->flags & ~IP6T_F_MASK) {
205 duprintf("Unknown flag bits set: %08X\n",
206 ipv6->flags & ~IP6T_F_MASK);
209 if (ipv6->invflags & ~IP6T_INV_MASK) {
210 duprintf("Unknown invflag bits set: %08X\n",
211 ipv6->invflags & ~IP6T_INV_MASK);
218 ip6t_error(struct sk_buff **pskb,
219 const struct net_device *in,
220 const struct net_device *out,
221 unsigned int hooknum,
222 const struct xt_target *target,
223 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)
262 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
264 unsigned int protoff = 0;
266 /* Initializing verdict to NF_DROP keeps gcc happy. */
267 unsigned int verdict = NF_DROP;
268 const char *indev, *outdev;
270 struct ip6t_entry *e, *back;
271 struct xt_table_info *private;
274 indev = in ? in->name : nulldevname;
275 outdev = out ? out->name : nulldevname;
276 /* We handle fragments by dealing with the first fragment as
277 * if it was a normal packet. All other fragments are treated
278 * normally, except that they will NEVER match rules that ask
279 * things we don't know, ie. tcp syn flag or ports). If the
280 * rule is also a fragment-specific rule, non-fragments won't
283 read_lock_bh(&table->lock);
284 private = table->private;
285 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
286 table_base = (void *)private->entries[smp_processor_id()];
287 e = get_entry(table_base, private->hook_entry[hook]);
289 /* For return from builtin chain */
290 back = get_entry(table_base, private->underflow[hook]);
295 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
296 &protoff, &offset)) {
297 struct ip6t_entry_target *t;
299 if (IP6T_MATCH_ITERATE(e, do_match,
301 offset, protoff, &hotdrop) != 0)
304 ADD_COUNTER(e->counters,
305 ntohs((*pskb)->nh.ipv6h->payload_len)
309 t = ip6t_get_target(e);
310 IP_NF_ASSERT(t->u.kernel.target);
311 /* Standard target? */
312 if (!t->u.kernel.target->target) {
315 v = ((struct ip6t_standard_target *)t)->verdict;
317 /* Pop from stack? */
318 if (v != IP6T_RETURN) {
319 verdict = (unsigned)(-v) - 1;
323 back = get_entry(table_base,
327 if (table_base + v != (void *)e + e->next_offset
328 && !(e->ipv6.flags & IP6T_F_GOTO)) {
329 /* Save old back ptr in next entry */
330 struct ip6t_entry *next
331 = (void *)e + e->next_offset;
333 = (void *)back - table_base;
334 /* set back pointer to next entry */
338 e = get_entry(table_base, v);
340 /* Targets which reenter must return
342 #ifdef CONFIG_NETFILTER_DEBUG
343 ((struct ip6t_entry *)table_base)->comefrom
346 verdict = t->u.kernel.target->target(pskb,
352 #ifdef CONFIG_NETFILTER_DEBUG
353 if (((struct ip6t_entry *)table_base)->comefrom
355 && verdict == IP6T_CONTINUE) {
356 printk("Target %s reentered!\n",
357 t->u.kernel.target->name);
360 ((struct ip6t_entry *)table_base)->comefrom
363 if (verdict == IP6T_CONTINUE)
364 e = (void *)e + e->next_offset;
372 e = (void *)e + e->next_offset;
376 #ifdef CONFIG_NETFILTER_DEBUG
377 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
379 read_unlock_bh(&table->lock);
381 #ifdef DEBUG_ALLOW_ALL
390 /* All zeroes == unconditional rule. */
392 unconditional(const struct ip6t_ip6 *ipv6)
396 for (i = 0; i < sizeof(*ipv6); i++)
397 if (((char *)ipv6)[i])
400 return (i == sizeof(*ipv6));
403 /* Figures out from what hook each rule can be called: returns 0 if
404 there are loops. Puts hook bitmask in comefrom. */
406 mark_source_chains(struct xt_table_info *newinfo,
407 unsigned int valid_hooks, void *entry0)
411 /* No recursion; use packet counter to save back ptrs (reset
412 to 0 as we leave), and comefrom to save source hook bitmask */
413 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
414 unsigned int pos = newinfo->hook_entry[hook];
416 = (struct ip6t_entry *)(entry0 + pos);
418 if (!(valid_hooks & (1 << hook)))
421 /* Set initial back pointer. */
422 e->counters.pcnt = pos;
425 struct ip6t_standard_target *t
426 = (void *)ip6t_get_target(e);
428 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
429 printk("iptables: loop hook %u pos %u %08X.\n",
430 hook, pos, e->comefrom);
434 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
436 /* Unconditional return/END. */
437 if (e->target_offset == sizeof(struct ip6t_entry)
438 && (strcmp(t->target.u.user.name,
439 IP6T_STANDARD_TARGET) == 0)
441 && unconditional(&e->ipv6)) {
442 unsigned int oldpos, size;
444 /* Return: backtrack through the last
447 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
448 #ifdef DEBUG_IP_FIREWALL_USER
450 & (1 << NF_IP6_NUMHOOKS)) {
451 duprintf("Back unset "
458 pos = e->counters.pcnt;
459 e->counters.pcnt = 0;
461 /* We're at the start. */
465 e = (struct ip6t_entry *)
467 } while (oldpos == pos + e->next_offset);
470 size = e->next_offset;
471 e = (struct ip6t_entry *)
472 (entry0 + pos + size);
473 e->counters.pcnt = pos;
476 int newpos = t->verdict;
478 if (strcmp(t->target.u.user.name,
479 IP6T_STANDARD_TARGET) == 0
481 /* This a jump; chase it. */
482 duprintf("Jump rule %u -> %u\n",
485 /* ... this is a fallthru */
486 newpos = pos + e->next_offset;
488 e = (struct ip6t_entry *)
490 e->counters.pcnt = pos;
495 duprintf("Finished chain %u\n", hook);
501 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
503 if (i && (*i)-- == 0)
506 if (m->u.kernel.match->destroy)
507 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
508 module_put(m->u.kernel.match->me);
513 standard_check(const struct ip6t_entry_target *t,
514 unsigned int max_offset)
516 struct ip6t_standard_target *targ = (void *)t;
518 /* Check standard info. */
519 if (targ->verdict >= 0
520 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
521 duprintf("ip6t_standard_check: bad verdict (%i)\n",
525 if (targ->verdict < -NF_MAX_VERDICT - 1) {
526 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
534 check_match(struct ip6t_entry_match *m,
536 const struct ip6t_ip6 *ipv6,
537 unsigned int hookmask,
540 struct ip6t_match *match;
543 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
545 "ip6t_%s", m->u.user.name);
546 if (IS_ERR(match) || !match) {
547 duprintf("check_match: `%s' not found\n", m->u.user.name);
548 return match ? PTR_ERR(match) : -ENOENT;
550 m->u.kernel.match = match;
552 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
553 name, hookmask, ipv6->proto,
554 ipv6->invflags & IP6T_INV_PROTO);
558 if (m->u.kernel.match->checkentry
559 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
561 duprintf("ip_tables: check failed for `%s'.\n",
562 m->u.kernel.match->name);
570 module_put(m->u.kernel.match->me);
574 static struct ip6t_target ip6t_standard_target;
577 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
580 struct ip6t_entry_target *t;
581 struct ip6t_target *target;
585 if (!ip6_checkentry(&e->ipv6)) {
586 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
591 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
593 goto cleanup_matches;
595 t = ip6t_get_target(e);
596 target = try_then_request_module(xt_find_target(AF_INET6,
599 "ip6t_%s", t->u.user.name);
600 if (IS_ERR(target) || !target) {
601 duprintf("check_entry: `%s' not found\n", t->u.user.name);
602 ret = target ? PTR_ERR(target) : -ENOENT;
603 goto cleanup_matches;
605 t->u.kernel.target = target;
607 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
608 name, e->comefrom, e->ipv6.proto,
609 e->ipv6.invflags & IP6T_INV_PROTO);
613 if (t->u.kernel.target == &ip6t_standard_target) {
614 if (!standard_check(t, size)) {
616 goto cleanup_matches;
618 } else if (t->u.kernel.target->checkentry
619 && !t->u.kernel.target->checkentry(name, e, target, t->data,
621 duprintf("ip_tables: check failed for `%s'.\n",
622 t->u.kernel.target->name);
630 module_put(t->u.kernel.target->me);
632 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
637 check_entry_size_and_hooks(struct ip6t_entry *e,
638 struct xt_table_info *newinfo,
640 unsigned char *limit,
641 const unsigned int *hook_entries,
642 const unsigned int *underflows,
647 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
648 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
649 duprintf("Bad offset %p\n", e);
654 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
655 duprintf("checking: element %p size %u\n",
660 /* Check hooks & underflows */
661 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
662 if ((unsigned char *)e - base == hook_entries[h])
663 newinfo->hook_entry[h] = hook_entries[h];
664 if ((unsigned char *)e - base == underflows[h])
665 newinfo->underflow[h] = underflows[h];
668 /* FIXME: underflows must be unconditional, standard verdicts
669 < 0 (not IP6T_RETURN). --RR */
671 /* Clear counters and comefrom */
672 e->counters = ((struct xt_counters) { 0, 0 });
680 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
682 struct ip6t_entry_target *t;
684 if (i && (*i)-- == 0)
687 /* Cleanup all matches */
688 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
689 t = ip6t_get_target(e);
690 if (t->u.kernel.target->destroy)
691 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
692 module_put(t->u.kernel.target->me);
696 /* Checks and translates the user-supplied table segment (held in
699 translate_table(const char *name,
700 unsigned int valid_hooks,
701 struct xt_table_info *newinfo,
705 const unsigned int *hook_entries,
706 const unsigned int *underflows)
711 newinfo->size = size;
712 newinfo->number = number;
714 /* Init all hooks to impossible value. */
715 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
716 newinfo->hook_entry[i] = 0xFFFFFFFF;
717 newinfo->underflow[i] = 0xFFFFFFFF;
720 duprintf("translate_table: size %u\n", newinfo->size);
722 /* Walk through entries, checking offsets. */
723 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
724 check_entry_size_and_hooks,
728 hook_entries, underflows, &i);
733 duprintf("translate_table: %u not %u entries\n",
738 /* Check hooks all assigned */
739 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
740 /* Only hooks which are valid */
741 if (!(valid_hooks & (1 << i)))
743 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
744 duprintf("Invalid hook entry %u %u\n",
748 if (newinfo->underflow[i] == 0xFFFFFFFF) {
749 duprintf("Invalid underflow %u %u\n",
755 if (!mark_source_chains(newinfo, valid_hooks, entry0))
758 /* Finally, each sanity check must pass */
760 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
761 check_entry, name, size, &i);
764 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
769 /* And one copy for every other CPU */
770 for_each_possible_cpu(i) {
771 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
772 memcpy(newinfo->entries[i], entry0, newinfo->size);
780 add_entry_to_counter(const struct ip6t_entry *e,
781 struct xt_counters total[],
784 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
791 set_entry_to_counter(const struct ip6t_entry *e,
792 struct ip6t_counters total[],
795 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
802 get_counters(const struct xt_table_info *t,
803 struct xt_counters counters[])
809 /* Instead of clearing (by a previous call to memset())
810 * the counters and using adds, we set the counters
811 * with data used by 'current' CPU
812 * We dont care about preemption here.
814 curcpu = raw_smp_processor_id();
817 IP6T_ENTRY_ITERATE(t->entries[curcpu],
819 set_entry_to_counter,
823 for_each_possible_cpu(cpu) {
827 IP6T_ENTRY_ITERATE(t->entries[cpu],
829 add_entry_to_counter,
836 copy_entries_to_user(unsigned int total_size,
837 struct xt_table *table,
838 void __user *userptr)
840 unsigned int off, num, countersize;
841 struct ip6t_entry *e;
842 struct xt_counters *counters;
843 struct xt_table_info *private = table->private;
847 /* We need atomic snapshot of counters: rest doesn't change
848 (other than comefrom, which userspace doesn't care
850 countersize = sizeof(struct xt_counters) * private->number;
851 counters = vmalloc(countersize);
853 if (counters == NULL)
856 /* First, sum counters... */
857 write_lock_bh(&table->lock);
858 get_counters(private, counters);
859 write_unlock_bh(&table->lock);
861 /* choose the copy that is on ourc node/cpu */
862 loc_cpu_entry = private->entries[raw_smp_processor_id()];
863 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
868 /* FIXME: use iterator macros --RR */
869 /* ... then go back and fix counters and names */
870 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
872 struct ip6t_entry_match *m;
873 struct ip6t_entry_target *t;
875 e = (struct ip6t_entry *)(loc_cpu_entry + off);
876 if (copy_to_user(userptr + off
877 + offsetof(struct ip6t_entry, counters),
879 sizeof(counters[num])) != 0) {
884 for (i = sizeof(struct ip6t_entry);
885 i < e->target_offset;
886 i += m->u.match_size) {
889 if (copy_to_user(userptr + off + i
890 + offsetof(struct ip6t_entry_match,
892 m->u.kernel.match->name,
893 strlen(m->u.kernel.match->name)+1)
900 t = ip6t_get_target(e);
901 if (copy_to_user(userptr + off + e->target_offset
902 + offsetof(struct ip6t_entry_target,
904 t->u.kernel.target->name,
905 strlen(t->u.kernel.target->name)+1) != 0) {
917 get_entries(const struct ip6t_get_entries *entries,
918 struct ip6t_get_entries __user *uptr)
923 t = xt_find_table_lock(AF_INET6, entries->name);
924 if (t && !IS_ERR(t)) {
925 struct xt_table_info *private = t->private;
926 duprintf("t->private->number = %u\n", private->number);
927 if (entries->size == private->size)
928 ret = copy_entries_to_user(private->size,
929 t, uptr->entrytable);
931 duprintf("get_entries: I've got %u not %u!\n",
932 private->size, entries->size);
938 ret = t ? PTR_ERR(t) : -ENOENT;
944 do_replace(void __user *user, unsigned int len)
947 struct ip6t_replace tmp;
949 struct xt_table_info *newinfo, *oldinfo;
950 struct xt_counters *counters;
951 void *loc_cpu_entry, *loc_cpu_old_entry;
953 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
957 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
960 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
963 newinfo = xt_alloc_table_info(tmp.size);
967 /* choose the copy that is on our node/cpu */
968 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
969 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
975 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
981 ret = translate_table(tmp.name, tmp.valid_hooks,
982 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
983 tmp.hook_entry, tmp.underflow);
985 goto free_newinfo_counters;
987 duprintf("ip_tables: Translated table\n");
989 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
990 "ip6table_%s", tmp.name);
991 if (!t || IS_ERR(t)) {
992 ret = t ? PTR_ERR(t) : -ENOENT;
993 goto free_newinfo_counters_untrans;
997 if (tmp.valid_hooks != t->valid_hooks) {
998 duprintf("Valid hook crap: %08X vs %08X\n",
999 tmp.valid_hooks, t->valid_hooks);
1004 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1008 /* Update module usage count based on number of rules */
1009 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1010 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1011 if ((oldinfo->number > oldinfo->initial_entries) ||
1012 (newinfo->number <= oldinfo->initial_entries))
1014 if ((oldinfo->number > oldinfo->initial_entries) &&
1015 (newinfo->number <= oldinfo->initial_entries))
1018 /* Get the old counters. */
1019 get_counters(oldinfo, counters);
1020 /* Decrease module usage counts and free resource */
1021 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1022 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1023 xt_free_table_info(oldinfo);
1024 if (copy_to_user(tmp.counters, counters,
1025 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1034 free_newinfo_counters_untrans:
1035 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1036 free_newinfo_counters:
1039 xt_free_table_info(newinfo);
1043 /* We're lazy, and add to the first CPU; overflow works its fey magic
1044 * and everything is OK. */
1046 add_counter_to_entry(struct ip6t_entry *e,
1047 const struct xt_counters addme[],
1051 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1053 (long unsigned int)e->counters.pcnt,
1054 (long unsigned int)e->counters.bcnt,
1055 (long unsigned int)addme[*i].pcnt,
1056 (long unsigned int)addme[*i].bcnt);
1059 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1066 do_add_counters(void __user *user, unsigned int len)
1069 struct xt_counters_info tmp, *paddc;
1070 struct xt_table_info *private;
1073 void *loc_cpu_entry;
1075 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1078 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1081 paddc = vmalloc(len);
1085 if (copy_from_user(paddc, user, len) != 0) {
1090 t = xt_find_table_lock(AF_INET6, tmp.name);
1091 if (!t || IS_ERR(t)) {
1092 ret = t ? PTR_ERR(t) : -ENOENT;
1096 write_lock_bh(&t->lock);
1097 private = t->private;
1098 if (private->number != tmp.num_counters) {
1100 goto unlock_up_free;
1104 /* Choose the copy that is on our node */
1105 loc_cpu_entry = private->entries[smp_processor_id()];
1106 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1108 add_counter_to_entry,
1112 write_unlock_bh(&t->lock);
1122 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1126 if (!capable(CAP_NET_ADMIN))
1130 case IP6T_SO_SET_REPLACE:
1131 ret = do_replace(user, len);
1134 case IP6T_SO_SET_ADD_COUNTERS:
1135 ret = do_add_counters(user, len);
1139 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1147 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1151 if (!capable(CAP_NET_ADMIN))
1155 case IP6T_SO_GET_INFO: {
1156 char name[IP6T_TABLE_MAXNAMELEN];
1159 if (*len != sizeof(struct ip6t_getinfo)) {
1160 duprintf("length %u != %u\n", *len,
1161 sizeof(struct ip6t_getinfo));
1166 if (copy_from_user(name, user, sizeof(name)) != 0) {
1170 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1172 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1173 "ip6table_%s", name);
1174 if (t && !IS_ERR(t)) {
1175 struct ip6t_getinfo info;
1176 struct xt_table_info *private = t->private;
1178 info.valid_hooks = t->valid_hooks;
1179 memcpy(info.hook_entry, private->hook_entry,
1180 sizeof(info.hook_entry));
1181 memcpy(info.underflow, private->underflow,
1182 sizeof(info.underflow));
1183 info.num_entries = private->number;
1184 info.size = private->size;
1185 memcpy(info.name, name, sizeof(info.name));
1187 if (copy_to_user(user, &info, *len) != 0)
1194 ret = t ? PTR_ERR(t) : -ENOENT;
1198 case IP6T_SO_GET_ENTRIES: {
1199 struct ip6t_get_entries get;
1201 if (*len < sizeof(get)) {
1202 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1204 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1206 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1207 duprintf("get_entries: %u != %u\n", *len,
1208 sizeof(struct ip6t_get_entries) + get.size);
1211 ret = get_entries(&get, user);
1215 case IP6T_SO_GET_REVISION_MATCH:
1216 case IP6T_SO_GET_REVISION_TARGET: {
1217 struct ip6t_get_revision rev;
1220 if (*len != sizeof(rev)) {
1224 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1229 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1234 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1237 "ip6t_%s", rev.name);
1242 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1249 int ip6t_register_table(struct xt_table *table,
1250 const struct ip6t_replace *repl)
1253 struct xt_table_info *newinfo;
1254 static struct xt_table_info bootstrap
1255 = { 0, 0, 0, { 0 }, { 0 }, { } };
1256 void *loc_cpu_entry;
1258 newinfo = xt_alloc_table_info(repl->size);
1262 /* choose the copy on our node/cpu */
1263 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1264 memcpy(loc_cpu_entry, repl->entries, repl->size);
1266 ret = translate_table(table->name, table->valid_hooks,
1267 newinfo, loc_cpu_entry, repl->size,
1272 xt_free_table_info(newinfo);
1276 ret = xt_register_table(table, &bootstrap, newinfo);
1278 xt_free_table_info(newinfo);
1285 void ip6t_unregister_table(struct xt_table *table)
1287 struct xt_table_info *private;
1288 void *loc_cpu_entry;
1290 private = xt_unregister_table(table);
1292 /* Decrease module usage counts and free resources */
1293 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1294 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1295 xt_free_table_info(private);
1298 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1300 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1301 u_int8_t type, u_int8_t code,
1304 return (type == test_type && code >= min_code && code <= max_code)
1309 icmp6_match(const struct sk_buff *skb,
1310 const struct net_device *in,
1311 const struct net_device *out,
1312 const struct xt_match *match,
1313 const void *matchinfo,
1315 unsigned int protoff,
1318 struct icmp6hdr _icmp, *ic;
1319 const struct ip6t_icmp *icmpinfo = matchinfo;
1321 /* Must not be a fragment. */
1325 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1327 /* We've been asked to examine this packet, and we
1328 can't. Hence, no choice but to drop. */
1329 duprintf("Dropping evil ICMP tinygram.\n");
1334 return icmp6_type_code_match(icmpinfo->type,
1337 ic->icmp6_type, ic->icmp6_code,
1338 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1341 /* Called when user tries to insert an entry of this type. */
1343 icmp6_checkentry(const char *tablename,
1345 const struct xt_match *match,
1347 unsigned int hook_mask)
1349 const struct ip6t_icmp *icmpinfo = matchinfo;
1351 /* Must specify no unknown invflags */
1352 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1355 /* The built-in targets: standard (NULL) and error. */
1356 static struct ip6t_target ip6t_standard_target = {
1357 .name = IP6T_STANDARD_TARGET,
1358 .targetsize = sizeof(int),
1362 static struct ip6t_target ip6t_error_target = {
1363 .name = IP6T_ERROR_TARGET,
1364 .target = ip6t_error,
1365 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1369 static struct nf_sockopt_ops ip6t_sockopts = {
1371 .set_optmin = IP6T_BASE_CTL,
1372 .set_optmax = IP6T_SO_SET_MAX+1,
1373 .set = do_ip6t_set_ctl,
1374 .get_optmin = IP6T_BASE_CTL,
1375 .get_optmax = IP6T_SO_GET_MAX+1,
1376 .get = do_ip6t_get_ctl,
1379 static struct ip6t_match icmp6_matchstruct = {
1381 .match = &icmp6_match,
1382 .matchsize = sizeof(struct ip6t_icmp),
1383 .checkentry = icmp6_checkentry,
1384 .proto = IPPROTO_ICMPV6,
1388 static int __init ip6_tables_init(void)
1392 ret = xt_proto_init(AF_INET6);
1396 /* Noone else will be downing sem now, so we won't sleep */
1397 ret = xt_register_target(&ip6t_standard_target);
1400 ret = xt_register_target(&ip6t_error_target);
1403 ret = xt_register_match(&icmp6_matchstruct);
1407 /* Register setsockopt */
1408 ret = nf_register_sockopt(&ip6t_sockopts);
1412 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1416 xt_unregister_match(&icmp6_matchstruct);
1418 xt_unregister_target(&ip6t_error_target);
1420 xt_unregister_target(&ip6t_standard_target);
1422 xt_proto_fini(AF_INET6);
1427 static void __exit ip6_tables_fini(void)
1429 nf_unregister_sockopt(&ip6t_sockopts);
1430 xt_unregister_match(&icmp6_matchstruct);
1431 xt_unregister_target(&ip6t_error_target);
1432 xt_unregister_target(&ip6t_standard_target);
1433 xt_proto_fini(AF_INET6);
1437 * find the offset to specified header or the protocol number of last header
1438 * if target < 0. "last header" is transport protocol header, ESP, or
1441 * If target header is found, its offset is set in *offset and return protocol
1442 * number. Otherwise, return -1.
1444 * Note that non-1st fragment is special case that "the protocol number
1445 * of last header" is "next header" field in Fragment header. In this case,
1446 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1450 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1451 int target, unsigned short *fragoff)
1453 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1454 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1455 unsigned int len = skb->len - start;
1460 while (nexthdr != target) {
1461 struct ipv6_opt_hdr _hdr, *hp;
1462 unsigned int hdrlen;
1464 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1470 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1473 if (nexthdr == NEXTHDR_FRAGMENT) {
1474 unsigned short _frag_off, *fp;
1475 fp = skb_header_pointer(skb,
1476 start+offsetof(struct frag_hdr,
1483 _frag_off = ntohs(*fp) & ~0x7;
1486 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1487 nexthdr == NEXTHDR_NONE)) {
1489 *fragoff = _frag_off;
1495 } else if (nexthdr == NEXTHDR_AUTH)
1496 hdrlen = (hp->hdrlen + 2) << 2;
1498 hdrlen = ipv6_optlen(hp);
1500 nexthdr = hp->nexthdr;
1509 EXPORT_SYMBOL(ip6t_register_table);
1510 EXPORT_SYMBOL(ip6t_unregister_table);
1511 EXPORT_SYMBOL(ip6t_do_table);
1512 EXPORT_SYMBOL(ip6t_ext_hdr);
1513 EXPORT_SYMBOL(ipv6_find_hdr);
1515 module_init(ip6_tables_init);
1516 module_exit(ip6_tables_fini);