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 <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 #ifdef CONFIG_NETFILTER_DEBUG
292 /* Check noone else using our table */
293 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
294 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
295 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
298 &((struct ip6t_entry *)table_base)->comefrom,
299 ((struct ip6t_entry *)table_base)->comefrom);
301 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
304 /* For return from builtin chain */
305 back = get_entry(table_base, private->underflow[hook]);
310 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
311 &protoff, &offset)) {
312 struct ip6t_entry_target *t;
314 if (IP6T_MATCH_ITERATE(e, do_match,
316 offset, protoff, &hotdrop) != 0)
319 ADD_COUNTER(e->counters,
320 ntohs((*pskb)->nh.ipv6h->payload_len)
324 t = ip6t_get_target(e);
325 IP_NF_ASSERT(t->u.kernel.target);
326 /* Standard target? */
327 if (!t->u.kernel.target->target) {
330 v = ((struct ip6t_standard_target *)t)->verdict;
332 /* Pop from stack? */
333 if (v != IP6T_RETURN) {
334 verdict = (unsigned)(-v) - 1;
338 back = get_entry(table_base,
342 if (table_base + v != (void *)e + e->next_offset
343 && !(e->ipv6.flags & IP6T_F_GOTO)) {
344 /* Save old back ptr in next entry */
345 struct ip6t_entry *next
346 = (void *)e + e->next_offset;
348 = (void *)back - table_base;
349 /* set back pointer to next entry */
353 e = get_entry(table_base, v);
355 /* Targets which reenter must return
357 #ifdef CONFIG_NETFILTER_DEBUG
358 ((struct ip6t_entry *)table_base)->comefrom
361 verdict = t->u.kernel.target->target(pskb,
368 #ifdef CONFIG_NETFILTER_DEBUG
369 if (((struct ip6t_entry *)table_base)->comefrom
371 && verdict == IP6T_CONTINUE) {
372 printk("Target %s reentered!\n",
373 t->u.kernel.target->name);
376 ((struct ip6t_entry *)table_base)->comefrom
379 if (verdict == IP6T_CONTINUE)
380 e = (void *)e + e->next_offset;
388 e = (void *)e + e->next_offset;
392 #ifdef CONFIG_NETFILTER_DEBUG
393 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
395 read_unlock_bh(&table->lock);
397 #ifdef DEBUG_ALLOW_ALL
406 /* All zeroes == unconditional rule. */
408 unconditional(const struct ip6t_ip6 *ipv6)
412 for (i = 0; i < sizeof(*ipv6); i++)
413 if (((char *)ipv6)[i])
416 return (i == sizeof(*ipv6));
419 /* Figures out from what hook each rule can be called: returns 0 if
420 there are loops. Puts hook bitmask in comefrom. */
422 mark_source_chains(struct xt_table_info *newinfo,
423 unsigned int valid_hooks, void *entry0)
427 /* No recursion; use packet counter to save back ptrs (reset
428 to 0 as we leave), and comefrom to save source hook bitmask */
429 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
430 unsigned int pos = newinfo->hook_entry[hook];
432 = (struct ip6t_entry *)(entry0 + pos);
434 if (!(valid_hooks & (1 << hook)))
437 /* Set initial back pointer. */
438 e->counters.pcnt = pos;
441 struct ip6t_standard_target *t
442 = (void *)ip6t_get_target(e);
444 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
445 printk("iptables: loop hook %u pos %u %08X.\n",
446 hook, pos, e->comefrom);
450 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
452 /* Unconditional return/END. */
453 if (e->target_offset == sizeof(struct ip6t_entry)
454 && (strcmp(t->target.u.user.name,
455 IP6T_STANDARD_TARGET) == 0)
457 && unconditional(&e->ipv6)) {
458 unsigned int oldpos, size;
460 /* Return: backtrack through the last
463 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
464 #ifdef DEBUG_IP_FIREWALL_USER
466 & (1 << NF_IP6_NUMHOOKS)) {
467 duprintf("Back unset "
474 pos = e->counters.pcnt;
475 e->counters.pcnt = 0;
477 /* We're at the start. */
481 e = (struct ip6t_entry *)
483 } while (oldpos == pos + e->next_offset);
486 size = e->next_offset;
487 e = (struct ip6t_entry *)
488 (entry0 + pos + size);
489 e->counters.pcnt = pos;
492 int newpos = t->verdict;
494 if (strcmp(t->target.u.user.name,
495 IP6T_STANDARD_TARGET) == 0
497 /* This a jump; chase it. */
498 duprintf("Jump rule %u -> %u\n",
501 /* ... this is a fallthru */
502 newpos = pos + e->next_offset;
504 e = (struct ip6t_entry *)
506 e->counters.pcnt = pos;
511 duprintf("Finished chain %u\n", hook);
517 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
519 if (i && (*i)-- == 0)
522 if (m->u.kernel.match->destroy)
523 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
524 m->u.match_size - sizeof(*m));
525 module_put(m->u.kernel.match->me);
530 standard_check(const struct ip6t_entry_target *t,
531 unsigned int max_offset)
533 struct ip6t_standard_target *targ = (void *)t;
535 /* Check standard info. */
536 if (targ->verdict >= 0
537 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
538 duprintf("ip6t_standard_check: bad verdict (%i)\n",
542 if (targ->verdict < -NF_MAX_VERDICT - 1) {
543 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
551 check_match(struct ip6t_entry_match *m,
553 const struct ip6t_ip6 *ipv6,
554 unsigned int hookmask,
557 struct ip6t_match *match;
560 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
562 "ip6t_%s", m->u.user.name);
563 if (IS_ERR(match) || !match) {
564 duprintf("check_match: `%s' not found\n", m->u.user.name);
565 return match ? PTR_ERR(match) : -ENOENT;
567 m->u.kernel.match = match;
569 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
570 name, hookmask, ipv6->proto,
571 ipv6->invflags & IP6T_INV_PROTO);
575 if (m->u.kernel.match->checkentry
576 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
577 m->u.match_size - sizeof(*m),
579 duprintf("ip_tables: check failed for `%s'.\n",
580 m->u.kernel.match->name);
588 module_put(m->u.kernel.match->me);
592 static struct ip6t_target ip6t_standard_target;
595 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
598 struct ip6t_entry_target *t;
599 struct ip6t_target *target;
603 if (!ip6_checkentry(&e->ipv6)) {
604 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
609 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
611 goto cleanup_matches;
613 t = ip6t_get_target(e);
614 target = try_then_request_module(xt_find_target(AF_INET6,
617 "ip6t_%s", t->u.user.name);
618 if (IS_ERR(target) || !target) {
619 duprintf("check_entry: `%s' not found\n", t->u.user.name);
620 ret = target ? PTR_ERR(target) : -ENOENT;
621 goto cleanup_matches;
623 t->u.kernel.target = target;
625 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
626 name, e->comefrom, e->ipv6.proto,
627 e->ipv6.invflags & IP6T_INV_PROTO);
631 if (t->u.kernel.target == &ip6t_standard_target) {
632 if (!standard_check(t, size)) {
634 goto cleanup_matches;
636 } else if (t->u.kernel.target->checkentry
637 && !t->u.kernel.target->checkentry(name, e, target, t->data,
641 duprintf("ip_tables: check failed for `%s'.\n",
642 t->u.kernel.target->name);
650 module_put(t->u.kernel.target->me);
652 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
657 check_entry_size_and_hooks(struct ip6t_entry *e,
658 struct xt_table_info *newinfo,
660 unsigned char *limit,
661 const unsigned int *hook_entries,
662 const unsigned int *underflows,
667 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
668 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
669 duprintf("Bad offset %p\n", e);
674 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
675 duprintf("checking: element %p size %u\n",
680 /* Check hooks & underflows */
681 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
682 if ((unsigned char *)e - base == hook_entries[h])
683 newinfo->hook_entry[h] = hook_entries[h];
684 if ((unsigned char *)e - base == underflows[h])
685 newinfo->underflow[h] = underflows[h];
688 /* FIXME: underflows must be unconditional, standard verdicts
689 < 0 (not IP6T_RETURN). --RR */
691 /* Clear counters and comefrom */
692 e->counters = ((struct xt_counters) { 0, 0 });
700 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
702 struct ip6t_entry_target *t;
704 if (i && (*i)-- == 0)
707 /* Cleanup all matches */
708 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
709 t = ip6t_get_target(e);
710 if (t->u.kernel.target->destroy)
711 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
712 t->u.target_size - sizeof(*t));
713 module_put(t->u.kernel.target->me);
717 /* Checks and translates the user-supplied table segment (held in
720 translate_table(const char *name,
721 unsigned int valid_hooks,
722 struct xt_table_info *newinfo,
726 const unsigned int *hook_entries,
727 const unsigned int *underflows)
732 newinfo->size = size;
733 newinfo->number = number;
735 /* Init all hooks to impossible value. */
736 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
737 newinfo->hook_entry[i] = 0xFFFFFFFF;
738 newinfo->underflow[i] = 0xFFFFFFFF;
741 duprintf("translate_table: size %u\n", newinfo->size);
743 /* Walk through entries, checking offsets. */
744 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
745 check_entry_size_and_hooks,
749 hook_entries, underflows, &i);
754 duprintf("translate_table: %u not %u entries\n",
759 /* Check hooks all assigned */
760 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
761 /* Only hooks which are valid */
762 if (!(valid_hooks & (1 << i)))
764 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
765 duprintf("Invalid hook entry %u %u\n",
769 if (newinfo->underflow[i] == 0xFFFFFFFF) {
770 duprintf("Invalid underflow %u %u\n",
776 if (!mark_source_chains(newinfo, valid_hooks, entry0))
779 /* Finally, each sanity check must pass */
781 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
782 check_entry, name, size, &i);
785 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
790 /* And one copy for every other CPU */
792 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
793 memcpy(newinfo->entries[i], entry0, newinfo->size);
801 add_entry_to_counter(const struct ip6t_entry *e,
802 struct xt_counters total[],
805 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
812 set_entry_to_counter(const struct ip6t_entry *e,
813 struct ip6t_counters total[],
816 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
823 get_counters(const struct xt_table_info *t,
824 struct xt_counters counters[])
830 /* Instead of clearing (by a previous call to memset())
831 * the counters and using adds, we set the counters
832 * with data used by 'current' CPU
833 * We dont care about preemption here.
835 curcpu = raw_smp_processor_id();
838 IP6T_ENTRY_ITERATE(t->entries[curcpu],
840 set_entry_to_counter,
848 IP6T_ENTRY_ITERATE(t->entries[cpu],
850 add_entry_to_counter,
857 copy_entries_to_user(unsigned int total_size,
858 struct xt_table *table,
859 void __user *userptr)
861 unsigned int off, num, countersize;
862 struct ip6t_entry *e;
863 struct xt_counters *counters;
864 struct xt_table_info *private = table->private;
868 /* We need atomic snapshot of counters: rest doesn't change
869 (other than comefrom, which userspace doesn't care
871 countersize = sizeof(struct xt_counters) * private->number;
872 counters = vmalloc(countersize);
874 if (counters == NULL)
877 /* First, sum counters... */
878 write_lock_bh(&table->lock);
879 get_counters(private, counters);
880 write_unlock_bh(&table->lock);
882 /* choose the copy that is on ourc node/cpu */
883 loc_cpu_entry = private->entries[raw_smp_processor_id()];
884 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
889 /* FIXME: use iterator macros --RR */
890 /* ... then go back and fix counters and names */
891 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
893 struct ip6t_entry_match *m;
894 struct ip6t_entry_target *t;
896 e = (struct ip6t_entry *)(loc_cpu_entry + off);
897 if (copy_to_user(userptr + off
898 + offsetof(struct ip6t_entry, counters),
900 sizeof(counters[num])) != 0) {
905 for (i = sizeof(struct ip6t_entry);
906 i < e->target_offset;
907 i += m->u.match_size) {
910 if (copy_to_user(userptr + off + i
911 + offsetof(struct ip6t_entry_match,
913 m->u.kernel.match->name,
914 strlen(m->u.kernel.match->name)+1)
921 t = ip6t_get_target(e);
922 if (copy_to_user(userptr + off + e->target_offset
923 + offsetof(struct ip6t_entry_target,
925 t->u.kernel.target->name,
926 strlen(t->u.kernel.target->name)+1) != 0) {
938 get_entries(const struct ip6t_get_entries *entries,
939 struct ip6t_get_entries __user *uptr)
944 t = xt_find_table_lock(AF_INET6, entries->name);
945 if (t && !IS_ERR(t)) {
946 struct xt_table_info *private = t->private;
947 duprintf("t->private->number = %u\n", private->number);
948 if (entries->size == private->size)
949 ret = copy_entries_to_user(private->size,
950 t, uptr->entrytable);
952 duprintf("get_entries: I've got %u not %u!\n",
953 private->size, entries->size);
959 ret = t ? PTR_ERR(t) : -ENOENT;
965 do_replace(void __user *user, unsigned int len)
968 struct ip6t_replace tmp;
970 struct xt_table_info *newinfo, *oldinfo;
971 struct xt_counters *counters;
972 void *loc_cpu_entry, *loc_cpu_old_entry;
974 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
978 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
981 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
984 newinfo = xt_alloc_table_info(tmp.size);
988 /* choose the copy that is on our node/cpu */
989 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
990 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
996 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1002 ret = translate_table(tmp.name, tmp.valid_hooks,
1003 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1004 tmp.hook_entry, tmp.underflow);
1006 goto free_newinfo_counters;
1008 duprintf("ip_tables: Translated table\n");
1010 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1011 "ip6table_%s", tmp.name);
1012 if (!t || IS_ERR(t)) {
1013 ret = t ? PTR_ERR(t) : -ENOENT;
1014 goto free_newinfo_counters_untrans;
1018 if (tmp.valid_hooks != t->valid_hooks) {
1019 duprintf("Valid hook crap: %08X vs %08X\n",
1020 tmp.valid_hooks, t->valid_hooks);
1025 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1029 /* Update module usage count based on number of rules */
1030 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1031 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1032 if ((oldinfo->number > oldinfo->initial_entries) ||
1033 (newinfo->number <= oldinfo->initial_entries))
1035 if ((oldinfo->number > oldinfo->initial_entries) &&
1036 (newinfo->number <= oldinfo->initial_entries))
1039 /* Get the old counters. */
1040 get_counters(oldinfo, counters);
1041 /* Decrease module usage counts and free resource */
1042 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1043 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1044 xt_free_table_info(oldinfo);
1045 if (copy_to_user(tmp.counters, counters,
1046 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1055 free_newinfo_counters_untrans:
1056 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1057 free_newinfo_counters:
1060 xt_free_table_info(newinfo);
1064 /* We're lazy, and add to the first CPU; overflow works its fey magic
1065 * and everything is OK. */
1067 add_counter_to_entry(struct ip6t_entry *e,
1068 const struct xt_counters addme[],
1072 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1074 (long unsigned int)e->counters.pcnt,
1075 (long unsigned int)e->counters.bcnt,
1076 (long unsigned int)addme[*i].pcnt,
1077 (long unsigned int)addme[*i].bcnt);
1080 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1087 do_add_counters(void __user *user, unsigned int len)
1090 struct xt_counters_info tmp, *paddc;
1091 struct xt_table_info *private;
1094 void *loc_cpu_entry;
1096 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1099 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1102 paddc = vmalloc(len);
1106 if (copy_from_user(paddc, user, len) != 0) {
1111 t = xt_find_table_lock(AF_INET6, tmp.name);
1112 if (!t || IS_ERR(t)) {
1113 ret = t ? PTR_ERR(t) : -ENOENT;
1117 write_lock_bh(&t->lock);
1118 private = t->private;
1119 if (private->number != paddc->num_counters) {
1121 goto unlock_up_free;
1125 /* Choose the copy that is on our node */
1126 loc_cpu_entry = private->entries[smp_processor_id()];
1127 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1129 add_counter_to_entry,
1133 write_unlock_bh(&t->lock);
1143 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1147 if (!capable(CAP_NET_ADMIN))
1151 case IP6T_SO_SET_REPLACE:
1152 ret = do_replace(user, len);
1155 case IP6T_SO_SET_ADD_COUNTERS:
1156 ret = do_add_counters(user, len);
1160 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1168 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1172 if (!capable(CAP_NET_ADMIN))
1176 case IP6T_SO_GET_INFO: {
1177 char name[IP6T_TABLE_MAXNAMELEN];
1180 if (*len != sizeof(struct ip6t_getinfo)) {
1181 duprintf("length %u != %u\n", *len,
1182 sizeof(struct ip6t_getinfo));
1187 if (copy_from_user(name, user, sizeof(name)) != 0) {
1191 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1193 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1194 "ip6table_%s", name);
1195 if (t && !IS_ERR(t)) {
1196 struct ip6t_getinfo info;
1197 struct xt_table_info *private = t->private;
1199 info.valid_hooks = t->valid_hooks;
1200 memcpy(info.hook_entry, private->hook_entry,
1201 sizeof(info.hook_entry));
1202 memcpy(info.underflow, private->underflow,
1203 sizeof(info.underflow));
1204 info.num_entries = private->number;
1205 info.size = private->size;
1206 memcpy(info.name, name, sizeof(info.name));
1208 if (copy_to_user(user, &info, *len) != 0)
1215 ret = t ? PTR_ERR(t) : -ENOENT;
1219 case IP6T_SO_GET_ENTRIES: {
1220 struct ip6t_get_entries get;
1222 if (*len < sizeof(get)) {
1223 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1225 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1227 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1228 duprintf("get_entries: %u != %u\n", *len,
1229 sizeof(struct ip6t_get_entries) + get.size);
1232 ret = get_entries(&get, user);
1236 case IP6T_SO_GET_REVISION_MATCH:
1237 case IP6T_SO_GET_REVISION_TARGET: {
1238 struct ip6t_get_revision rev;
1241 if (*len != sizeof(rev)) {
1245 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1250 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1255 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1258 "ip6t_%s", rev.name);
1263 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1270 int ip6t_register_table(struct xt_table *table,
1271 const struct ip6t_replace *repl)
1274 struct xt_table_info *newinfo;
1275 static struct xt_table_info bootstrap
1276 = { 0, 0, 0, { 0 }, { 0 }, { } };
1277 void *loc_cpu_entry;
1279 newinfo = xt_alloc_table_info(repl->size);
1283 /* choose the copy on our node/cpu */
1284 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1285 memcpy(loc_cpu_entry, repl->entries, repl->size);
1287 ret = translate_table(table->name, table->valid_hooks,
1288 newinfo, loc_cpu_entry, repl->size,
1293 xt_free_table_info(newinfo);
1297 if (xt_register_table(table, &bootstrap, newinfo) != 0) {
1298 xt_free_table_info(newinfo);
1305 void ip6t_unregister_table(struct xt_table *table)
1307 struct xt_table_info *private;
1308 void *loc_cpu_entry;
1310 private = xt_unregister_table(table);
1312 /* Decrease module usage counts and free resources */
1313 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1314 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1315 xt_free_table_info(private);
1318 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1320 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1321 u_int8_t type, u_int8_t code,
1324 return (type == test_type && code >= min_code && code <= max_code)
1329 icmp6_match(const struct sk_buff *skb,
1330 const struct net_device *in,
1331 const struct net_device *out,
1332 const struct xt_match *match,
1333 const void *matchinfo,
1335 unsigned int protoff,
1338 struct icmp6hdr _icmp, *ic;
1339 const struct ip6t_icmp *icmpinfo = matchinfo;
1341 /* Must not be a fragment. */
1345 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1347 /* We've been asked to examine this packet, and we
1348 can't. Hence, no choice but to drop. */
1349 duprintf("Dropping evil ICMP tinygram.\n");
1354 return icmp6_type_code_match(icmpinfo->type,
1357 ic->icmp6_type, ic->icmp6_code,
1358 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1361 /* Called when user tries to insert an entry of this type. */
1363 icmp6_checkentry(const char *tablename,
1365 const struct xt_match *match,
1367 unsigned int matchsize,
1368 unsigned int hook_mask)
1370 const struct ip6t_icmp *icmpinfo = matchinfo;
1372 /* Must specify no unknown invflags */
1373 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1376 /* The built-in targets: standard (NULL) and error. */
1377 static struct ip6t_target ip6t_standard_target = {
1378 .name = IP6T_STANDARD_TARGET,
1379 .targetsize = sizeof(int),
1383 static struct ip6t_target ip6t_error_target = {
1384 .name = IP6T_ERROR_TARGET,
1385 .target = ip6t_error,
1386 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1390 static struct nf_sockopt_ops ip6t_sockopts = {
1392 .set_optmin = IP6T_BASE_CTL,
1393 .set_optmax = IP6T_SO_SET_MAX+1,
1394 .set = do_ip6t_set_ctl,
1395 .get_optmin = IP6T_BASE_CTL,
1396 .get_optmax = IP6T_SO_GET_MAX+1,
1397 .get = do_ip6t_get_ctl,
1400 static struct ip6t_match icmp6_matchstruct = {
1402 .match = &icmp6_match,
1403 .matchsize = sizeof(struct ip6t_icmp),
1404 .checkentry = icmp6_checkentry,
1405 .proto = IPPROTO_ICMPV6,
1409 static int __init ip6_tables_init(void)
1413 xt_proto_init(AF_INET6);
1415 /* Noone else will be downing sem now, so we won't sleep */
1416 xt_register_target(&ip6t_standard_target);
1417 xt_register_target(&ip6t_error_target);
1418 xt_register_match(&icmp6_matchstruct);
1420 /* Register setsockopt */
1421 ret = nf_register_sockopt(&ip6t_sockopts);
1423 duprintf("Unable to register sockopts.\n");
1424 xt_proto_fini(AF_INET6);
1428 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1432 static void __exit ip6_tables_fini(void)
1434 nf_unregister_sockopt(&ip6t_sockopts);
1435 xt_unregister_match(&icmp6_matchstruct);
1436 xt_unregister_target(&ip6t_error_target);
1437 xt_unregister_target(&ip6t_standard_target);
1438 xt_proto_fini(AF_INET6);
1442 * find the offset to specified header or the protocol number of last header
1443 * if target < 0. "last header" is transport protocol header, ESP, or
1446 * If target header is found, its offset is set in *offset and return protocol
1447 * number. Otherwise, return -1.
1449 * Note that non-1st fragment is special case that "the protocol number
1450 * of last header" is "next header" field in Fragment header. In this case,
1451 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1455 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1456 int target, unsigned short *fragoff)
1458 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1459 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1460 unsigned int len = skb->len - start;
1465 while (nexthdr != target) {
1466 struct ipv6_opt_hdr _hdr, *hp;
1467 unsigned int hdrlen;
1469 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1475 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1478 if (nexthdr == NEXTHDR_FRAGMENT) {
1479 unsigned short _frag_off, *fp;
1480 fp = skb_header_pointer(skb,
1481 start+offsetof(struct frag_hdr,
1488 _frag_off = ntohs(*fp) & ~0x7;
1491 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1492 nexthdr == NEXTHDR_NONE)) {
1494 *fragoff = _frag_off;
1500 } else if (nexthdr == NEXTHDR_AUTH)
1501 hdrlen = (hp->hdrlen + 2) << 2;
1503 hdrlen = ipv6_optlen(hp);
1505 nexthdr = hp->nexthdr;
1514 EXPORT_SYMBOL(ip6t_register_table);
1515 EXPORT_SYMBOL(ip6t_unregister_table);
1516 EXPORT_SYMBOL(ip6t_do_table);
1517 EXPORT_SYMBOL(ip6t_ext_hdr);
1518 EXPORT_SYMBOL(ipv6_find_hdr);
1520 module_init(ip6_tables_init);
1521 module_exit(ip6_tables_fini);