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>
22 #include <linux/config.h>
24 #include <linux/skbuff.h>
25 #include <linux/kmod.h>
26 #include <linux/vmalloc.h>
27 #include <linux/netdevice.h>
28 #include <linux/module.h>
29 #include <linux/icmpv6.h>
31 #include <asm/uaccess.h>
32 #include <asm/semaphore.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)
98 ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
99 const struct in6_addr *addr2)
102 for( i = 0; i < 16; i++){
103 if((addr1->s6_addr[i] & mask->s6_addr[i]) !=
104 (addr2->s6_addr[i] & mask->s6_addr[i]))
110 /* Check for an extension */
112 ip6t_ext_hdr(u8 nexthdr)
114 return ( (nexthdr == IPPROTO_HOPOPTS) ||
115 (nexthdr == IPPROTO_ROUTING) ||
116 (nexthdr == IPPROTO_FRAGMENT) ||
117 (nexthdr == IPPROTO_ESP) ||
118 (nexthdr == IPPROTO_AH) ||
119 (nexthdr == IPPROTO_NONE) ||
120 (nexthdr == IPPROTO_DSTOPTS) );
123 /* Returns whether matches rule or not. */
125 ip6_packet_match(const struct sk_buff *skb,
128 const struct ip6t_ip6 *ip6info,
129 unsigned int *protoff,
130 int *fragoff, int *hotdrop)
134 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
136 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
138 if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk,
139 &ip6info->src), IP6T_INV_SRCIP)
140 || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk,
141 &ip6info->dst), IP6T_INV_DSTIP)) {
142 dprintf("Source or dest mismatch.\n");
144 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
145 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
146 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
147 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
148 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
149 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
153 /* Look for ifname matches; this should unroll nicely. */
154 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
155 ret |= (((const unsigned long *)indev)[i]
156 ^ ((const unsigned long *)ip6info->iniface)[i])
157 & ((const unsigned long *)ip6info->iniface_mask)[i];
160 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
161 dprintf("VIA in mismatch (%s vs %s).%s\n",
162 indev, ip6info->iniface,
163 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
167 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
168 ret |= (((const unsigned long *)outdev)[i]
169 ^ ((const unsigned long *)ip6info->outiface)[i])
170 & ((const unsigned long *)ip6info->outiface_mask)[i];
173 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
174 dprintf("VIA out mismatch (%s vs %s).%s\n",
175 outdev, ip6info->outiface,
176 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
180 /* ... might want to do something with class and flowlabel here ... */
182 /* look for the desired protocol header */
183 if((ip6info->flags & IP6T_F_PROTO)) {
185 unsigned short _frag_off;
187 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
193 *fragoff = _frag_off;
195 dprintf("Packet protocol %hi ?= %s%hi.\n",
197 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
200 if (ip6info->proto == protohdr) {
201 if(ip6info->invflags & IP6T_INV_PROTO) {
207 /* We need match for the '-p all', too! */
208 if ((ip6info->proto != 0) &&
209 !(ip6info->invflags & IP6T_INV_PROTO))
215 /* should be ip6 safe */
217 ip6_checkentry(const struct ip6t_ip6 *ipv6)
219 if (ipv6->flags & ~IP6T_F_MASK) {
220 duprintf("Unknown flag bits set: %08X\n",
221 ipv6->flags & ~IP6T_F_MASK);
224 if (ipv6->invflags & ~IP6T_INV_MASK) {
225 duprintf("Unknown invflag bits set: %08X\n",
226 ipv6->invflags & ~IP6T_INV_MASK);
233 ip6t_error(struct sk_buff **pskb,
234 const struct net_device *in,
235 const struct net_device *out,
236 unsigned int hooknum,
237 const void *targinfo,
241 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
247 int do_match(struct ip6t_entry_match *m,
248 const struct sk_buff *skb,
249 const struct net_device *in,
250 const struct net_device *out,
252 unsigned int protoff,
255 /* Stop iteration if it doesn't match */
256 if (!m->u.kernel.match->match(skb, in, out, m->data,
257 offset, protoff, hotdrop))
263 static inline struct ip6t_entry *
264 get_entry(void *base, unsigned int offset)
266 return (struct ip6t_entry *)(base + offset);
269 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
271 ip6t_do_table(struct sk_buff **pskb,
273 const struct net_device *in,
274 const struct net_device *out,
275 struct xt_table *table,
278 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
280 unsigned int protoff = 0;
282 /* Initializing verdict to NF_DROP keeps gcc happy. */
283 unsigned int verdict = NF_DROP;
284 const char *indev, *outdev;
286 struct ip6t_entry *e, *back;
287 struct xt_table_info *private;
290 indev = in ? in->name : nulldevname;
291 outdev = out ? out->name : nulldevname;
292 /* We handle fragments by dealing with the first fragment as
293 * if it was a normal packet. All other fragments are treated
294 * normally, except that they will NEVER match rules that ask
295 * things we don't know, ie. tcp syn flag or ports). If the
296 * rule is also a fragment-specific rule, non-fragments won't
299 read_lock_bh(&table->lock);
300 private = table->private;
301 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
302 table_base = (void *)private->entries[smp_processor_id()];
303 e = get_entry(table_base, private->hook_entry[hook]);
305 #ifdef CONFIG_NETFILTER_DEBUG
306 /* Check noone else using our table */
307 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
308 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
309 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
312 &((struct ip6t_entry *)table_base)->comefrom,
313 ((struct ip6t_entry *)table_base)->comefrom);
315 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
318 /* For return from builtin chain */
319 back = get_entry(table_base, private->underflow[hook]);
324 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
325 &protoff, &offset, &hotdrop)) {
326 struct ip6t_entry_target *t;
328 if (IP6T_MATCH_ITERATE(e, do_match,
330 offset, protoff, &hotdrop) != 0)
333 ADD_COUNTER(e->counters,
334 ntohs((*pskb)->nh.ipv6h->payload_len)
338 t = ip6t_get_target(e);
339 IP_NF_ASSERT(t->u.kernel.target);
340 /* Standard target? */
341 if (!t->u.kernel.target->target) {
344 v = ((struct ip6t_standard_target *)t)->verdict;
346 /* Pop from stack? */
347 if (v != IP6T_RETURN) {
348 verdict = (unsigned)(-v) - 1;
352 back = get_entry(table_base,
356 if (table_base + v != (void *)e + e->next_offset
357 && !(e->ipv6.flags & IP6T_F_GOTO)) {
358 /* Save old back ptr in next entry */
359 struct ip6t_entry *next
360 = (void *)e + e->next_offset;
362 = (void *)back - table_base;
363 /* set back pointer to next entry */
367 e = get_entry(table_base, v);
369 /* Targets which reenter must return
371 #ifdef CONFIG_NETFILTER_DEBUG
372 ((struct ip6t_entry *)table_base)->comefrom
375 verdict = t->u.kernel.target->target(pskb,
381 #ifdef CONFIG_NETFILTER_DEBUG
382 if (((struct ip6t_entry *)table_base)->comefrom
384 && verdict == IP6T_CONTINUE) {
385 printk("Target %s reentered!\n",
386 t->u.kernel.target->name);
389 ((struct ip6t_entry *)table_base)->comefrom
392 if (verdict == IP6T_CONTINUE)
393 e = (void *)e + e->next_offset;
401 e = (void *)e + e->next_offset;
405 #ifdef CONFIG_NETFILTER_DEBUG
406 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
408 read_unlock_bh(&table->lock);
410 #ifdef DEBUG_ALLOW_ALL
419 /* All zeroes == unconditional rule. */
421 unconditional(const struct ip6t_ip6 *ipv6)
425 for (i = 0; i < sizeof(*ipv6); i++)
426 if (((char *)ipv6)[i])
429 return (i == sizeof(*ipv6));
432 /* Figures out from what hook each rule can be called: returns 0 if
433 there are loops. Puts hook bitmask in comefrom. */
435 mark_source_chains(struct xt_table_info *newinfo,
436 unsigned int valid_hooks, void *entry0)
440 /* No recursion; use packet counter to save back ptrs (reset
441 to 0 as we leave), and comefrom to save source hook bitmask */
442 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
443 unsigned int pos = newinfo->hook_entry[hook];
445 = (struct ip6t_entry *)(entry0 + pos);
447 if (!(valid_hooks & (1 << hook)))
450 /* Set initial back pointer. */
451 e->counters.pcnt = pos;
454 struct ip6t_standard_target *t
455 = (void *)ip6t_get_target(e);
457 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
458 printk("iptables: loop hook %u pos %u %08X.\n",
459 hook, pos, e->comefrom);
463 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
465 /* Unconditional return/END. */
466 if (e->target_offset == sizeof(struct ip6t_entry)
467 && (strcmp(t->target.u.user.name,
468 IP6T_STANDARD_TARGET) == 0)
470 && unconditional(&e->ipv6)) {
471 unsigned int oldpos, size;
473 /* Return: backtrack through the last
476 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
477 #ifdef DEBUG_IP_FIREWALL_USER
479 & (1 << NF_IP6_NUMHOOKS)) {
480 duprintf("Back unset "
487 pos = e->counters.pcnt;
488 e->counters.pcnt = 0;
490 /* We're at the start. */
494 e = (struct ip6t_entry *)
496 } while (oldpos == pos + e->next_offset);
499 size = e->next_offset;
500 e = (struct ip6t_entry *)
501 (entry0 + pos + size);
502 e->counters.pcnt = pos;
505 int newpos = t->verdict;
507 if (strcmp(t->target.u.user.name,
508 IP6T_STANDARD_TARGET) == 0
510 /* This a jump; chase it. */
511 duprintf("Jump rule %u -> %u\n",
514 /* ... this is a fallthru */
515 newpos = pos + e->next_offset;
517 e = (struct ip6t_entry *)
519 e->counters.pcnt = pos;
524 duprintf("Finished chain %u\n", hook);
530 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
532 if (i && (*i)-- == 0)
535 if (m->u.kernel.match->destroy)
536 m->u.kernel.match->destroy(m->data,
537 m->u.match_size - sizeof(*m));
538 module_put(m->u.kernel.match->me);
543 standard_check(const struct ip6t_entry_target *t,
544 unsigned int max_offset)
546 struct ip6t_standard_target *targ = (void *)t;
548 /* Check standard info. */
550 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
551 duprintf("standard_check: target size %u != %u\n",
553 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
557 if (targ->verdict >= 0
558 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
559 duprintf("ip6t_standard_check: bad verdict (%i)\n",
564 if (targ->verdict < -NF_MAX_VERDICT - 1) {
565 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
573 check_match(struct ip6t_entry_match *m,
575 const struct ip6t_ip6 *ipv6,
576 unsigned int hookmask,
579 struct ip6t_match *match;
581 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
583 "ip6t_%s", m->u.user.name);
584 if (IS_ERR(match) || !match) {
585 duprintf("check_match: `%s' not found\n", m->u.user.name);
586 return match ? PTR_ERR(match) : -ENOENT;
588 m->u.kernel.match = match;
590 if (m->u.kernel.match->checkentry
591 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
592 m->u.match_size - sizeof(*m),
594 module_put(m->u.kernel.match->me);
595 duprintf("ip_tables: check failed for `%s'.\n",
596 m->u.kernel.match->name);
604 static struct ip6t_target ip6t_standard_target;
607 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
610 struct ip6t_entry_target *t;
611 struct ip6t_target *target;
615 if (!ip6_checkentry(&e->ipv6)) {
616 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
621 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
623 goto cleanup_matches;
625 t = ip6t_get_target(e);
626 target = try_then_request_module(xt_find_target(AF_INET6,
629 "ip6t_%s", t->u.user.name);
630 if (IS_ERR(target) || !target) {
631 duprintf("check_entry: `%s' not found\n", t->u.user.name);
632 ret = target ? PTR_ERR(target) : -ENOENT;
633 goto cleanup_matches;
635 t->u.kernel.target = target;
637 if (t->u.kernel.target == &ip6t_standard_target) {
638 if (!standard_check(t, size)) {
640 goto cleanup_matches;
642 } else if (t->u.kernel.target->checkentry
643 && !t->u.kernel.target->checkentry(name, e, t->data,
647 module_put(t->u.kernel.target->me);
648 duprintf("ip_tables: check failed for `%s'.\n",
649 t->u.kernel.target->name);
651 goto cleanup_matches;
658 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
663 check_entry_size_and_hooks(struct ip6t_entry *e,
664 struct xt_table_info *newinfo,
666 unsigned char *limit,
667 const unsigned int *hook_entries,
668 const unsigned int *underflows,
673 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
674 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
675 duprintf("Bad offset %p\n", e);
680 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
681 duprintf("checking: element %p size %u\n",
686 /* Check hooks & underflows */
687 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
688 if ((unsigned char *)e - base == hook_entries[h])
689 newinfo->hook_entry[h] = hook_entries[h];
690 if ((unsigned char *)e - base == underflows[h])
691 newinfo->underflow[h] = underflows[h];
694 /* FIXME: underflows must be unconditional, standard verdicts
695 < 0 (not IP6T_RETURN). --RR */
697 /* Clear counters and comefrom */
698 e->counters = ((struct xt_counters) { 0, 0 });
706 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
708 struct ip6t_entry_target *t;
710 if (i && (*i)-- == 0)
713 /* Cleanup all matches */
714 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
715 t = ip6t_get_target(e);
716 if (t->u.kernel.target->destroy)
717 t->u.kernel.target->destroy(t->data,
718 t->u.target_size - sizeof(*t));
719 module_put(t->u.kernel.target->me);
723 /* Checks and translates the user-supplied table segment (held in
726 translate_table(const char *name,
727 unsigned int valid_hooks,
728 struct xt_table_info *newinfo,
732 const unsigned int *hook_entries,
733 const unsigned int *underflows)
738 newinfo->size = size;
739 newinfo->number = number;
741 /* Init all hooks to impossible value. */
742 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
743 newinfo->hook_entry[i] = 0xFFFFFFFF;
744 newinfo->underflow[i] = 0xFFFFFFFF;
747 duprintf("translate_table: size %u\n", newinfo->size);
749 /* Walk through entries, checking offsets. */
750 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
751 check_entry_size_and_hooks,
755 hook_entries, underflows, &i);
760 duprintf("translate_table: %u not %u entries\n",
765 /* Check hooks all assigned */
766 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
767 /* Only hooks which are valid */
768 if (!(valid_hooks & (1 << i)))
770 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
771 duprintf("Invalid hook entry %u %u\n",
775 if (newinfo->underflow[i] == 0xFFFFFFFF) {
776 duprintf("Invalid underflow %u %u\n",
782 if (!mark_source_chains(newinfo, valid_hooks, entry0))
785 /* Finally, each sanity check must pass */
787 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
788 check_entry, name, size, &i);
791 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
796 /* And one copy for every other CPU */
798 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
799 memcpy(newinfo->entries[i], entry0, newinfo->size);
807 add_entry_to_counter(const struct ip6t_entry *e,
808 struct xt_counters total[],
811 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
818 set_entry_to_counter(const struct ip6t_entry *e,
819 struct ip6t_counters total[],
822 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
829 get_counters(const struct xt_table_info *t,
830 struct xt_counters counters[])
836 /* Instead of clearing (by a previous call to memset())
837 * the counters and using adds, we set the counters
838 * with data used by 'current' CPU
839 * We dont care about preemption here.
841 curcpu = raw_smp_processor_id();
844 IP6T_ENTRY_ITERATE(t->entries[curcpu],
846 set_entry_to_counter,
854 IP6T_ENTRY_ITERATE(t->entries[cpu],
856 add_entry_to_counter,
863 copy_entries_to_user(unsigned int total_size,
864 struct xt_table *table,
865 void __user *userptr)
867 unsigned int off, num, countersize;
868 struct ip6t_entry *e;
869 struct xt_counters *counters;
870 struct xt_table_info *private = table->private;
874 /* We need atomic snapshot of counters: rest doesn't change
875 (other than comefrom, which userspace doesn't care
877 countersize = sizeof(struct xt_counters) * private->number;
878 counters = vmalloc(countersize);
880 if (counters == NULL)
883 /* First, sum counters... */
884 write_lock_bh(&table->lock);
885 get_counters(private, counters);
886 write_unlock_bh(&table->lock);
888 /* choose the copy that is on ourc node/cpu */
889 loc_cpu_entry = private->entries[raw_smp_processor_id()];
890 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
895 /* FIXME: use iterator macros --RR */
896 /* ... then go back and fix counters and names */
897 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
899 struct ip6t_entry_match *m;
900 struct ip6t_entry_target *t;
902 e = (struct ip6t_entry *)(loc_cpu_entry + off);
903 if (copy_to_user(userptr + off
904 + offsetof(struct ip6t_entry, counters),
906 sizeof(counters[num])) != 0) {
911 for (i = sizeof(struct ip6t_entry);
912 i < e->target_offset;
913 i += m->u.match_size) {
916 if (copy_to_user(userptr + off + i
917 + offsetof(struct ip6t_entry_match,
919 m->u.kernel.match->name,
920 strlen(m->u.kernel.match->name)+1)
927 t = ip6t_get_target(e);
928 if (copy_to_user(userptr + off + e->target_offset
929 + offsetof(struct ip6t_entry_target,
931 t->u.kernel.target->name,
932 strlen(t->u.kernel.target->name)+1) != 0) {
944 get_entries(const struct ip6t_get_entries *entries,
945 struct ip6t_get_entries __user *uptr)
950 t = xt_find_table_lock(AF_INET6, entries->name);
951 if (t && !IS_ERR(t)) {
952 struct xt_table_info *private = t->private;
953 duprintf("t->private->number = %u\n", private->number);
954 if (entries->size == private->size)
955 ret = copy_entries_to_user(private->size,
956 t, uptr->entrytable);
958 duprintf("get_entries: I've got %u not %u!\n",
959 private->size, entries->size);
965 ret = t ? PTR_ERR(t) : -ENOENT;
971 do_replace(void __user *user, unsigned int len)
974 struct ip6t_replace tmp;
976 struct xt_table_info *newinfo, *oldinfo;
977 struct xt_counters *counters;
978 void *loc_cpu_entry, *loc_cpu_old_entry;
980 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
984 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
987 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
990 newinfo = xt_alloc_table_info(tmp.size);
994 /* choose the copy that is on our node/cpu */
995 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
996 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1002 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1008 ret = translate_table(tmp.name, tmp.valid_hooks,
1009 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1010 tmp.hook_entry, tmp.underflow);
1012 goto free_newinfo_counters;
1014 duprintf("ip_tables: Translated table\n");
1016 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1017 "ip6table_%s", tmp.name);
1018 if (!t || IS_ERR(t)) {
1019 ret = t ? PTR_ERR(t) : -ENOENT;
1020 goto free_newinfo_counters_untrans;
1024 if (tmp.valid_hooks != t->valid_hooks) {
1025 duprintf("Valid hook crap: %08X vs %08X\n",
1026 tmp.valid_hooks, t->valid_hooks);
1031 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1035 /* Update module usage count based on number of rules */
1036 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1037 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1038 if ((oldinfo->number > oldinfo->initial_entries) ||
1039 (newinfo->number <= oldinfo->initial_entries))
1041 if ((oldinfo->number > oldinfo->initial_entries) &&
1042 (newinfo->number <= oldinfo->initial_entries))
1045 /* Get the old counters. */
1046 get_counters(oldinfo, counters);
1047 /* Decrease module usage counts and free resource */
1048 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1049 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1050 xt_free_table_info(oldinfo);
1051 if (copy_to_user(tmp.counters, counters,
1052 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1061 free_newinfo_counters_untrans:
1062 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1063 free_newinfo_counters:
1066 xt_free_table_info(newinfo);
1070 /* We're lazy, and add to the first CPU; overflow works its fey magic
1071 * and everything is OK. */
1073 add_counter_to_entry(struct ip6t_entry *e,
1074 const struct xt_counters addme[],
1078 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1080 (long unsigned int)e->counters.pcnt,
1081 (long unsigned int)e->counters.bcnt,
1082 (long unsigned int)addme[*i].pcnt,
1083 (long unsigned int)addme[*i].bcnt);
1086 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1093 do_add_counters(void __user *user, unsigned int len)
1096 struct xt_counters_info tmp, *paddc;
1097 struct xt_table_info *private;
1100 void *loc_cpu_entry;
1102 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1105 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1108 paddc = vmalloc(len);
1112 if (copy_from_user(paddc, user, len) != 0) {
1117 t = xt_find_table_lock(AF_INET6, tmp.name);
1118 if (!t || IS_ERR(t)) {
1119 ret = t ? PTR_ERR(t) : -ENOENT;
1123 write_lock_bh(&t->lock);
1124 private = t->private;
1125 if (private->number != tmp.num_counters) {
1127 goto unlock_up_free;
1131 /* Choose the copy that is on our node */
1132 loc_cpu_entry = private->entries[smp_processor_id()];
1133 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1135 add_counter_to_entry,
1139 write_unlock_bh(&t->lock);
1149 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1153 if (!capable(CAP_NET_ADMIN))
1157 case IP6T_SO_SET_REPLACE:
1158 ret = do_replace(user, len);
1161 case IP6T_SO_SET_ADD_COUNTERS:
1162 ret = do_add_counters(user, len);
1166 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1174 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1178 if (!capable(CAP_NET_ADMIN))
1182 case IP6T_SO_GET_INFO: {
1183 char name[IP6T_TABLE_MAXNAMELEN];
1186 if (*len != sizeof(struct ip6t_getinfo)) {
1187 duprintf("length %u != %u\n", *len,
1188 sizeof(struct ip6t_getinfo));
1193 if (copy_from_user(name, user, sizeof(name)) != 0) {
1197 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1199 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1200 "ip6table_%s", name);
1201 if (t && !IS_ERR(t)) {
1202 struct ip6t_getinfo info;
1203 struct xt_table_info *private = t->private;
1205 info.valid_hooks = t->valid_hooks;
1206 memcpy(info.hook_entry, private->hook_entry,
1207 sizeof(info.hook_entry));
1208 memcpy(info.underflow, private->underflow,
1209 sizeof(info.underflow));
1210 info.num_entries = private->number;
1211 info.size = private->size;
1212 memcpy(info.name, name, sizeof(info.name));
1214 if (copy_to_user(user, &info, *len) != 0)
1221 ret = t ? PTR_ERR(t) : -ENOENT;
1225 case IP6T_SO_GET_ENTRIES: {
1226 struct ip6t_get_entries get;
1228 if (*len < sizeof(get)) {
1229 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1231 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1233 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1234 duprintf("get_entries: %u != %u\n", *len,
1235 sizeof(struct ip6t_get_entries) + get.size);
1238 ret = get_entries(&get, user);
1242 case IP6T_SO_GET_REVISION_MATCH:
1243 case IP6T_SO_GET_REVISION_TARGET: {
1244 struct ip6t_get_revision rev;
1247 if (*len != sizeof(rev)) {
1251 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1256 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1261 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1264 "ip6t_%s", rev.name);
1269 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1276 int ip6t_register_table(struct xt_table *table,
1277 const struct ip6t_replace *repl)
1280 struct xt_table_info *newinfo;
1281 static struct xt_table_info bootstrap
1282 = { 0, 0, 0, { 0 }, { 0 }, { } };
1283 void *loc_cpu_entry;
1285 newinfo = xt_alloc_table_info(repl->size);
1289 /* choose the copy on our node/cpu */
1290 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1291 memcpy(loc_cpu_entry, repl->entries, repl->size);
1293 ret = translate_table(table->name, table->valid_hooks,
1294 newinfo, loc_cpu_entry, repl->size,
1299 xt_free_table_info(newinfo);
1303 if (xt_register_table(table, &bootstrap, newinfo) != 0) {
1304 xt_free_table_info(newinfo);
1311 void ip6t_unregister_table(struct xt_table *table)
1313 struct xt_table_info *private;
1314 void *loc_cpu_entry;
1316 private = xt_unregister_table(table);
1318 /* Decrease module usage counts and free resources */
1319 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1320 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1321 xt_free_table_info(private);
1324 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1326 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1327 u_int8_t type, u_int8_t code,
1330 return (type == test_type && code >= min_code && code <= max_code)
1335 icmp6_match(const struct sk_buff *skb,
1336 const struct net_device *in,
1337 const struct net_device *out,
1338 const void *matchinfo,
1340 unsigned int protoff,
1343 struct icmp6hdr _icmp, *ic;
1344 const struct ip6t_icmp *icmpinfo = matchinfo;
1346 /* Must not be a fragment. */
1350 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1352 /* We've been asked to examine this packet, and we
1353 can't. Hence, no choice but to drop. */
1354 duprintf("Dropping evil ICMP tinygram.\n");
1359 return icmp6_type_code_match(icmpinfo->type,
1362 ic->icmp6_type, ic->icmp6_code,
1363 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1366 /* Called when user tries to insert an entry of this type. */
1368 icmp6_checkentry(const char *tablename,
1371 unsigned int matchsize,
1372 unsigned int hook_mask)
1374 const struct ip6t_ip6 *ipv6 = entry;
1375 const struct ip6t_icmp *icmpinfo = matchinfo;
1377 /* Must specify proto == ICMP, and no unknown invflags */
1378 return ipv6->proto == IPPROTO_ICMPV6
1379 && !(ipv6->invflags & IP6T_INV_PROTO)
1380 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1381 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1384 /* The built-in targets: standard (NULL) and error. */
1385 static struct ip6t_target ip6t_standard_target = {
1386 .name = IP6T_STANDARD_TARGET,
1389 static struct ip6t_target ip6t_error_target = {
1390 .name = IP6T_ERROR_TARGET,
1391 .target = ip6t_error,
1394 static struct nf_sockopt_ops ip6t_sockopts = {
1396 .set_optmin = IP6T_BASE_CTL,
1397 .set_optmax = IP6T_SO_SET_MAX+1,
1398 .set = do_ip6t_set_ctl,
1399 .get_optmin = IP6T_BASE_CTL,
1400 .get_optmax = IP6T_SO_GET_MAX+1,
1401 .get = do_ip6t_get_ctl,
1404 static struct ip6t_match icmp6_matchstruct = {
1406 .match = &icmp6_match,
1407 .checkentry = &icmp6_checkentry,
1410 static int __init init(void)
1414 xt_proto_init(AF_INET6);
1416 /* Noone else will be downing sem now, so we won't sleep */
1417 xt_register_target(AF_INET6, &ip6t_standard_target);
1418 xt_register_target(AF_INET6, &ip6t_error_target);
1419 xt_register_match(AF_INET6, &icmp6_matchstruct);
1421 /* Register setsockopt */
1422 ret = nf_register_sockopt(&ip6t_sockopts);
1424 duprintf("Unable to register sockopts.\n");
1425 xt_proto_fini(AF_INET6);
1429 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1433 static void __exit fini(void)
1435 nf_unregister_sockopt(&ip6t_sockopts);
1436 xt_unregister_match(AF_INET6, &icmp6_matchstruct);
1437 xt_unregister_target(AF_INET6, &ip6t_error_target);
1438 xt_unregister_target(AF_INET6, &ip6t_standard_target);
1439 xt_proto_fini(AF_INET6);
1443 * find the offset to specified header or the protocol number of last header
1444 * if target < 0. "last header" is transport protocol header, ESP, or
1447 * If target header is found, its offset is set in *offset and return protocol
1448 * number. Otherwise, return -1.
1450 * If the first fragment doesn't contain the final protocol header or
1451 * NEXTHDR_NONE it is considered invalid.
1453 * Note that non-1st fragment is special case that "the protocol number
1454 * of last header" is "next header" field in Fragment header. In this case,
1455 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1459 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1460 int target, unsigned short *fragoff)
1462 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1463 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1464 unsigned int len = skb->len - start;
1469 while (nexthdr != target) {
1470 struct ipv6_opt_hdr _hdr, *hp;
1471 unsigned int hdrlen;
1473 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1479 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1482 if (nexthdr == NEXTHDR_FRAGMENT) {
1483 unsigned short _frag_off, *fp;
1484 fp = skb_header_pointer(skb,
1485 start+offsetof(struct frag_hdr,
1492 _frag_off = ntohs(*fp) & ~0x7;
1495 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1496 nexthdr == NEXTHDR_NONE)) {
1498 *fragoff = _frag_off;
1504 } else if (nexthdr == NEXTHDR_AUTH)
1505 hdrlen = (hp->hdrlen + 2) << 2;
1507 hdrlen = ipv6_optlen(hp);
1509 nexthdr = hp->nexthdr;
1518 EXPORT_SYMBOL(ip6t_register_table);
1519 EXPORT_SYMBOL(ip6t_unregister_table);
1520 EXPORT_SYMBOL(ip6t_do_table);
1521 EXPORT_SYMBOL(ip6t_ext_hdr);
1522 EXPORT_SYMBOL(ipv6_find_hdr);
1523 EXPORT_SYMBOL(ip6_masked_addrcmp);