2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
16 * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
17 * - Unification of {ip,ip6}_tables into x_tables
18 * - Removed tcp and udp code, since it's not ipv6 specific
21 #include <linux/capability.h>
23 #include <linux/skbuff.h>
24 #include <linux/kmod.h>
25 #include <linux/vmalloc.h>
26 #include <linux/netdevice.h>
27 #include <linux/module.h>
28 #include <linux/poison.h>
29 #include <linux/icmpv6.h>
31 #include <asm/uaccess.h>
32 #include <linux/mutex.h>
33 #include <linux/proc_fs.h>
34 #include <linux/cpumask.h>
36 #include <linux/netfilter_ipv6/ip6_tables.h>
37 #include <linux/netfilter/x_tables.h>
39 MODULE_LICENSE("GPL");
40 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
41 MODULE_DESCRIPTION("IPv6 packet filter");
43 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
44 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
46 /*#define DEBUG_IP_FIREWALL*/
47 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
48 /*#define DEBUG_IP_FIREWALL_USER*/
50 #ifdef DEBUG_IP_FIREWALL
51 #define dprintf(format, args...) printk(format , ## args)
53 #define dprintf(format, args...)
56 #ifdef DEBUG_IP_FIREWALL_USER
57 #define duprintf(format, args...) printk(format , ## args)
59 #define duprintf(format, args...)
62 #ifdef CONFIG_NETFILTER_DEBUG
63 #define IP_NF_ASSERT(x) \
66 printk("IP_NF_ASSERT: %s:%s:%u\n", \
67 __FUNCTION__, __FILE__, __LINE__); \
70 #define IP_NF_ASSERT(x)
74 #include <linux/netfilter_ipv4/listhelp.h>
77 /* All the better to debug you with... */
83 We keep a set of rules for each CPU, so we can avoid write-locking
84 them in the softirq when updating the counters and therefore
85 only need to read-lock in the softirq; doing a write_lock_bh() in user
86 context stops packets coming through and allows user context to read
87 the counters or update the rules.
89 Hence the start of any table is given by get_table() below. */
92 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
93 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
94 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
97 /* Check for an extension */
99 ip6t_ext_hdr(u8 nexthdr)
101 return ( (nexthdr == IPPROTO_HOPOPTS) ||
102 (nexthdr == IPPROTO_ROUTING) ||
103 (nexthdr == IPPROTO_FRAGMENT) ||
104 (nexthdr == IPPROTO_ESP) ||
105 (nexthdr == IPPROTO_AH) ||
106 (nexthdr == IPPROTO_NONE) ||
107 (nexthdr == IPPROTO_DSTOPTS) );
110 /* Returns whether matches rule or not. */
112 ip6_packet_match(const struct sk_buff *skb,
115 const struct ip6t_ip6 *ip6info,
116 unsigned int *protoff,
121 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
123 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
125 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
126 &ip6info->src), IP6T_INV_SRCIP)
127 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
128 &ip6info->dst), IP6T_INV_DSTIP)) {
129 dprintf("Source or dest mismatch.\n");
131 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
132 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
133 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
134 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
135 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
136 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
140 /* Look for ifname matches; this should unroll nicely. */
141 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
142 ret |= (((const unsigned long *)indev)[i]
143 ^ ((const unsigned long *)ip6info->iniface)[i])
144 & ((const unsigned long *)ip6info->iniface_mask)[i];
147 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
148 dprintf("VIA in mismatch (%s vs %s).%s\n",
149 indev, ip6info->iniface,
150 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
154 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
155 ret |= (((const unsigned long *)outdev)[i]
156 ^ ((const unsigned long *)ip6info->outiface)[i])
157 & ((const unsigned long *)ip6info->outiface_mask)[i];
160 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
161 dprintf("VIA out mismatch (%s vs %s).%s\n",
162 outdev, ip6info->outiface,
163 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
167 /* ... might want to do something with class and flowlabel here ... */
169 /* look for the desired protocol header */
170 if((ip6info->flags & IP6T_F_PROTO)) {
172 unsigned short _frag_off;
174 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
178 *fragoff = _frag_off;
180 dprintf("Packet protocol %hi ?= %s%hi.\n",
182 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
185 if (ip6info->proto == protohdr) {
186 if(ip6info->invflags & IP6T_INV_PROTO) {
192 /* We need match for the '-p all', too! */
193 if ((ip6info->proto != 0) &&
194 !(ip6info->invflags & IP6T_INV_PROTO))
200 /* should be ip6 safe */
202 ip6_checkentry(const struct ip6t_ip6 *ipv6)
204 if (ipv6->flags & ~IP6T_F_MASK) {
205 duprintf("Unknown flag bits set: %08X\n",
206 ipv6->flags & ~IP6T_F_MASK);
209 if (ipv6->invflags & ~IP6T_INV_MASK) {
210 duprintf("Unknown invflag bits set: %08X\n",
211 ipv6->invflags & ~IP6T_INV_MASK);
218 ip6t_error(struct sk_buff **pskb,
219 const struct net_device *in,
220 const struct net_device *out,
221 unsigned int hooknum,
222 const struct xt_target *target,
223 const void *targinfo)
226 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
232 int do_match(struct ip6t_entry_match *m,
233 const struct sk_buff *skb,
234 const struct net_device *in,
235 const struct net_device *out,
237 unsigned int protoff,
240 /* Stop iteration if it doesn't match */
241 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
242 offset, protoff, hotdrop))
248 static inline struct ip6t_entry *
249 get_entry(void *base, unsigned int offset)
251 return (struct ip6t_entry *)(base + offset);
254 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
256 ip6t_do_table(struct sk_buff **pskb,
258 const struct net_device *in,
259 const struct net_device *out,
260 struct xt_table *table)
262 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
264 unsigned int protoff = 0;
266 /* Initializing verdict to NF_DROP keeps gcc happy. */
267 unsigned int verdict = NF_DROP;
268 const char *indev, *outdev;
270 struct ip6t_entry *e, *back;
271 struct xt_table_info *private;
274 indev = in ? in->name : nulldevname;
275 outdev = out ? out->name : nulldevname;
276 /* We handle fragments by dealing with the first fragment as
277 * if it was a normal packet. All other fragments are treated
278 * normally, except that they will NEVER match rules that ask
279 * things we don't know, ie. tcp syn flag or ports). If the
280 * rule is also a fragment-specific rule, non-fragments won't
283 read_lock_bh(&table->lock);
284 private = table->private;
285 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
286 table_base = (void *)private->entries[smp_processor_id()];
287 e = get_entry(table_base, private->hook_entry[hook]);
289 /* For return from builtin chain */
290 back = get_entry(table_base, private->underflow[hook]);
295 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
296 &protoff, &offset)) {
297 struct ip6t_entry_target *t;
299 if (IP6T_MATCH_ITERATE(e, do_match,
301 offset, protoff, &hotdrop) != 0)
304 ADD_COUNTER(e->counters,
305 ntohs((*pskb)->nh.ipv6h->payload_len)
309 t = ip6t_get_target(e);
310 IP_NF_ASSERT(t->u.kernel.target);
311 /* Standard target? */
312 if (!t->u.kernel.target->target) {
315 v = ((struct ip6t_standard_target *)t)->verdict;
317 /* Pop from stack? */
318 if (v != IP6T_RETURN) {
319 verdict = (unsigned)(-v) - 1;
323 back = get_entry(table_base,
327 if (table_base + v != (void *)e + e->next_offset
328 && !(e->ipv6.flags & IP6T_F_GOTO)) {
329 /* Save old back ptr in next entry */
330 struct ip6t_entry *next
331 = (void *)e + e->next_offset;
333 = (void *)back - table_base;
334 /* set back pointer to next entry */
338 e = get_entry(table_base, v);
340 /* Targets which reenter must return
342 #ifdef CONFIG_NETFILTER_DEBUG
343 ((struct ip6t_entry *)table_base)->comefrom
346 verdict = t->u.kernel.target->target(pskb,
352 #ifdef CONFIG_NETFILTER_DEBUG
353 if (((struct ip6t_entry *)table_base)->comefrom
355 && verdict == IP6T_CONTINUE) {
356 printk("Target %s reentered!\n",
357 t->u.kernel.target->name);
360 ((struct ip6t_entry *)table_base)->comefrom
363 if (verdict == IP6T_CONTINUE)
364 e = (void *)e + e->next_offset;
372 e = (void *)e + e->next_offset;
376 #ifdef CONFIG_NETFILTER_DEBUG
377 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
379 read_unlock_bh(&table->lock);
381 #ifdef DEBUG_ALLOW_ALL
390 /* All zeroes == unconditional rule. */
392 unconditional(const struct ip6t_ip6 *ipv6)
396 for (i = 0; i < sizeof(*ipv6); i++)
397 if (((char *)ipv6)[i])
400 return (i == sizeof(*ipv6));
403 /* Figures out from what hook each rule can be called: returns 0 if
404 there are loops. Puts hook bitmask in comefrom. */
406 mark_source_chains(struct xt_table_info *newinfo,
407 unsigned int valid_hooks, void *entry0)
411 /* No recursion; use packet counter to save back ptrs (reset
412 to 0 as we leave), and comefrom to save source hook bitmask */
413 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
414 unsigned int pos = newinfo->hook_entry[hook];
416 = (struct ip6t_entry *)(entry0 + pos);
418 if (!(valid_hooks & (1 << hook)))
421 /* Set initial back pointer. */
422 e->counters.pcnt = pos;
425 struct ip6t_standard_target *t
426 = (void *)ip6t_get_target(e);
428 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
429 printk("iptables: loop hook %u pos %u %08X.\n",
430 hook, pos, e->comefrom);
434 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
436 /* Unconditional return/END. */
437 if (e->target_offset == sizeof(struct ip6t_entry)
438 && (strcmp(t->target.u.user.name,
439 IP6T_STANDARD_TARGET) == 0)
441 && unconditional(&e->ipv6)) {
442 unsigned int oldpos, size;
444 /* Return: backtrack through the last
447 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
448 #ifdef DEBUG_IP_FIREWALL_USER
450 & (1 << NF_IP6_NUMHOOKS)) {
451 duprintf("Back unset "
458 pos = e->counters.pcnt;
459 e->counters.pcnt = 0;
461 /* We're at the start. */
465 e = (struct ip6t_entry *)
467 } while (oldpos == pos + e->next_offset);
470 size = e->next_offset;
471 e = (struct ip6t_entry *)
472 (entry0 + pos + size);
473 e->counters.pcnt = pos;
476 int newpos = t->verdict;
478 if (strcmp(t->target.u.user.name,
479 IP6T_STANDARD_TARGET) == 0
481 /* This a jump; chase it. */
482 duprintf("Jump rule %u -> %u\n",
485 /* ... this is a fallthru */
486 newpos = pos + e->next_offset;
488 e = (struct ip6t_entry *)
490 e->counters.pcnt = pos;
495 duprintf("Finished chain %u\n", hook);
501 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
503 if (i && (*i)-- == 0)
506 if (m->u.kernel.match->destroy)
507 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
508 m->u.match_size - sizeof(*m));
509 module_put(m->u.kernel.match->me);
514 standard_check(const struct ip6t_entry_target *t,
515 unsigned int max_offset)
517 struct ip6t_standard_target *targ = (void *)t;
519 /* Check standard info. */
520 if (targ->verdict >= 0
521 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
522 duprintf("ip6t_standard_check: bad verdict (%i)\n",
526 if (targ->verdict < -NF_MAX_VERDICT - 1) {
527 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
535 check_match(struct ip6t_entry_match *m,
537 const struct ip6t_ip6 *ipv6,
538 unsigned int hookmask,
541 struct ip6t_match *match;
544 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
546 "ip6t_%s", m->u.user.name);
547 if (IS_ERR(match) || !match) {
548 duprintf("check_match: `%s' not found\n", m->u.user.name);
549 return match ? PTR_ERR(match) : -ENOENT;
551 m->u.kernel.match = match;
553 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
554 name, hookmask, ipv6->proto,
555 ipv6->invflags & IP6T_INV_PROTO);
559 if (m->u.kernel.match->checkentry
560 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
561 m->u.match_size - sizeof(*m),
563 duprintf("ip_tables: check failed for `%s'.\n",
564 m->u.kernel.match->name);
572 module_put(m->u.kernel.match->me);
576 static struct ip6t_target ip6t_standard_target;
579 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
582 struct ip6t_entry_target *t;
583 struct ip6t_target *target;
587 if (!ip6_checkentry(&e->ipv6)) {
588 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
593 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
595 goto cleanup_matches;
597 t = ip6t_get_target(e);
598 target = try_then_request_module(xt_find_target(AF_INET6,
601 "ip6t_%s", t->u.user.name);
602 if (IS_ERR(target) || !target) {
603 duprintf("check_entry: `%s' not found\n", t->u.user.name);
604 ret = target ? PTR_ERR(target) : -ENOENT;
605 goto cleanup_matches;
607 t->u.kernel.target = target;
609 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
610 name, e->comefrom, e->ipv6.proto,
611 e->ipv6.invflags & IP6T_INV_PROTO);
615 if (t->u.kernel.target == &ip6t_standard_target) {
616 if (!standard_check(t, size)) {
618 goto cleanup_matches;
620 } else if (t->u.kernel.target->checkentry
621 && !t->u.kernel.target->checkentry(name, e, target, t->data,
625 duprintf("ip_tables: check failed for `%s'.\n",
626 t->u.kernel.target->name);
634 module_put(t->u.kernel.target->me);
636 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
641 check_entry_size_and_hooks(struct ip6t_entry *e,
642 struct xt_table_info *newinfo,
644 unsigned char *limit,
645 const unsigned int *hook_entries,
646 const unsigned int *underflows,
651 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
652 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
653 duprintf("Bad offset %p\n", e);
658 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
659 duprintf("checking: element %p size %u\n",
664 /* Check hooks & underflows */
665 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
666 if ((unsigned char *)e - base == hook_entries[h])
667 newinfo->hook_entry[h] = hook_entries[h];
668 if ((unsigned char *)e - base == underflows[h])
669 newinfo->underflow[h] = underflows[h];
672 /* FIXME: underflows must be unconditional, standard verdicts
673 < 0 (not IP6T_RETURN). --RR */
675 /* Clear counters and comefrom */
676 e->counters = ((struct xt_counters) { 0, 0 });
684 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
686 struct ip6t_entry_target *t;
688 if (i && (*i)-- == 0)
691 /* Cleanup all matches */
692 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
693 t = ip6t_get_target(e);
694 if (t->u.kernel.target->destroy)
695 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
696 t->u.target_size - sizeof(*t));
697 module_put(t->u.kernel.target->me);
701 /* Checks and translates the user-supplied table segment (held in
704 translate_table(const char *name,
705 unsigned int valid_hooks,
706 struct xt_table_info *newinfo,
710 const unsigned int *hook_entries,
711 const unsigned int *underflows)
716 newinfo->size = size;
717 newinfo->number = number;
719 /* Init all hooks to impossible value. */
720 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
721 newinfo->hook_entry[i] = 0xFFFFFFFF;
722 newinfo->underflow[i] = 0xFFFFFFFF;
725 duprintf("translate_table: size %u\n", newinfo->size);
727 /* Walk through entries, checking offsets. */
728 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
729 check_entry_size_and_hooks,
733 hook_entries, underflows, &i);
738 duprintf("translate_table: %u not %u entries\n",
743 /* Check hooks all assigned */
744 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
745 /* Only hooks which are valid */
746 if (!(valid_hooks & (1 << i)))
748 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
749 duprintf("Invalid hook entry %u %u\n",
753 if (newinfo->underflow[i] == 0xFFFFFFFF) {
754 duprintf("Invalid underflow %u %u\n",
760 if (!mark_source_chains(newinfo, valid_hooks, entry0))
763 /* Finally, each sanity check must pass */
765 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
766 check_entry, name, size, &i);
769 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
774 /* And one copy for every other CPU */
775 for_each_possible_cpu(i) {
776 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
777 memcpy(newinfo->entries[i], entry0, newinfo->size);
785 add_entry_to_counter(const struct ip6t_entry *e,
786 struct xt_counters total[],
789 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
796 set_entry_to_counter(const struct ip6t_entry *e,
797 struct ip6t_counters total[],
800 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
807 get_counters(const struct xt_table_info *t,
808 struct xt_counters counters[])
814 /* Instead of clearing (by a previous call to memset())
815 * the counters and using adds, we set the counters
816 * with data used by 'current' CPU
817 * We dont care about preemption here.
819 curcpu = raw_smp_processor_id();
822 IP6T_ENTRY_ITERATE(t->entries[curcpu],
824 set_entry_to_counter,
828 for_each_possible_cpu(cpu) {
832 IP6T_ENTRY_ITERATE(t->entries[cpu],
834 add_entry_to_counter,
841 copy_entries_to_user(unsigned int total_size,
842 struct xt_table *table,
843 void __user *userptr)
845 unsigned int off, num, countersize;
846 struct ip6t_entry *e;
847 struct xt_counters *counters;
848 struct xt_table_info *private = table->private;
852 /* We need atomic snapshot of counters: rest doesn't change
853 (other than comefrom, which userspace doesn't care
855 countersize = sizeof(struct xt_counters) * private->number;
856 counters = vmalloc(countersize);
858 if (counters == NULL)
861 /* First, sum counters... */
862 write_lock_bh(&table->lock);
863 get_counters(private, counters);
864 write_unlock_bh(&table->lock);
866 /* choose the copy that is on ourc node/cpu */
867 loc_cpu_entry = private->entries[raw_smp_processor_id()];
868 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
873 /* FIXME: use iterator macros --RR */
874 /* ... then go back and fix counters and names */
875 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
877 struct ip6t_entry_match *m;
878 struct ip6t_entry_target *t;
880 e = (struct ip6t_entry *)(loc_cpu_entry + off);
881 if (copy_to_user(userptr + off
882 + offsetof(struct ip6t_entry, counters),
884 sizeof(counters[num])) != 0) {
889 for (i = sizeof(struct ip6t_entry);
890 i < e->target_offset;
891 i += m->u.match_size) {
894 if (copy_to_user(userptr + off + i
895 + offsetof(struct ip6t_entry_match,
897 m->u.kernel.match->name,
898 strlen(m->u.kernel.match->name)+1)
905 t = ip6t_get_target(e);
906 if (copy_to_user(userptr + off + e->target_offset
907 + offsetof(struct ip6t_entry_target,
909 t->u.kernel.target->name,
910 strlen(t->u.kernel.target->name)+1) != 0) {
922 get_entries(const struct ip6t_get_entries *entries,
923 struct ip6t_get_entries __user *uptr)
928 t = xt_find_table_lock(AF_INET6, entries->name);
929 if (t && !IS_ERR(t)) {
930 struct xt_table_info *private = t->private;
931 duprintf("t->private->number = %u\n", private->number);
932 if (entries->size == private->size)
933 ret = copy_entries_to_user(private->size,
934 t, uptr->entrytable);
936 duprintf("get_entries: I've got %u not %u!\n",
937 private->size, entries->size);
943 ret = t ? PTR_ERR(t) : -ENOENT;
949 do_replace(void __user *user, unsigned int len)
952 struct ip6t_replace tmp;
954 struct xt_table_info *newinfo, *oldinfo;
955 struct xt_counters *counters;
956 void *loc_cpu_entry, *loc_cpu_old_entry;
958 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
962 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
965 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
968 newinfo = xt_alloc_table_info(tmp.size);
972 /* choose the copy that is on our node/cpu */
973 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
974 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
980 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
986 ret = translate_table(tmp.name, tmp.valid_hooks,
987 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
988 tmp.hook_entry, tmp.underflow);
990 goto free_newinfo_counters;
992 duprintf("ip_tables: Translated table\n");
994 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
995 "ip6table_%s", tmp.name);
996 if (!t || IS_ERR(t)) {
997 ret = t ? PTR_ERR(t) : -ENOENT;
998 goto free_newinfo_counters_untrans;
1002 if (tmp.valid_hooks != t->valid_hooks) {
1003 duprintf("Valid hook crap: %08X vs %08X\n",
1004 tmp.valid_hooks, t->valid_hooks);
1009 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1013 /* Update module usage count based on number of rules */
1014 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1015 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1016 if ((oldinfo->number > oldinfo->initial_entries) ||
1017 (newinfo->number <= oldinfo->initial_entries))
1019 if ((oldinfo->number > oldinfo->initial_entries) &&
1020 (newinfo->number <= oldinfo->initial_entries))
1023 /* Get the old counters. */
1024 get_counters(oldinfo, counters);
1025 /* Decrease module usage counts and free resource */
1026 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1027 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1028 xt_free_table_info(oldinfo);
1029 if (copy_to_user(tmp.counters, counters,
1030 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1039 free_newinfo_counters_untrans:
1040 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1041 free_newinfo_counters:
1044 xt_free_table_info(newinfo);
1048 /* We're lazy, and add to the first CPU; overflow works its fey magic
1049 * and everything is OK. */
1051 add_counter_to_entry(struct ip6t_entry *e,
1052 const struct xt_counters addme[],
1056 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1058 (long unsigned int)e->counters.pcnt,
1059 (long unsigned int)e->counters.bcnt,
1060 (long unsigned int)addme[*i].pcnt,
1061 (long unsigned int)addme[*i].bcnt);
1064 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1071 do_add_counters(void __user *user, unsigned int len)
1074 struct xt_counters_info tmp, *paddc;
1075 struct xt_table_info *private;
1078 void *loc_cpu_entry;
1080 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1083 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1086 paddc = vmalloc(len);
1090 if (copy_from_user(paddc, user, len) != 0) {
1095 t = xt_find_table_lock(AF_INET6, tmp.name);
1096 if (!t || IS_ERR(t)) {
1097 ret = t ? PTR_ERR(t) : -ENOENT;
1101 write_lock_bh(&t->lock);
1102 private = t->private;
1103 if (private->number != tmp.num_counters) {
1105 goto unlock_up_free;
1109 /* Choose the copy that is on our node */
1110 loc_cpu_entry = private->entries[smp_processor_id()];
1111 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1113 add_counter_to_entry,
1117 write_unlock_bh(&t->lock);
1127 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1131 if (!capable(CAP_NET_ADMIN))
1135 case IP6T_SO_SET_REPLACE:
1136 ret = do_replace(user, len);
1139 case IP6T_SO_SET_ADD_COUNTERS:
1140 ret = do_add_counters(user, len);
1144 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1152 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1156 if (!capable(CAP_NET_ADMIN))
1160 case IP6T_SO_GET_INFO: {
1161 char name[IP6T_TABLE_MAXNAMELEN];
1164 if (*len != sizeof(struct ip6t_getinfo)) {
1165 duprintf("length %u != %u\n", *len,
1166 sizeof(struct ip6t_getinfo));
1171 if (copy_from_user(name, user, sizeof(name)) != 0) {
1175 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1177 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1178 "ip6table_%s", name);
1179 if (t && !IS_ERR(t)) {
1180 struct ip6t_getinfo info;
1181 struct xt_table_info *private = t->private;
1183 info.valid_hooks = t->valid_hooks;
1184 memcpy(info.hook_entry, private->hook_entry,
1185 sizeof(info.hook_entry));
1186 memcpy(info.underflow, private->underflow,
1187 sizeof(info.underflow));
1188 info.num_entries = private->number;
1189 info.size = private->size;
1190 memcpy(info.name, name, sizeof(info.name));
1192 if (copy_to_user(user, &info, *len) != 0)
1199 ret = t ? PTR_ERR(t) : -ENOENT;
1203 case IP6T_SO_GET_ENTRIES: {
1204 struct ip6t_get_entries get;
1206 if (*len < sizeof(get)) {
1207 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1209 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1211 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1212 duprintf("get_entries: %u != %u\n", *len,
1213 sizeof(struct ip6t_get_entries) + get.size);
1216 ret = get_entries(&get, user);
1220 case IP6T_SO_GET_REVISION_MATCH:
1221 case IP6T_SO_GET_REVISION_TARGET: {
1222 struct ip6t_get_revision rev;
1225 if (*len != sizeof(rev)) {
1229 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1234 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1239 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1242 "ip6t_%s", rev.name);
1247 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1254 int ip6t_register_table(struct xt_table *table,
1255 const struct ip6t_replace *repl)
1258 struct xt_table_info *newinfo;
1259 static struct xt_table_info bootstrap
1260 = { 0, 0, 0, { 0 }, { 0 }, { } };
1261 void *loc_cpu_entry;
1263 newinfo = xt_alloc_table_info(repl->size);
1267 /* choose the copy on our node/cpu */
1268 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1269 memcpy(loc_cpu_entry, repl->entries, repl->size);
1271 ret = translate_table(table->name, table->valid_hooks,
1272 newinfo, loc_cpu_entry, repl->size,
1277 xt_free_table_info(newinfo);
1281 ret = xt_register_table(table, &bootstrap, newinfo);
1283 xt_free_table_info(newinfo);
1290 void ip6t_unregister_table(struct xt_table *table)
1292 struct xt_table_info *private;
1293 void *loc_cpu_entry;
1295 private = xt_unregister_table(table);
1297 /* Decrease module usage counts and free resources */
1298 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1299 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1300 xt_free_table_info(private);
1303 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1305 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1306 u_int8_t type, u_int8_t code,
1309 return (type == test_type && code >= min_code && code <= max_code)
1314 icmp6_match(const struct sk_buff *skb,
1315 const struct net_device *in,
1316 const struct net_device *out,
1317 const struct xt_match *match,
1318 const void *matchinfo,
1320 unsigned int protoff,
1323 struct icmp6hdr _icmp, *ic;
1324 const struct ip6t_icmp *icmpinfo = matchinfo;
1326 /* Must not be a fragment. */
1330 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1332 /* We've been asked to examine this packet, and we
1333 can't. Hence, no choice but to drop. */
1334 duprintf("Dropping evil ICMP tinygram.\n");
1339 return icmp6_type_code_match(icmpinfo->type,
1342 ic->icmp6_type, ic->icmp6_code,
1343 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1346 /* Called when user tries to insert an entry of this type. */
1348 icmp6_checkentry(const char *tablename,
1350 const struct xt_match *match,
1352 unsigned int matchsize,
1353 unsigned int hook_mask)
1355 const struct ip6t_icmp *icmpinfo = matchinfo;
1357 /* Must specify no unknown invflags */
1358 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1361 /* The built-in targets: standard (NULL) and error. */
1362 static struct ip6t_target ip6t_standard_target = {
1363 .name = IP6T_STANDARD_TARGET,
1364 .targetsize = sizeof(int),
1368 static struct ip6t_target ip6t_error_target = {
1369 .name = IP6T_ERROR_TARGET,
1370 .target = ip6t_error,
1371 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1375 static struct nf_sockopt_ops ip6t_sockopts = {
1377 .set_optmin = IP6T_BASE_CTL,
1378 .set_optmax = IP6T_SO_SET_MAX+1,
1379 .set = do_ip6t_set_ctl,
1380 .get_optmin = IP6T_BASE_CTL,
1381 .get_optmax = IP6T_SO_GET_MAX+1,
1382 .get = do_ip6t_get_ctl,
1385 static struct ip6t_match icmp6_matchstruct = {
1387 .match = &icmp6_match,
1388 .matchsize = sizeof(struct ip6t_icmp),
1389 .checkentry = icmp6_checkentry,
1390 .proto = IPPROTO_ICMPV6,
1394 static int __init ip6_tables_init(void)
1398 ret = xt_proto_init(AF_INET6);
1402 /* Noone else will be downing sem now, so we won't sleep */
1403 ret = xt_register_target(&ip6t_standard_target);
1406 ret = xt_register_target(&ip6t_error_target);
1409 ret = xt_register_match(&icmp6_matchstruct);
1413 /* Register setsockopt */
1414 ret = nf_register_sockopt(&ip6t_sockopts);
1418 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1422 xt_unregister_match(&icmp6_matchstruct);
1424 xt_unregister_target(&ip6t_error_target);
1426 xt_unregister_target(&ip6t_standard_target);
1428 xt_proto_fini(AF_INET6);
1433 static void __exit ip6_tables_fini(void)
1435 nf_unregister_sockopt(&ip6t_sockopts);
1436 xt_unregister_match(&icmp6_matchstruct);
1437 xt_unregister_target(&ip6t_error_target);
1438 xt_unregister_target(&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 * Note that non-1st fragment is special case that "the protocol number
1451 * of last header" is "next header" field in Fragment header. In this case,
1452 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1456 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1457 int target, unsigned short *fragoff)
1459 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1460 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1461 unsigned int len = skb->len - start;
1466 while (nexthdr != target) {
1467 struct ipv6_opt_hdr _hdr, *hp;
1468 unsigned int hdrlen;
1470 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1476 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1479 if (nexthdr == NEXTHDR_FRAGMENT) {
1480 unsigned short _frag_off, *fp;
1481 fp = skb_header_pointer(skb,
1482 start+offsetof(struct frag_hdr,
1489 _frag_off = ntohs(*fp) & ~0x7;
1492 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1493 nexthdr == NEXTHDR_NONE)) {
1495 *fragoff = _frag_off;
1501 } else if (nexthdr == NEXTHDR_AUTH)
1502 hdrlen = (hp->hdrlen + 2) << 2;
1504 hdrlen = ipv6_optlen(hp);
1506 nexthdr = hp->nexthdr;
1515 EXPORT_SYMBOL(ip6t_register_table);
1516 EXPORT_SYMBOL(ip6t_unregister_table);
1517 EXPORT_SYMBOL(ip6t_do_table);
1518 EXPORT_SYMBOL(ip6t_ext_hdr);
1519 EXPORT_SYMBOL(ipv6_find_hdr);
1521 module_init(ip6_tables_init);
1522 module_exit(ip6_tables_fini);