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,
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);
191 *fragoff = _frag_off;
193 dprintf("Packet protocol %hi ?= %s%hi.\n",
195 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
198 if (ip6info->proto == protohdr) {
199 if(ip6info->invflags & IP6T_INV_PROTO) {
205 /* We need match for the '-p all', too! */
206 if ((ip6info->proto != 0) &&
207 !(ip6info->invflags & IP6T_INV_PROTO))
213 /* should be ip6 safe */
215 ip6_checkentry(const struct ip6t_ip6 *ipv6)
217 if (ipv6->flags & ~IP6T_F_MASK) {
218 duprintf("Unknown flag bits set: %08X\n",
219 ipv6->flags & ~IP6T_F_MASK);
222 if (ipv6->invflags & ~IP6T_INV_MASK) {
223 duprintf("Unknown invflag bits set: %08X\n",
224 ipv6->invflags & ~IP6T_INV_MASK);
231 ip6t_error(struct sk_buff **pskb,
232 const struct net_device *in,
233 const struct net_device *out,
234 unsigned int hooknum,
235 const void *targinfo,
239 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
245 int do_match(struct ip6t_entry_match *m,
246 const struct sk_buff *skb,
247 const struct net_device *in,
248 const struct net_device *out,
250 unsigned int protoff,
253 /* Stop iteration if it doesn't match */
254 if (!m->u.kernel.match->match(skb, in, out, m->data,
255 offset, protoff, hotdrop))
261 static inline struct ip6t_entry *
262 get_entry(void *base, unsigned int offset)
264 return (struct ip6t_entry *)(base + offset);
267 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
269 ip6t_do_table(struct sk_buff **pskb,
271 const struct net_device *in,
272 const struct net_device *out,
273 struct xt_table *table,
276 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
278 unsigned int protoff = 0;
280 /* Initializing verdict to NF_DROP keeps gcc happy. */
281 unsigned int verdict = NF_DROP;
282 const char *indev, *outdev;
284 struct ip6t_entry *e, *back;
285 struct xt_table_info *private;
288 indev = in ? in->name : nulldevname;
289 outdev = out ? out->name : nulldevname;
290 /* We handle fragments by dealing with the first fragment as
291 * if it was a normal packet. All other fragments are treated
292 * normally, except that they will NEVER match rules that ask
293 * things we don't know, ie. tcp syn flag or ports). If the
294 * rule is also a fragment-specific rule, non-fragments won't
297 read_lock_bh(&table->lock);
298 private = table->private;
299 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
300 table_base = (void *)private->entries[smp_processor_id()];
301 e = get_entry(table_base, private->hook_entry[hook]);
303 #ifdef CONFIG_NETFILTER_DEBUG
304 /* Check noone else using our table */
305 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
306 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
307 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
310 &((struct ip6t_entry *)table_base)->comefrom,
311 ((struct ip6t_entry *)table_base)->comefrom);
313 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
316 /* For return from builtin chain */
317 back = get_entry(table_base, private->underflow[hook]);
322 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
323 &protoff, &offset)) {
324 struct ip6t_entry_target *t;
326 if (IP6T_MATCH_ITERATE(e, do_match,
328 offset, protoff, &hotdrop) != 0)
331 ADD_COUNTER(e->counters,
332 ntohs((*pskb)->nh.ipv6h->payload_len)
336 t = ip6t_get_target(e);
337 IP_NF_ASSERT(t->u.kernel.target);
338 /* Standard target? */
339 if (!t->u.kernel.target->target) {
342 v = ((struct ip6t_standard_target *)t)->verdict;
344 /* Pop from stack? */
345 if (v != IP6T_RETURN) {
346 verdict = (unsigned)(-v) - 1;
350 back = get_entry(table_base,
354 if (table_base + v != (void *)e + e->next_offset
355 && !(e->ipv6.flags & IP6T_F_GOTO)) {
356 /* Save old back ptr in next entry */
357 struct ip6t_entry *next
358 = (void *)e + e->next_offset;
360 = (void *)back - table_base;
361 /* set back pointer to next entry */
365 e = get_entry(table_base, v);
367 /* Targets which reenter must return
369 #ifdef CONFIG_NETFILTER_DEBUG
370 ((struct ip6t_entry *)table_base)->comefrom
373 verdict = t->u.kernel.target->target(pskb,
379 #ifdef CONFIG_NETFILTER_DEBUG
380 if (((struct ip6t_entry *)table_base)->comefrom
382 && verdict == IP6T_CONTINUE) {
383 printk("Target %s reentered!\n",
384 t->u.kernel.target->name);
387 ((struct ip6t_entry *)table_base)->comefrom
390 if (verdict == IP6T_CONTINUE)
391 e = (void *)e + e->next_offset;
399 e = (void *)e + e->next_offset;
403 #ifdef CONFIG_NETFILTER_DEBUG
404 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
406 read_unlock_bh(&table->lock);
408 #ifdef DEBUG_ALLOW_ALL
417 /* All zeroes == unconditional rule. */
419 unconditional(const struct ip6t_ip6 *ipv6)
423 for (i = 0; i < sizeof(*ipv6); i++)
424 if (((char *)ipv6)[i])
427 return (i == sizeof(*ipv6));
430 /* Figures out from what hook each rule can be called: returns 0 if
431 there are loops. Puts hook bitmask in comefrom. */
433 mark_source_chains(struct xt_table_info *newinfo,
434 unsigned int valid_hooks, void *entry0)
438 /* No recursion; use packet counter to save back ptrs (reset
439 to 0 as we leave), and comefrom to save source hook bitmask */
440 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
441 unsigned int pos = newinfo->hook_entry[hook];
443 = (struct ip6t_entry *)(entry0 + pos);
445 if (!(valid_hooks & (1 << hook)))
448 /* Set initial back pointer. */
449 e->counters.pcnt = pos;
452 struct ip6t_standard_target *t
453 = (void *)ip6t_get_target(e);
455 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
456 printk("iptables: loop hook %u pos %u %08X.\n",
457 hook, pos, e->comefrom);
461 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
463 /* Unconditional return/END. */
464 if (e->target_offset == sizeof(struct ip6t_entry)
465 && (strcmp(t->target.u.user.name,
466 IP6T_STANDARD_TARGET) == 0)
468 && unconditional(&e->ipv6)) {
469 unsigned int oldpos, size;
471 /* Return: backtrack through the last
474 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
475 #ifdef DEBUG_IP_FIREWALL_USER
477 & (1 << NF_IP6_NUMHOOKS)) {
478 duprintf("Back unset "
485 pos = e->counters.pcnt;
486 e->counters.pcnt = 0;
488 /* We're at the start. */
492 e = (struct ip6t_entry *)
494 } while (oldpos == pos + e->next_offset);
497 size = e->next_offset;
498 e = (struct ip6t_entry *)
499 (entry0 + pos + size);
500 e->counters.pcnt = pos;
503 int newpos = t->verdict;
505 if (strcmp(t->target.u.user.name,
506 IP6T_STANDARD_TARGET) == 0
508 /* This a jump; chase it. */
509 duprintf("Jump rule %u -> %u\n",
512 /* ... this is a fallthru */
513 newpos = pos + e->next_offset;
515 e = (struct ip6t_entry *)
517 e->counters.pcnt = pos;
522 duprintf("Finished chain %u\n", hook);
528 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
530 if (i && (*i)-- == 0)
533 if (m->u.kernel.match->destroy)
534 m->u.kernel.match->destroy(m->data,
535 m->u.match_size - sizeof(*m));
536 module_put(m->u.kernel.match->me);
541 standard_check(const struct ip6t_entry_target *t,
542 unsigned int max_offset)
544 struct ip6t_standard_target *targ = (void *)t;
546 /* Check standard info. */
548 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
549 duprintf("standard_check: target size %u != %u\n",
551 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
555 if (targ->verdict >= 0
556 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
557 duprintf("ip6t_standard_check: bad verdict (%i)\n",
562 if (targ->verdict < -NF_MAX_VERDICT - 1) {
563 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
571 check_match(struct ip6t_entry_match *m,
573 const struct ip6t_ip6 *ipv6,
574 unsigned int hookmask,
577 struct ip6t_match *match;
579 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
581 "ip6t_%s", m->u.user.name);
582 if (IS_ERR(match) || !match) {
583 duprintf("check_match: `%s' not found\n", m->u.user.name);
584 return match ? PTR_ERR(match) : -ENOENT;
586 m->u.kernel.match = match;
588 if (m->u.kernel.match->checkentry
589 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
590 m->u.match_size - sizeof(*m),
592 module_put(m->u.kernel.match->me);
593 duprintf("ip_tables: check failed for `%s'.\n",
594 m->u.kernel.match->name);
602 static struct ip6t_target ip6t_standard_target;
605 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
608 struct ip6t_entry_target *t;
609 struct ip6t_target *target;
613 if (!ip6_checkentry(&e->ipv6)) {
614 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
619 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
621 goto cleanup_matches;
623 t = ip6t_get_target(e);
624 target = try_then_request_module(xt_find_target(AF_INET6,
627 "ip6t_%s", t->u.user.name);
628 if (IS_ERR(target) || !target) {
629 duprintf("check_entry: `%s' not found\n", t->u.user.name);
630 ret = target ? PTR_ERR(target) : -ENOENT;
631 goto cleanup_matches;
633 t->u.kernel.target = target;
635 if (t->u.kernel.target == &ip6t_standard_target) {
636 if (!standard_check(t, size)) {
638 goto cleanup_matches;
640 } else if (t->u.kernel.target->checkentry
641 && !t->u.kernel.target->checkentry(name, e, t->data,
645 module_put(t->u.kernel.target->me);
646 duprintf("ip_tables: check failed for `%s'.\n",
647 t->u.kernel.target->name);
649 goto cleanup_matches;
656 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
661 check_entry_size_and_hooks(struct ip6t_entry *e,
662 struct xt_table_info *newinfo,
664 unsigned char *limit,
665 const unsigned int *hook_entries,
666 const unsigned int *underflows,
671 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
672 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
673 duprintf("Bad offset %p\n", e);
678 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
679 duprintf("checking: element %p size %u\n",
684 /* Check hooks & underflows */
685 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
686 if ((unsigned char *)e - base == hook_entries[h])
687 newinfo->hook_entry[h] = hook_entries[h];
688 if ((unsigned char *)e - base == underflows[h])
689 newinfo->underflow[h] = underflows[h];
692 /* FIXME: underflows must be unconditional, standard verdicts
693 < 0 (not IP6T_RETURN). --RR */
695 /* Clear counters and comefrom */
696 e->counters = ((struct xt_counters) { 0, 0 });
704 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
706 struct ip6t_entry_target *t;
708 if (i && (*i)-- == 0)
711 /* Cleanup all matches */
712 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
713 t = ip6t_get_target(e);
714 if (t->u.kernel.target->destroy)
715 t->u.kernel.target->destroy(t->data,
716 t->u.target_size - sizeof(*t));
717 module_put(t->u.kernel.target->me);
721 /* Checks and translates the user-supplied table segment (held in
724 translate_table(const char *name,
725 unsigned int valid_hooks,
726 struct xt_table_info *newinfo,
730 const unsigned int *hook_entries,
731 const unsigned int *underflows)
736 newinfo->size = size;
737 newinfo->number = number;
739 /* Init all hooks to impossible value. */
740 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
741 newinfo->hook_entry[i] = 0xFFFFFFFF;
742 newinfo->underflow[i] = 0xFFFFFFFF;
745 duprintf("translate_table: size %u\n", newinfo->size);
747 /* Walk through entries, checking offsets. */
748 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
749 check_entry_size_and_hooks,
753 hook_entries, underflows, &i);
758 duprintf("translate_table: %u not %u entries\n",
763 /* Check hooks all assigned */
764 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
765 /* Only hooks which are valid */
766 if (!(valid_hooks & (1 << i)))
768 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
769 duprintf("Invalid hook entry %u %u\n",
773 if (newinfo->underflow[i] == 0xFFFFFFFF) {
774 duprintf("Invalid underflow %u %u\n",
780 if (!mark_source_chains(newinfo, valid_hooks, entry0))
783 /* Finally, each sanity check must pass */
785 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
786 check_entry, name, size, &i);
789 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
794 /* And one copy for every other CPU */
796 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
797 memcpy(newinfo->entries[i], entry0, newinfo->size);
805 add_entry_to_counter(const struct ip6t_entry *e,
806 struct xt_counters total[],
809 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
816 set_entry_to_counter(const struct ip6t_entry *e,
817 struct ip6t_counters total[],
820 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
827 get_counters(const struct xt_table_info *t,
828 struct xt_counters counters[])
834 /* Instead of clearing (by a previous call to memset())
835 * the counters and using adds, we set the counters
836 * with data used by 'current' CPU
837 * We dont care about preemption here.
839 curcpu = raw_smp_processor_id();
842 IP6T_ENTRY_ITERATE(t->entries[curcpu],
844 set_entry_to_counter,
852 IP6T_ENTRY_ITERATE(t->entries[cpu],
854 add_entry_to_counter,
861 copy_entries_to_user(unsigned int total_size,
862 struct xt_table *table,
863 void __user *userptr)
865 unsigned int off, num, countersize;
866 struct ip6t_entry *e;
867 struct xt_counters *counters;
868 struct xt_table_info *private = table->private;
872 /* We need atomic snapshot of counters: rest doesn't change
873 (other than comefrom, which userspace doesn't care
875 countersize = sizeof(struct xt_counters) * private->number;
876 counters = vmalloc(countersize);
878 if (counters == NULL)
881 /* First, sum counters... */
882 write_lock_bh(&table->lock);
883 get_counters(private, counters);
884 write_unlock_bh(&table->lock);
886 /* choose the copy that is on ourc node/cpu */
887 loc_cpu_entry = private->entries[raw_smp_processor_id()];
888 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
893 /* FIXME: use iterator macros --RR */
894 /* ... then go back and fix counters and names */
895 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
897 struct ip6t_entry_match *m;
898 struct ip6t_entry_target *t;
900 e = (struct ip6t_entry *)(loc_cpu_entry + off);
901 if (copy_to_user(userptr + off
902 + offsetof(struct ip6t_entry, counters),
904 sizeof(counters[num])) != 0) {
909 for (i = sizeof(struct ip6t_entry);
910 i < e->target_offset;
911 i += m->u.match_size) {
914 if (copy_to_user(userptr + off + i
915 + offsetof(struct ip6t_entry_match,
917 m->u.kernel.match->name,
918 strlen(m->u.kernel.match->name)+1)
925 t = ip6t_get_target(e);
926 if (copy_to_user(userptr + off + e->target_offset
927 + offsetof(struct ip6t_entry_target,
929 t->u.kernel.target->name,
930 strlen(t->u.kernel.target->name)+1) != 0) {
942 get_entries(const struct ip6t_get_entries *entries,
943 struct ip6t_get_entries __user *uptr)
948 t = xt_find_table_lock(AF_INET6, entries->name);
949 if (t && !IS_ERR(t)) {
950 struct xt_table_info *private = t->private;
951 duprintf("t->private->number = %u\n", private->number);
952 if (entries->size == private->size)
953 ret = copy_entries_to_user(private->size,
954 t, uptr->entrytable);
956 duprintf("get_entries: I've got %u not %u!\n",
957 private->size, entries->size);
963 ret = t ? PTR_ERR(t) : -ENOENT;
969 do_replace(void __user *user, unsigned int len)
972 struct ip6t_replace tmp;
974 struct xt_table_info *newinfo, *oldinfo;
975 struct xt_counters *counters;
976 void *loc_cpu_entry, *loc_cpu_old_entry;
978 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
982 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
985 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
988 newinfo = xt_alloc_table_info(tmp.size);
992 /* choose the copy that is on our node/cpu */
993 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
994 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1000 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1006 ret = translate_table(tmp.name, tmp.valid_hooks,
1007 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1008 tmp.hook_entry, tmp.underflow);
1010 goto free_newinfo_counters;
1012 duprintf("ip_tables: Translated table\n");
1014 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1015 "ip6table_%s", tmp.name);
1016 if (!t || IS_ERR(t)) {
1017 ret = t ? PTR_ERR(t) : -ENOENT;
1018 goto free_newinfo_counters_untrans;
1022 if (tmp.valid_hooks != t->valid_hooks) {
1023 duprintf("Valid hook crap: %08X vs %08X\n",
1024 tmp.valid_hooks, t->valid_hooks);
1029 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1033 /* Update module usage count based on number of rules */
1034 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1035 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1036 if ((oldinfo->number > oldinfo->initial_entries) ||
1037 (newinfo->number <= oldinfo->initial_entries))
1039 if ((oldinfo->number > oldinfo->initial_entries) &&
1040 (newinfo->number <= oldinfo->initial_entries))
1043 /* Get the old counters. */
1044 get_counters(oldinfo, counters);
1045 /* Decrease module usage counts and free resource */
1046 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1047 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1048 xt_free_table_info(oldinfo);
1049 if (copy_to_user(tmp.counters, counters,
1050 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1059 free_newinfo_counters_untrans:
1060 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1061 free_newinfo_counters:
1064 xt_free_table_info(newinfo);
1068 /* We're lazy, and add to the first CPU; overflow works its fey magic
1069 * and everything is OK. */
1071 add_counter_to_entry(struct ip6t_entry *e,
1072 const struct xt_counters addme[],
1076 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1078 (long unsigned int)e->counters.pcnt,
1079 (long unsigned int)e->counters.bcnt,
1080 (long unsigned int)addme[*i].pcnt,
1081 (long unsigned int)addme[*i].bcnt);
1084 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1091 do_add_counters(void __user *user, unsigned int len)
1094 struct xt_counters_info tmp, *paddc;
1095 struct xt_table_info *private;
1098 void *loc_cpu_entry;
1100 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1103 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1106 paddc = vmalloc(len);
1110 if (copy_from_user(paddc, user, len) != 0) {
1115 t = xt_find_table_lock(AF_INET6, tmp.name);
1116 if (!t || IS_ERR(t)) {
1117 ret = t ? PTR_ERR(t) : -ENOENT;
1121 write_lock_bh(&t->lock);
1122 private = t->private;
1123 if (private->number != paddc->num_counters) {
1125 goto unlock_up_free;
1129 /* Choose the copy that is on our node */
1130 loc_cpu_entry = private->entries[smp_processor_id()];
1131 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1133 add_counter_to_entry,
1137 write_unlock_bh(&t->lock);
1147 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1151 if (!capable(CAP_NET_ADMIN))
1155 case IP6T_SO_SET_REPLACE:
1156 ret = do_replace(user, len);
1159 case IP6T_SO_SET_ADD_COUNTERS:
1160 ret = do_add_counters(user, len);
1164 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1172 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1176 if (!capable(CAP_NET_ADMIN))
1180 case IP6T_SO_GET_INFO: {
1181 char name[IP6T_TABLE_MAXNAMELEN];
1184 if (*len != sizeof(struct ip6t_getinfo)) {
1185 duprintf("length %u != %u\n", *len,
1186 sizeof(struct ip6t_getinfo));
1191 if (copy_from_user(name, user, sizeof(name)) != 0) {
1195 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1197 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1198 "ip6table_%s", name);
1199 if (t && !IS_ERR(t)) {
1200 struct ip6t_getinfo info;
1201 struct xt_table_info *private = t->private;
1203 info.valid_hooks = t->valid_hooks;
1204 memcpy(info.hook_entry, private->hook_entry,
1205 sizeof(info.hook_entry));
1206 memcpy(info.underflow, private->underflow,
1207 sizeof(info.underflow));
1208 info.num_entries = private->number;
1209 info.size = private->size;
1210 memcpy(info.name, name, sizeof(info.name));
1212 if (copy_to_user(user, &info, *len) != 0)
1219 ret = t ? PTR_ERR(t) : -ENOENT;
1223 case IP6T_SO_GET_ENTRIES: {
1224 struct ip6t_get_entries get;
1226 if (*len < sizeof(get)) {
1227 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1229 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1231 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1232 duprintf("get_entries: %u != %u\n", *len,
1233 sizeof(struct ip6t_get_entries) + get.size);
1236 ret = get_entries(&get, user);
1240 case IP6T_SO_GET_REVISION_MATCH:
1241 case IP6T_SO_GET_REVISION_TARGET: {
1242 struct ip6t_get_revision rev;
1245 if (*len != sizeof(rev)) {
1249 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1254 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1259 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1262 "ip6t_%s", rev.name);
1267 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1274 int ip6t_register_table(struct xt_table *table,
1275 const struct ip6t_replace *repl)
1278 struct xt_table_info *newinfo;
1279 static struct xt_table_info bootstrap
1280 = { 0, 0, 0, { 0 }, { 0 }, { } };
1281 void *loc_cpu_entry;
1283 newinfo = xt_alloc_table_info(repl->size);
1287 /* choose the copy on our node/cpu */
1288 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1289 memcpy(loc_cpu_entry, repl->entries, repl->size);
1291 ret = translate_table(table->name, table->valid_hooks,
1292 newinfo, loc_cpu_entry, repl->size,
1297 xt_free_table_info(newinfo);
1301 if (xt_register_table(table, &bootstrap, newinfo) != 0) {
1302 xt_free_table_info(newinfo);
1309 void ip6t_unregister_table(struct xt_table *table)
1311 struct xt_table_info *private;
1312 void *loc_cpu_entry;
1314 private = xt_unregister_table(table);
1316 /* Decrease module usage counts and free resources */
1317 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1318 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1319 xt_free_table_info(private);
1322 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1324 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1325 u_int8_t type, u_int8_t code,
1328 return (type == test_type && code >= min_code && code <= max_code)
1333 icmp6_match(const struct sk_buff *skb,
1334 const struct net_device *in,
1335 const struct net_device *out,
1336 const void *matchinfo,
1338 unsigned int protoff,
1341 struct icmp6hdr _icmp, *ic;
1342 const struct ip6t_icmp *icmpinfo = matchinfo;
1344 /* Must not be a fragment. */
1348 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1350 /* We've been asked to examine this packet, and we
1351 can't. Hence, no choice but to drop. */
1352 duprintf("Dropping evil ICMP tinygram.\n");
1357 return icmp6_type_code_match(icmpinfo->type,
1360 ic->icmp6_type, ic->icmp6_code,
1361 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1364 /* Called when user tries to insert an entry of this type. */
1366 icmp6_checkentry(const char *tablename,
1369 unsigned int matchsize,
1370 unsigned int hook_mask)
1372 const struct ip6t_ip6 *ipv6 = entry;
1373 const struct ip6t_icmp *icmpinfo = matchinfo;
1375 /* Must specify proto == ICMP, and no unknown invflags */
1376 return ipv6->proto == IPPROTO_ICMPV6
1377 && !(ipv6->invflags & IP6T_INV_PROTO)
1378 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1379 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1382 /* The built-in targets: standard (NULL) and error. */
1383 static struct ip6t_target ip6t_standard_target = {
1384 .name = IP6T_STANDARD_TARGET,
1387 static struct ip6t_target ip6t_error_target = {
1388 .name = IP6T_ERROR_TARGET,
1389 .target = ip6t_error,
1392 static struct nf_sockopt_ops ip6t_sockopts = {
1394 .set_optmin = IP6T_BASE_CTL,
1395 .set_optmax = IP6T_SO_SET_MAX+1,
1396 .set = do_ip6t_set_ctl,
1397 .get_optmin = IP6T_BASE_CTL,
1398 .get_optmax = IP6T_SO_GET_MAX+1,
1399 .get = do_ip6t_get_ctl,
1402 static struct ip6t_match icmp6_matchstruct = {
1404 .match = &icmp6_match,
1405 .checkentry = &icmp6_checkentry,
1408 static int __init init(void)
1412 xt_proto_init(AF_INET6);
1414 /* Noone else will be downing sem now, so we won't sleep */
1415 xt_register_target(AF_INET6, &ip6t_standard_target);
1416 xt_register_target(AF_INET6, &ip6t_error_target);
1417 xt_register_match(AF_INET6, &icmp6_matchstruct);
1419 /* Register setsockopt */
1420 ret = nf_register_sockopt(&ip6t_sockopts);
1422 duprintf("Unable to register sockopts.\n");
1423 xt_proto_fini(AF_INET6);
1427 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1431 static void __exit fini(void)
1433 nf_unregister_sockopt(&ip6t_sockopts);
1434 xt_unregister_match(AF_INET6, &icmp6_matchstruct);
1435 xt_unregister_target(AF_INET6, &ip6t_error_target);
1436 xt_unregister_target(AF_INET6, &ip6t_standard_target);
1437 xt_proto_fini(AF_INET6);
1441 * find the offset to specified header or the protocol number of last header
1442 * if target < 0. "last header" is transport protocol header, ESP, or
1445 * If target header is found, its offset is set in *offset and return protocol
1446 * number. Otherwise, return -1.
1448 * Note that non-1st fragment is special case that "the protocol number
1449 * of last header" is "next header" field in Fragment header. In this case,
1450 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1454 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1455 int target, unsigned short *fragoff)
1457 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1458 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1459 unsigned int len = skb->len - start;
1464 while (nexthdr != target) {
1465 struct ipv6_opt_hdr _hdr, *hp;
1466 unsigned int hdrlen;
1468 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1474 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1477 if (nexthdr == NEXTHDR_FRAGMENT) {
1478 unsigned short _frag_off, *fp;
1479 fp = skb_header_pointer(skb,
1480 start+offsetof(struct frag_hdr,
1487 _frag_off = ntohs(*fp) & ~0x7;
1490 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1491 nexthdr == NEXTHDR_NONE)) {
1493 *fragoff = _frag_off;
1499 } else if (nexthdr == NEXTHDR_AUTH)
1500 hdrlen = (hp->hdrlen + 2) << 2;
1502 hdrlen = ipv6_optlen(hp);
1504 nexthdr = hp->nexthdr;
1513 EXPORT_SYMBOL(ip6t_register_table);
1514 EXPORT_SYMBOL(ip6t_unregister_table);
1515 EXPORT_SYMBOL(ip6t_do_table);
1516 EXPORT_SYMBOL(ip6t_ext_hdr);
1517 EXPORT_SYMBOL(ipv6_find_hdr);
1518 EXPORT_SYMBOL(ip6_masked_addrcmp);