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,
227 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
233 int do_match(struct ip6t_entry_match *m,
234 const struct sk_buff *skb,
235 const struct net_device *in,
236 const struct net_device *out,
238 unsigned int protoff,
241 /* Stop iteration if it doesn't match */
242 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
243 offset, protoff, hotdrop))
249 static inline struct ip6t_entry *
250 get_entry(void *base, unsigned int offset)
252 return (struct ip6t_entry *)(base + offset);
255 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
257 ip6t_do_table(struct sk_buff **pskb,
259 const struct net_device *in,
260 const struct net_device *out,
261 struct xt_table *table,
264 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
266 unsigned int protoff = 0;
268 /* Initializing verdict to NF_DROP keeps gcc happy. */
269 unsigned int verdict = NF_DROP;
270 const char *indev, *outdev;
272 struct ip6t_entry *e, *back;
273 struct xt_table_info *private;
276 indev = in ? in->name : nulldevname;
277 outdev = out ? out->name : nulldevname;
278 /* We handle fragments by dealing with the first fragment as
279 * if it was a normal packet. All other fragments are treated
280 * normally, except that they will NEVER match rules that ask
281 * things we don't know, ie. tcp syn flag or ports). If the
282 * rule is also a fragment-specific rule, non-fragments won't
285 read_lock_bh(&table->lock);
286 private = table->private;
287 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
288 table_base = (void *)private->entries[smp_processor_id()];
289 e = get_entry(table_base, private->hook_entry[hook]);
291 /* For return from builtin chain */
292 back = get_entry(table_base, private->underflow[hook]);
297 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
298 &protoff, &offset)) {
299 struct ip6t_entry_target *t;
301 if (IP6T_MATCH_ITERATE(e, do_match,
303 offset, protoff, &hotdrop) != 0)
306 ADD_COUNTER(e->counters,
307 ntohs((*pskb)->nh.ipv6h->payload_len)
311 t = ip6t_get_target(e);
312 IP_NF_ASSERT(t->u.kernel.target);
313 /* Standard target? */
314 if (!t->u.kernel.target->target) {
317 v = ((struct ip6t_standard_target *)t)->verdict;
319 /* Pop from stack? */
320 if (v != IP6T_RETURN) {
321 verdict = (unsigned)(-v) - 1;
325 back = get_entry(table_base,
329 if (table_base + v != (void *)e + e->next_offset
330 && !(e->ipv6.flags & IP6T_F_GOTO)) {
331 /* Save old back ptr in next entry */
332 struct ip6t_entry *next
333 = (void *)e + e->next_offset;
335 = (void *)back - table_base;
336 /* set back pointer to next entry */
340 e = get_entry(table_base, v);
342 /* Targets which reenter must return
344 #ifdef CONFIG_NETFILTER_DEBUG
345 ((struct ip6t_entry *)table_base)->comefrom
348 verdict = t->u.kernel.target->target(pskb,
355 #ifdef CONFIG_NETFILTER_DEBUG
356 if (((struct ip6t_entry *)table_base)->comefrom
358 && verdict == IP6T_CONTINUE) {
359 printk("Target %s reentered!\n",
360 t->u.kernel.target->name);
363 ((struct ip6t_entry *)table_base)->comefrom
366 if (verdict == IP6T_CONTINUE)
367 e = (void *)e + e->next_offset;
375 e = (void *)e + e->next_offset;
379 #ifdef CONFIG_NETFILTER_DEBUG
380 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
382 read_unlock_bh(&table->lock);
384 #ifdef DEBUG_ALLOW_ALL
393 /* All zeroes == unconditional rule. */
395 unconditional(const struct ip6t_ip6 *ipv6)
399 for (i = 0; i < sizeof(*ipv6); i++)
400 if (((char *)ipv6)[i])
403 return (i == sizeof(*ipv6));
406 /* Figures out from what hook each rule can be called: returns 0 if
407 there are loops. Puts hook bitmask in comefrom. */
409 mark_source_chains(struct xt_table_info *newinfo,
410 unsigned int valid_hooks, void *entry0)
414 /* No recursion; use packet counter to save back ptrs (reset
415 to 0 as we leave), and comefrom to save source hook bitmask */
416 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
417 unsigned int pos = newinfo->hook_entry[hook];
419 = (struct ip6t_entry *)(entry0 + pos);
421 if (!(valid_hooks & (1 << hook)))
424 /* Set initial back pointer. */
425 e->counters.pcnt = pos;
428 struct ip6t_standard_target *t
429 = (void *)ip6t_get_target(e);
431 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
432 printk("iptables: loop hook %u pos %u %08X.\n",
433 hook, pos, e->comefrom);
437 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
439 /* Unconditional return/END. */
440 if (e->target_offset == sizeof(struct ip6t_entry)
441 && (strcmp(t->target.u.user.name,
442 IP6T_STANDARD_TARGET) == 0)
444 && unconditional(&e->ipv6)) {
445 unsigned int oldpos, size;
447 if (t->verdict < -NF_MAX_VERDICT - 1) {
448 duprintf("mark_source_chains: bad "
449 "negative verdict (%i)\n",
454 /* Return: backtrack through the last
457 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
458 #ifdef DEBUG_IP_FIREWALL_USER
460 & (1 << NF_IP6_NUMHOOKS)) {
461 duprintf("Back unset "
468 pos = e->counters.pcnt;
469 e->counters.pcnt = 0;
471 /* We're at the start. */
475 e = (struct ip6t_entry *)
477 } while (oldpos == pos + e->next_offset);
480 size = e->next_offset;
481 e = (struct ip6t_entry *)
482 (entry0 + pos + size);
483 e->counters.pcnt = pos;
486 int newpos = t->verdict;
488 if (strcmp(t->target.u.user.name,
489 IP6T_STANDARD_TARGET) == 0
491 if (newpos > newinfo->size -
492 sizeof(struct ip6t_entry)) {
493 duprintf("mark_source_chains: "
494 "bad verdict (%i)\n",
498 /* This a jump; chase it. */
499 duprintf("Jump rule %u -> %u\n",
502 /* ... this is a fallthru */
503 newpos = pos + e->next_offset;
505 e = (struct ip6t_entry *)
507 e->counters.pcnt = pos;
512 duprintf("Finished chain %u\n", hook);
518 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
520 if (i && (*i)-- == 0)
523 if (m->u.kernel.match->destroy)
524 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
525 m->u.match_size - sizeof(*m));
526 module_put(m->u.kernel.match->me);
531 check_match(struct ip6t_entry_match *m,
533 const struct ip6t_ip6 *ipv6,
534 unsigned int hookmask,
537 struct ip6t_match *match;
540 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
542 "ip6t_%s", m->u.user.name);
543 if (IS_ERR(match) || !match) {
544 duprintf("check_match: `%s' not found\n", m->u.user.name);
545 return match ? PTR_ERR(match) : -ENOENT;
547 m->u.kernel.match = match;
549 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
550 name, hookmask, ipv6->proto,
551 ipv6->invflags & IP6T_INV_PROTO);
555 if (m->u.kernel.match->checkentry
556 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
557 m->u.match_size - sizeof(*m),
559 duprintf("ip_tables: check failed for `%s'.\n",
560 m->u.kernel.match->name);
568 module_put(m->u.kernel.match->me);
572 static struct ip6t_target ip6t_standard_target;
575 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
578 struct ip6t_entry_target *t;
579 struct ip6t_target *target;
583 if (!ip6_checkentry(&e->ipv6)) {
584 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
588 if (e->target_offset + sizeof(struct ip6t_entry_target) >
593 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
595 goto cleanup_matches;
597 t = ip6t_get_target(e);
599 if (e->target_offset + t->u.target_size > e->next_offset)
600 goto cleanup_matches;
601 target = try_then_request_module(xt_find_target(AF_INET6,
604 "ip6t_%s", t->u.user.name);
605 if (IS_ERR(target) || !target) {
606 duprintf("check_entry: `%s' not found\n", t->u.user.name);
607 ret = target ? PTR_ERR(target) : -ENOENT;
608 goto cleanup_matches;
610 t->u.kernel.target = target;
612 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
613 name, e->comefrom, e->ipv6.proto,
614 e->ipv6.invflags & IP6T_INV_PROTO);
618 if (t->u.kernel.target->checkentry
619 && !t->u.kernel.target->checkentry(name, e, target, t->data,
623 duprintf("ip_tables: check failed for `%s'.\n",
624 t->u.kernel.target->name);
632 module_put(t->u.kernel.target->me);
634 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
639 check_entry_size_and_hooks(struct ip6t_entry *e,
640 struct xt_table_info *newinfo,
642 unsigned char *limit,
643 const unsigned int *hook_entries,
644 const unsigned int *underflows,
649 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
650 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
651 duprintf("Bad offset %p\n", e);
656 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
657 duprintf("checking: element %p size %u\n",
662 /* Check hooks & underflows */
663 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
664 if ((unsigned char *)e - base == hook_entries[h])
665 newinfo->hook_entry[h] = hook_entries[h];
666 if ((unsigned char *)e - base == underflows[h])
667 newinfo->underflow[h] = underflows[h];
670 /* FIXME: underflows must be unconditional, standard verdicts
671 < 0 (not IP6T_RETURN). --RR */
673 /* Clear counters and comefrom */
674 e->counters = ((struct xt_counters) { 0, 0 });
682 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
684 struct ip6t_entry_target *t;
686 if (i && (*i)-- == 0)
689 /* Cleanup all matches */
690 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
691 t = ip6t_get_target(e);
692 if (t->u.kernel.target->destroy)
693 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
694 t->u.target_size - sizeof(*t));
695 module_put(t->u.kernel.target->me);
699 /* Checks and translates the user-supplied table segment (held in
702 translate_table(const char *name,
703 unsigned int valid_hooks,
704 struct xt_table_info *newinfo,
708 const unsigned int *hook_entries,
709 const unsigned int *underflows)
714 newinfo->size = size;
715 newinfo->number = number;
717 /* Init all hooks to impossible value. */
718 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
719 newinfo->hook_entry[i] = 0xFFFFFFFF;
720 newinfo->underflow[i] = 0xFFFFFFFF;
723 duprintf("translate_table: size %u\n", newinfo->size);
725 /* Walk through entries, checking offsets. */
726 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
727 check_entry_size_and_hooks,
731 hook_entries, underflows, &i);
736 duprintf("translate_table: %u not %u entries\n",
741 /* Check hooks all assigned */
742 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
743 /* Only hooks which are valid */
744 if (!(valid_hooks & (1 << i)))
746 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
747 duprintf("Invalid hook entry %u %u\n",
751 if (newinfo->underflow[i] == 0xFFFFFFFF) {
752 duprintf("Invalid underflow %u %u\n",
758 if (!mark_source_chains(newinfo, valid_hooks, entry0))
761 /* Finally, each sanity check must pass */
763 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
764 check_entry, name, size, &i);
767 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
772 /* And one copy for every other CPU */
773 for_each_possible_cpu(i) {
774 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
775 memcpy(newinfo->entries[i], entry0, newinfo->size);
783 add_entry_to_counter(const struct ip6t_entry *e,
784 struct xt_counters total[],
787 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
794 set_entry_to_counter(const struct ip6t_entry *e,
795 struct ip6t_counters total[],
798 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
805 get_counters(const struct xt_table_info *t,
806 struct xt_counters counters[])
812 /* Instead of clearing (by a previous call to memset())
813 * the counters and using adds, we set the counters
814 * with data used by 'current' CPU
815 * We dont care about preemption here.
817 curcpu = raw_smp_processor_id();
820 IP6T_ENTRY_ITERATE(t->entries[curcpu],
822 set_entry_to_counter,
826 for_each_possible_cpu(cpu) {
830 IP6T_ENTRY_ITERATE(t->entries[cpu],
832 add_entry_to_counter,
839 copy_entries_to_user(unsigned int total_size,
840 struct xt_table *table,
841 void __user *userptr)
843 unsigned int off, num, countersize;
844 struct ip6t_entry *e;
845 struct xt_counters *counters;
846 struct xt_table_info *private = table->private;
850 /* We need atomic snapshot of counters: rest doesn't change
851 (other than comefrom, which userspace doesn't care
853 countersize = sizeof(struct xt_counters) * private->number;
854 counters = vmalloc(countersize);
856 if (counters == NULL)
859 /* First, sum counters... */
860 write_lock_bh(&table->lock);
861 get_counters(private, counters);
862 write_unlock_bh(&table->lock);
864 /* choose the copy that is on ourc node/cpu */
865 loc_cpu_entry = private->entries[raw_smp_processor_id()];
866 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
871 /* FIXME: use iterator macros --RR */
872 /* ... then go back and fix counters and names */
873 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
875 struct ip6t_entry_match *m;
876 struct ip6t_entry_target *t;
878 e = (struct ip6t_entry *)(loc_cpu_entry + off);
879 if (copy_to_user(userptr + off
880 + offsetof(struct ip6t_entry, counters),
882 sizeof(counters[num])) != 0) {
887 for (i = sizeof(struct ip6t_entry);
888 i < e->target_offset;
889 i += m->u.match_size) {
892 if (copy_to_user(userptr + off + i
893 + offsetof(struct ip6t_entry_match,
895 m->u.kernel.match->name,
896 strlen(m->u.kernel.match->name)+1)
903 t = ip6t_get_target(e);
904 if (copy_to_user(userptr + off + e->target_offset
905 + offsetof(struct ip6t_entry_target,
907 t->u.kernel.target->name,
908 strlen(t->u.kernel.target->name)+1) != 0) {
920 get_entries(const struct ip6t_get_entries *entries,
921 struct ip6t_get_entries __user *uptr)
926 t = xt_find_table_lock(AF_INET6, entries->name);
927 if (t && !IS_ERR(t)) {
928 struct xt_table_info *private = t->private;
929 duprintf("t->private->number = %u\n", private->number);
930 if (entries->size == private->size)
931 ret = copy_entries_to_user(private->size,
932 t, uptr->entrytable);
934 duprintf("get_entries: I've got %u not %u!\n",
935 private->size, entries->size);
941 ret = t ? PTR_ERR(t) : -ENOENT;
947 do_replace(void __user *user, unsigned int len)
950 struct ip6t_replace tmp;
952 struct xt_table_info *newinfo, *oldinfo;
953 struct xt_counters *counters;
954 void *loc_cpu_entry, *loc_cpu_old_entry;
956 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
960 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
963 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
966 newinfo = xt_alloc_table_info(tmp.size);
970 /* choose the copy that is on our node/cpu */
971 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
972 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
978 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
984 ret = translate_table(tmp.name, tmp.valid_hooks,
985 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
986 tmp.hook_entry, tmp.underflow);
988 goto free_newinfo_counters;
990 duprintf("ip_tables: Translated table\n");
992 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
993 "ip6table_%s", tmp.name);
994 if (!t || IS_ERR(t)) {
995 ret = t ? PTR_ERR(t) : -ENOENT;
996 goto free_newinfo_counters_untrans;
1000 if (tmp.valid_hooks != t->valid_hooks) {
1001 duprintf("Valid hook crap: %08X vs %08X\n",
1002 tmp.valid_hooks, t->valid_hooks);
1007 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1011 /* Update module usage count based on number of rules */
1012 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1013 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1014 if ((oldinfo->number > oldinfo->initial_entries) ||
1015 (newinfo->number <= oldinfo->initial_entries))
1017 if ((oldinfo->number > oldinfo->initial_entries) &&
1018 (newinfo->number <= oldinfo->initial_entries))
1021 /* Get the old counters. */
1022 get_counters(oldinfo, counters);
1023 /* Decrease module usage counts and free resource */
1024 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1025 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1026 xt_free_table_info(oldinfo);
1027 if (copy_to_user(tmp.counters, counters,
1028 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1037 free_newinfo_counters_untrans:
1038 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1039 free_newinfo_counters:
1042 xt_free_table_info(newinfo);
1046 /* We're lazy, and add to the first CPU; overflow works its fey magic
1047 * and everything is OK. */
1049 add_counter_to_entry(struct ip6t_entry *e,
1050 const struct xt_counters addme[],
1054 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1056 (long unsigned int)e->counters.pcnt,
1057 (long unsigned int)e->counters.bcnt,
1058 (long unsigned int)addme[*i].pcnt,
1059 (long unsigned int)addme[*i].bcnt);
1062 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1069 do_add_counters(void __user *user, unsigned int len)
1072 struct xt_counters_info tmp, *paddc;
1073 struct xt_table_info *private;
1076 void *loc_cpu_entry;
1078 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1081 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1084 paddc = vmalloc(len);
1088 if (copy_from_user(paddc, user, len) != 0) {
1093 t = xt_find_table_lock(AF_INET6, tmp.name);
1094 if (!t || IS_ERR(t)) {
1095 ret = t ? PTR_ERR(t) : -ENOENT;
1099 write_lock_bh(&t->lock);
1100 private = t->private;
1101 if (private->number != tmp.num_counters) {
1103 goto unlock_up_free;
1107 /* Choose the copy that is on our node */
1108 loc_cpu_entry = private->entries[smp_processor_id()];
1109 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1111 add_counter_to_entry,
1115 write_unlock_bh(&t->lock);
1125 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1129 if (!capable(CAP_NET_ADMIN))
1133 case IP6T_SO_SET_REPLACE:
1134 ret = do_replace(user, len);
1137 case IP6T_SO_SET_ADD_COUNTERS:
1138 ret = do_add_counters(user, len);
1142 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1150 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1154 if (!capable(CAP_NET_ADMIN))
1158 case IP6T_SO_GET_INFO: {
1159 char name[IP6T_TABLE_MAXNAMELEN];
1162 if (*len != sizeof(struct ip6t_getinfo)) {
1163 duprintf("length %u != %u\n", *len,
1164 sizeof(struct ip6t_getinfo));
1169 if (copy_from_user(name, user, sizeof(name)) != 0) {
1173 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1175 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1176 "ip6table_%s", name);
1177 if (t && !IS_ERR(t)) {
1178 struct ip6t_getinfo info;
1179 struct xt_table_info *private = t->private;
1181 info.valid_hooks = t->valid_hooks;
1182 memcpy(info.hook_entry, private->hook_entry,
1183 sizeof(info.hook_entry));
1184 memcpy(info.underflow, private->underflow,
1185 sizeof(info.underflow));
1186 info.num_entries = private->number;
1187 info.size = private->size;
1188 memcpy(info.name, name, sizeof(info.name));
1190 if (copy_to_user(user, &info, *len) != 0)
1197 ret = t ? PTR_ERR(t) : -ENOENT;
1201 case IP6T_SO_GET_ENTRIES: {
1202 struct ip6t_get_entries get;
1204 if (*len < sizeof(get)) {
1205 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1207 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1209 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1210 duprintf("get_entries: %u != %u\n", *len,
1211 sizeof(struct ip6t_get_entries) + get.size);
1214 ret = get_entries(&get, user);
1218 case IP6T_SO_GET_REVISION_MATCH:
1219 case IP6T_SO_GET_REVISION_TARGET: {
1220 struct ip6t_get_revision rev;
1223 if (*len != sizeof(rev)) {
1227 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1232 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1237 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1240 "ip6t_%s", rev.name);
1245 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1252 int ip6t_register_table(struct xt_table *table,
1253 const struct ip6t_replace *repl)
1256 struct xt_table_info *newinfo;
1257 static struct xt_table_info bootstrap
1258 = { 0, 0, 0, { 0 }, { 0 }, { } };
1259 void *loc_cpu_entry;
1261 newinfo = xt_alloc_table_info(repl->size);
1265 /* choose the copy on our node/cpu */
1266 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1267 memcpy(loc_cpu_entry, repl->entries, repl->size);
1269 ret = translate_table(table->name, table->valid_hooks,
1270 newinfo, loc_cpu_entry, repl->size,
1275 xt_free_table_info(newinfo);
1279 ret = xt_register_table(table, &bootstrap, newinfo);
1281 xt_free_table_info(newinfo);
1288 void ip6t_unregister_table(struct xt_table *table)
1290 struct xt_table_info *private;
1291 void *loc_cpu_entry;
1293 private = xt_unregister_table(table);
1295 /* Decrease module usage counts and free resources */
1296 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1297 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1298 xt_free_table_info(private);
1301 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1303 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1304 u_int8_t type, u_int8_t code,
1307 return (type == test_type && code >= min_code && code <= max_code)
1312 icmp6_match(const struct sk_buff *skb,
1313 const struct net_device *in,
1314 const struct net_device *out,
1315 const struct xt_match *match,
1316 const void *matchinfo,
1318 unsigned int protoff,
1321 struct icmp6hdr _icmp, *ic;
1322 const struct ip6t_icmp *icmpinfo = matchinfo;
1324 /* Must not be a fragment. */
1328 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1330 /* We've been asked to examine this packet, and we
1331 can't. Hence, no choice but to drop. */
1332 duprintf("Dropping evil ICMP tinygram.\n");
1337 return icmp6_type_code_match(icmpinfo->type,
1340 ic->icmp6_type, ic->icmp6_code,
1341 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1344 /* Called when user tries to insert an entry of this type. */
1346 icmp6_checkentry(const char *tablename,
1348 const struct xt_match *match,
1350 unsigned int matchsize,
1351 unsigned int hook_mask)
1353 const struct ip6t_icmp *icmpinfo = matchinfo;
1355 /* Must specify no unknown invflags */
1356 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1359 /* The built-in targets: standard (NULL) and error. */
1360 static struct ip6t_target ip6t_standard_target = {
1361 .name = IP6T_STANDARD_TARGET,
1362 .targetsize = sizeof(int),
1366 static struct ip6t_target ip6t_error_target = {
1367 .name = IP6T_ERROR_TARGET,
1368 .target = ip6t_error,
1369 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1373 static struct nf_sockopt_ops ip6t_sockopts = {
1375 .set_optmin = IP6T_BASE_CTL,
1376 .set_optmax = IP6T_SO_SET_MAX+1,
1377 .set = do_ip6t_set_ctl,
1378 .get_optmin = IP6T_BASE_CTL,
1379 .get_optmax = IP6T_SO_GET_MAX+1,
1380 .get = do_ip6t_get_ctl,
1383 static struct ip6t_match icmp6_matchstruct = {
1385 .match = &icmp6_match,
1386 .matchsize = sizeof(struct ip6t_icmp),
1387 .checkentry = icmp6_checkentry,
1388 .proto = IPPROTO_ICMPV6,
1392 static int __init ip6_tables_init(void)
1396 ret = xt_proto_init(AF_INET6);
1400 /* Noone else will be downing sem now, so we won't sleep */
1401 ret = xt_register_target(&ip6t_standard_target);
1404 ret = xt_register_target(&ip6t_error_target);
1407 ret = xt_register_match(&icmp6_matchstruct);
1411 /* Register setsockopt */
1412 ret = nf_register_sockopt(&ip6t_sockopts);
1416 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1420 xt_unregister_match(&icmp6_matchstruct);
1422 xt_unregister_target(&ip6t_error_target);
1424 xt_unregister_target(&ip6t_standard_target);
1426 xt_proto_fini(AF_INET6);
1431 static void __exit ip6_tables_fini(void)
1433 nf_unregister_sockopt(&ip6t_sockopts);
1434 xt_unregister_match(&icmp6_matchstruct);
1435 xt_unregister_target(&ip6t_error_target);
1436 xt_unregister_target(&ip6t_standard_target);
1437 xt_proto_fini(AF_INET6);
1441 * find the offset to specified header or the protocol number of last header
1442 * if target < 0. "last header" is transport protocol header, ESP, or
1445 * If target header is found, its offset is set in *offset and return protocol
1446 * number. Otherwise, return -1.
1448 * Note that non-1st fragment is special case that "the protocol number
1449 * of last header" is "next header" field in Fragment header. In this case,
1450 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1454 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1455 int target, unsigned short *fragoff)
1457 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1458 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1459 unsigned int len = skb->len - start;
1464 while (nexthdr != target) {
1465 struct ipv6_opt_hdr _hdr, *hp;
1466 unsigned int hdrlen;
1468 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1474 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1477 if (nexthdr == NEXTHDR_FRAGMENT) {
1478 unsigned short _frag_off, *fp;
1479 fp = skb_header_pointer(skb,
1480 start+offsetof(struct frag_hdr,
1487 _frag_off = ntohs(*fp) & ~0x7;
1490 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1491 nexthdr == NEXTHDR_NONE)) {
1493 *fragoff = _frag_off;
1499 } else if (nexthdr == NEXTHDR_AUTH)
1500 hdrlen = (hp->hdrlen + 2) << 2;
1502 hdrlen = ipv6_optlen(hp);
1504 nexthdr = hp->nexthdr;
1513 EXPORT_SYMBOL(ip6t_register_table);
1514 EXPORT_SYMBOL(ip6t_unregister_table);
1515 EXPORT_SYMBOL(ip6t_do_table);
1516 EXPORT_SYMBOL(ip6t_ext_hdr);
1517 EXPORT_SYMBOL(ipv6_find_hdr);
1519 module_init(ip6_tables_init);
1520 module_exit(ip6_tables_fini);