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.
12 #include <linux/capability.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/poison.h>
20 #include <linux/icmpv6.h>
22 #include <asm/uaccess.h>
23 #include <linux/mutex.h>
24 #include <linux/proc_fs.h>
25 #include <linux/cpumask.h>
27 #include <linux/netfilter_ipv6/ip6_tables.h>
28 #include <linux/netfilter/x_tables.h>
30 MODULE_LICENSE("GPL");
31 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
32 MODULE_DESCRIPTION("IPv6 packet filter");
34 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
35 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
37 /*#define DEBUG_IP_FIREWALL*/
38 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
39 /*#define DEBUG_IP_FIREWALL_USER*/
41 #ifdef DEBUG_IP_FIREWALL
42 #define dprintf(format, args...) printk(format , ## args)
44 #define dprintf(format, args...)
47 #ifdef DEBUG_IP_FIREWALL_USER
48 #define duprintf(format, args...) printk(format , ## args)
50 #define duprintf(format, args...)
53 #ifdef CONFIG_NETFILTER_DEBUG
54 #define IP_NF_ASSERT(x) \
57 printk("IP_NF_ASSERT: %s:%s:%u\n", \
58 __FUNCTION__, __FILE__, __LINE__); \
61 #define IP_NF_ASSERT(x)
65 /* All the better to debug you with... */
71 We keep a set of rules for each CPU, so we can avoid write-locking
72 them in the softirq when updating the counters and therefore
73 only need to read-lock in the softirq; doing a write_lock_bh() in user
74 context stops packets coming through and allows user context to read
75 the counters or update the rules.
77 Hence the start of any table is given by get_table() below. */
80 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
81 #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; })
82 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
85 /* Check for an extension */
87 ip6t_ext_hdr(u8 nexthdr)
89 return ( (nexthdr == IPPROTO_HOPOPTS) ||
90 (nexthdr == IPPROTO_ROUTING) ||
91 (nexthdr == IPPROTO_FRAGMENT) ||
92 (nexthdr == IPPROTO_ESP) ||
93 (nexthdr == IPPROTO_AH) ||
94 (nexthdr == IPPROTO_NONE) ||
95 (nexthdr == IPPROTO_DSTOPTS) );
98 /* Returns whether matches rule or not. */
100 ip6_packet_match(const struct sk_buff *skb,
103 const struct ip6t_ip6 *ip6info,
104 unsigned int *protoff,
105 int *fragoff, bool *hotdrop)
109 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
111 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
113 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
114 &ip6info->src), IP6T_INV_SRCIP)
115 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
116 &ip6info->dst), IP6T_INV_DSTIP)) {
117 dprintf("Source or dest mismatch.\n");
119 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
120 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
121 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
122 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
123 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
124 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
128 /* Look for ifname matches; this should unroll nicely. */
129 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
130 ret |= (((const unsigned long *)indev)[i]
131 ^ ((const unsigned long *)ip6info->iniface)[i])
132 & ((const unsigned long *)ip6info->iniface_mask)[i];
135 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
136 dprintf("VIA in mismatch (%s vs %s).%s\n",
137 indev, ip6info->iniface,
138 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
142 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
143 ret |= (((const unsigned long *)outdev)[i]
144 ^ ((const unsigned long *)ip6info->outiface)[i])
145 & ((const unsigned long *)ip6info->outiface_mask)[i];
148 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
149 dprintf("VIA out mismatch (%s vs %s).%s\n",
150 outdev, ip6info->outiface,
151 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
155 /* ... might want to do something with class and flowlabel here ... */
157 /* look for the desired protocol header */
158 if((ip6info->flags & IP6T_F_PROTO)) {
160 unsigned short _frag_off;
162 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
168 *fragoff = _frag_off;
170 dprintf("Packet protocol %hi ?= %s%hi.\n",
172 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
175 if (ip6info->proto == protohdr) {
176 if(ip6info->invflags & IP6T_INV_PROTO) {
182 /* We need match for the '-p all', too! */
183 if ((ip6info->proto != 0) &&
184 !(ip6info->invflags & IP6T_INV_PROTO))
190 /* should be ip6 safe */
192 ip6_checkentry(const struct ip6t_ip6 *ipv6)
194 if (ipv6->flags & ~IP6T_F_MASK) {
195 duprintf("Unknown flag bits set: %08X\n",
196 ipv6->flags & ~IP6T_F_MASK);
199 if (ipv6->invflags & ~IP6T_INV_MASK) {
200 duprintf("Unknown invflag bits set: %08X\n",
201 ipv6->invflags & ~IP6T_INV_MASK);
208 ip6t_error(struct sk_buff **pskb,
209 const struct net_device *in,
210 const struct net_device *out,
211 unsigned int hooknum,
212 const struct xt_target *target,
213 const void *targinfo)
216 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
222 bool do_match(struct ip6t_entry_match *m,
223 const struct sk_buff *skb,
224 const struct net_device *in,
225 const struct net_device *out,
227 unsigned int protoff,
230 /* Stop iteration if it doesn't match */
231 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
232 offset, protoff, hotdrop))
238 static inline struct ip6t_entry *
239 get_entry(void *base, unsigned int offset)
241 return (struct ip6t_entry *)(base + offset);
244 /* All zeroes == unconditional rule. */
246 unconditional(const struct ip6t_ip6 *ipv6)
250 for (i = 0; i < sizeof(*ipv6); i++)
251 if (((char *)ipv6)[i])
254 return (i == sizeof(*ipv6));
257 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
258 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
259 /* This cries for unification! */
260 static const char *hooknames[] = {
261 [NF_IP6_PRE_ROUTING] = "PREROUTING",
262 [NF_IP6_LOCAL_IN] = "INPUT",
263 [NF_IP6_FORWARD] = "FORWARD",
264 [NF_IP6_LOCAL_OUT] = "OUTPUT",
265 [NF_IP6_POST_ROUTING] = "POSTROUTING",
268 enum nf_ip_trace_comments {
269 NF_IP6_TRACE_COMMENT_RULE,
270 NF_IP6_TRACE_COMMENT_RETURN,
271 NF_IP6_TRACE_COMMENT_POLICY,
274 static const char *comments[] = {
275 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
276 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
277 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
280 static struct nf_loginfo trace_loginfo = {
281 .type = NF_LOG_TYPE_LOG,
285 .logflags = NF_LOG_MASK,
291 get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
292 char *hookname, char **chainname,
293 char **comment, unsigned int *rulenum)
295 struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
297 if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
298 /* Head of user chain: ERROR target with chainname */
299 *chainname = t->target.data;
304 if (s->target_offset == sizeof(struct ip6t_entry)
305 && strcmp(t->target.u.kernel.target->name,
306 IP6T_STANDARD_TARGET) == 0
308 && unconditional(&s->ipv6)) {
309 /* Tail of chains: STANDARD target (return/policy) */
310 *comment = *chainname == hookname
311 ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY]
312 : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN];
321 static void trace_packet(struct sk_buff *skb,
323 const struct net_device *in,
324 const struct net_device *out,
326 struct xt_table_info *private,
327 struct ip6t_entry *e)
330 struct ip6t_entry *root;
331 char *hookname, *chainname, *comment;
332 unsigned int rulenum = 0;
334 table_base = (void *)private->entries[smp_processor_id()];
335 root = get_entry(table_base, private->hook_entry[hook]);
337 hookname = chainname = (char *)hooknames[hook];
338 comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE];
340 IP6T_ENTRY_ITERATE(root,
341 private->size - private->hook_entry[hook],
342 get_chainname_rulenum,
343 e, hookname, &chainname, &comment, &rulenum);
345 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
346 "TRACE: %s:%s:%s:%u ",
347 tablename, chainname, comment, rulenum);
351 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
353 ip6t_do_table(struct sk_buff **pskb,
355 const struct net_device *in,
356 const struct net_device *out,
357 struct xt_table *table)
359 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
361 unsigned int protoff = 0;
362 bool hotdrop = false;
363 /* Initializing verdict to NF_DROP keeps gcc happy. */
364 unsigned int verdict = NF_DROP;
365 const char *indev, *outdev;
367 struct ip6t_entry *e, *back;
368 struct xt_table_info *private;
371 indev = in ? in->name : nulldevname;
372 outdev = out ? out->name : nulldevname;
373 /* We handle fragments by dealing with the first fragment as
374 * if it was a normal packet. All other fragments are treated
375 * normally, except that they will NEVER match rules that ask
376 * things we don't know, ie. tcp syn flag or ports). If the
377 * rule is also a fragment-specific rule, non-fragments won't
380 read_lock_bh(&table->lock);
381 private = table->private;
382 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
383 table_base = (void *)private->entries[smp_processor_id()];
384 e = get_entry(table_base, private->hook_entry[hook]);
386 /* For return from builtin chain */
387 back = get_entry(table_base, private->underflow[hook]);
392 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
393 &protoff, &offset, &hotdrop)) {
394 struct ip6t_entry_target *t;
396 if (IP6T_MATCH_ITERATE(e, do_match,
398 offset, protoff, &hotdrop) != 0)
401 ADD_COUNTER(e->counters,
402 ntohs(ipv6_hdr(*pskb)->payload_len)
406 t = ip6t_get_target(e);
407 IP_NF_ASSERT(t->u.kernel.target);
409 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
410 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
411 /* The packet is traced: log it */
412 if (unlikely((*pskb)->nf_trace))
413 trace_packet(*pskb, hook, in, out,
414 table->name, private, e);
416 /* Standard target? */
417 if (!t->u.kernel.target->target) {
420 v = ((struct ip6t_standard_target *)t)->verdict;
422 /* Pop from stack? */
423 if (v != IP6T_RETURN) {
424 verdict = (unsigned)(-v) - 1;
428 back = get_entry(table_base,
432 if (table_base + v != (void *)e + e->next_offset
433 && !(e->ipv6.flags & IP6T_F_GOTO)) {
434 /* Save old back ptr in next entry */
435 struct ip6t_entry *next
436 = (void *)e + e->next_offset;
438 = (void *)back - table_base;
439 /* set back pointer to next entry */
443 e = get_entry(table_base, v);
445 /* Targets which reenter must return
447 #ifdef CONFIG_NETFILTER_DEBUG
448 ((struct ip6t_entry *)table_base)->comefrom
451 verdict = t->u.kernel.target->target(pskb,
457 #ifdef CONFIG_NETFILTER_DEBUG
458 if (((struct ip6t_entry *)table_base)->comefrom
460 && verdict == IP6T_CONTINUE) {
461 printk("Target %s reentered!\n",
462 t->u.kernel.target->name);
465 ((struct ip6t_entry *)table_base)->comefrom
468 if (verdict == IP6T_CONTINUE)
469 e = (void *)e + e->next_offset;
477 e = (void *)e + e->next_offset;
481 #ifdef CONFIG_NETFILTER_DEBUG
482 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
484 read_unlock_bh(&table->lock);
486 #ifdef DEBUG_ALLOW_ALL
495 /* Figures out from what hook each rule can be called: returns 0 if
496 there are loops. Puts hook bitmask in comefrom. */
498 mark_source_chains(struct xt_table_info *newinfo,
499 unsigned int valid_hooks, void *entry0)
503 /* No recursion; use packet counter to save back ptrs (reset
504 to 0 as we leave), and comefrom to save source hook bitmask */
505 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
506 unsigned int pos = newinfo->hook_entry[hook];
508 = (struct ip6t_entry *)(entry0 + pos);
509 int visited = e->comefrom & (1 << hook);
511 if (!(valid_hooks & (1 << hook)))
514 /* Set initial back pointer. */
515 e->counters.pcnt = pos;
518 struct ip6t_standard_target *t
519 = (void *)ip6t_get_target(e);
521 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
522 printk("iptables: loop hook %u pos %u %08X.\n",
523 hook, pos, e->comefrom);
527 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
529 /* Unconditional return/END. */
530 if ((e->target_offset == sizeof(struct ip6t_entry)
531 && (strcmp(t->target.u.user.name,
532 IP6T_STANDARD_TARGET) == 0)
534 && unconditional(&e->ipv6)) || visited) {
535 unsigned int oldpos, size;
537 if (t->verdict < -NF_MAX_VERDICT - 1) {
538 duprintf("mark_source_chains: bad "
539 "negative verdict (%i)\n",
544 /* Return: backtrack through the last
547 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
548 #ifdef DEBUG_IP_FIREWALL_USER
550 & (1 << NF_IP6_NUMHOOKS)) {
551 duprintf("Back unset "
558 pos = e->counters.pcnt;
559 e->counters.pcnt = 0;
561 /* We're at the start. */
565 e = (struct ip6t_entry *)
567 } while (oldpos == pos + e->next_offset);
570 size = e->next_offset;
571 e = (struct ip6t_entry *)
572 (entry0 + pos + size);
573 e->counters.pcnt = pos;
576 int newpos = t->verdict;
578 if (strcmp(t->target.u.user.name,
579 IP6T_STANDARD_TARGET) == 0
581 if (newpos > newinfo->size -
582 sizeof(struct ip6t_entry)) {
583 duprintf("mark_source_chains: "
584 "bad verdict (%i)\n",
588 /* This a jump; chase it. */
589 duprintf("Jump rule %u -> %u\n",
592 /* ... this is a fallthru */
593 newpos = pos + e->next_offset;
595 e = (struct ip6t_entry *)
597 e->counters.pcnt = pos;
602 duprintf("Finished chain %u\n", hook);
608 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
610 if (i && (*i)-- == 0)
613 if (m->u.kernel.match->destroy)
614 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
615 module_put(m->u.kernel.match->me);
620 check_match(struct ip6t_entry_match *m,
622 const struct ip6t_ip6 *ipv6,
623 unsigned int hookmask,
626 struct xt_match *match;
629 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
631 "ip6t_%s", m->u.user.name);
632 if (IS_ERR(match) || !match) {
633 duprintf("check_match: `%s' not found\n", m->u.user.name);
634 return match ? PTR_ERR(match) : -ENOENT;
636 m->u.kernel.match = match;
638 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
639 name, hookmask, ipv6->proto,
640 ipv6->invflags & IP6T_INV_PROTO);
644 if (m->u.kernel.match->checkentry
645 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
647 duprintf("ip_tables: check failed for `%s'.\n",
648 m->u.kernel.match->name);
656 module_put(m->u.kernel.match->me);
660 static struct xt_target ip6t_standard_target;
663 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
666 struct ip6t_entry_target *t;
667 struct xt_target *target;
671 if (!ip6_checkentry(&e->ipv6)) {
672 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
676 if (e->target_offset + sizeof(struct ip6t_entry_target) >
681 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
683 goto cleanup_matches;
685 t = ip6t_get_target(e);
687 if (e->target_offset + t->u.target_size > e->next_offset)
688 goto cleanup_matches;
689 target = try_then_request_module(xt_find_target(AF_INET6,
692 "ip6t_%s", t->u.user.name);
693 if (IS_ERR(target) || !target) {
694 duprintf("check_entry: `%s' not found\n", t->u.user.name);
695 ret = target ? PTR_ERR(target) : -ENOENT;
696 goto cleanup_matches;
698 t->u.kernel.target = target;
700 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
701 name, e->comefrom, e->ipv6.proto,
702 e->ipv6.invflags & IP6T_INV_PROTO);
706 if (t->u.kernel.target->checkentry
707 && !t->u.kernel.target->checkentry(name, e, target, t->data,
709 duprintf("ip_tables: check failed for `%s'.\n",
710 t->u.kernel.target->name);
718 module_put(t->u.kernel.target->me);
720 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
725 check_entry_size_and_hooks(struct ip6t_entry *e,
726 struct xt_table_info *newinfo,
728 unsigned char *limit,
729 const unsigned int *hook_entries,
730 const unsigned int *underflows,
735 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
736 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
737 duprintf("Bad offset %p\n", e);
742 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
743 duprintf("checking: element %p size %u\n",
748 /* Check hooks & underflows */
749 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
750 if ((unsigned char *)e - base == hook_entries[h])
751 newinfo->hook_entry[h] = hook_entries[h];
752 if ((unsigned char *)e - base == underflows[h])
753 newinfo->underflow[h] = underflows[h];
756 /* FIXME: underflows must be unconditional, standard verdicts
757 < 0 (not IP6T_RETURN). --RR */
759 /* Clear counters and comefrom */
760 e->counters = ((struct xt_counters) { 0, 0 });
768 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
770 struct ip6t_entry_target *t;
772 if (i && (*i)-- == 0)
775 /* Cleanup all matches */
776 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
777 t = ip6t_get_target(e);
778 if (t->u.kernel.target->destroy)
779 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
780 module_put(t->u.kernel.target->me);
784 /* Checks and translates the user-supplied table segment (held in
787 translate_table(const char *name,
788 unsigned int valid_hooks,
789 struct xt_table_info *newinfo,
793 const unsigned int *hook_entries,
794 const unsigned int *underflows)
799 newinfo->size = size;
800 newinfo->number = number;
802 /* Init all hooks to impossible value. */
803 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
804 newinfo->hook_entry[i] = 0xFFFFFFFF;
805 newinfo->underflow[i] = 0xFFFFFFFF;
808 duprintf("translate_table: size %u\n", newinfo->size);
810 /* Walk through entries, checking offsets. */
811 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
812 check_entry_size_and_hooks,
816 hook_entries, underflows, &i);
821 duprintf("translate_table: %u not %u entries\n",
826 /* Check hooks all assigned */
827 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
828 /* Only hooks which are valid */
829 if (!(valid_hooks & (1 << i)))
831 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
832 duprintf("Invalid hook entry %u %u\n",
836 if (newinfo->underflow[i] == 0xFFFFFFFF) {
837 duprintf("Invalid underflow %u %u\n",
843 if (!mark_source_chains(newinfo, valid_hooks, entry0))
846 /* Finally, each sanity check must pass */
848 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
849 check_entry, name, size, &i);
852 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
857 /* And one copy for every other CPU */
858 for_each_possible_cpu(i) {
859 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
860 memcpy(newinfo->entries[i], entry0, newinfo->size);
868 add_entry_to_counter(const struct ip6t_entry *e,
869 struct xt_counters total[],
872 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
879 set_entry_to_counter(const struct ip6t_entry *e,
880 struct ip6t_counters total[],
883 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
890 get_counters(const struct xt_table_info *t,
891 struct xt_counters counters[])
897 /* Instead of clearing (by a previous call to memset())
898 * the counters and using adds, we set the counters
899 * with data used by 'current' CPU
900 * We dont care about preemption here.
902 curcpu = raw_smp_processor_id();
905 IP6T_ENTRY_ITERATE(t->entries[curcpu],
907 set_entry_to_counter,
911 for_each_possible_cpu(cpu) {
915 IP6T_ENTRY_ITERATE(t->entries[cpu],
917 add_entry_to_counter,
924 copy_entries_to_user(unsigned int total_size,
925 struct xt_table *table,
926 void __user *userptr)
928 unsigned int off, num, countersize;
929 struct ip6t_entry *e;
930 struct xt_counters *counters;
931 struct xt_table_info *private = table->private;
935 /* We need atomic snapshot of counters: rest doesn't change
936 (other than comefrom, which userspace doesn't care
938 countersize = sizeof(struct xt_counters) * private->number;
939 counters = vmalloc(countersize);
941 if (counters == NULL)
944 /* First, sum counters... */
945 write_lock_bh(&table->lock);
946 get_counters(private, counters);
947 write_unlock_bh(&table->lock);
949 /* choose the copy that is on ourc node/cpu */
950 loc_cpu_entry = private->entries[raw_smp_processor_id()];
951 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
956 /* FIXME: use iterator macros --RR */
957 /* ... then go back and fix counters and names */
958 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
960 struct ip6t_entry_match *m;
961 struct ip6t_entry_target *t;
963 e = (struct ip6t_entry *)(loc_cpu_entry + off);
964 if (copy_to_user(userptr + off
965 + offsetof(struct ip6t_entry, counters),
967 sizeof(counters[num])) != 0) {
972 for (i = sizeof(struct ip6t_entry);
973 i < e->target_offset;
974 i += m->u.match_size) {
977 if (copy_to_user(userptr + off + i
978 + offsetof(struct ip6t_entry_match,
980 m->u.kernel.match->name,
981 strlen(m->u.kernel.match->name)+1)
988 t = ip6t_get_target(e);
989 if (copy_to_user(userptr + off + e->target_offset
990 + offsetof(struct ip6t_entry_target,
992 t->u.kernel.target->name,
993 strlen(t->u.kernel.target->name)+1) != 0) {
1005 get_entries(const struct ip6t_get_entries *entries,
1006 struct ip6t_get_entries __user *uptr)
1011 t = xt_find_table_lock(AF_INET6, entries->name);
1012 if (t && !IS_ERR(t)) {
1013 struct xt_table_info *private = t->private;
1014 duprintf("t->private->number = %u\n", private->number);
1015 if (entries->size == private->size)
1016 ret = copy_entries_to_user(private->size,
1017 t, uptr->entrytable);
1019 duprintf("get_entries: I've got %u not %u!\n",
1020 private->size, entries->size);
1026 ret = t ? PTR_ERR(t) : -ENOENT;
1032 do_replace(void __user *user, unsigned int len)
1035 struct ip6t_replace tmp;
1037 struct xt_table_info *newinfo, *oldinfo;
1038 struct xt_counters *counters;
1039 void *loc_cpu_entry, *loc_cpu_old_entry;
1041 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1044 /* overflow check */
1045 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1048 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1051 newinfo = xt_alloc_table_info(tmp.size);
1055 /* choose the copy that is on our node/cpu */
1056 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1057 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1063 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1069 ret = translate_table(tmp.name, tmp.valid_hooks,
1070 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1071 tmp.hook_entry, tmp.underflow);
1073 goto free_newinfo_counters;
1075 duprintf("ip_tables: Translated table\n");
1077 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1078 "ip6table_%s", tmp.name);
1079 if (!t || IS_ERR(t)) {
1080 ret = t ? PTR_ERR(t) : -ENOENT;
1081 goto free_newinfo_counters_untrans;
1085 if (tmp.valid_hooks != t->valid_hooks) {
1086 duprintf("Valid hook crap: %08X vs %08X\n",
1087 tmp.valid_hooks, t->valid_hooks);
1092 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1096 /* Update module usage count based on number of rules */
1097 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1098 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1099 if ((oldinfo->number > oldinfo->initial_entries) ||
1100 (newinfo->number <= oldinfo->initial_entries))
1102 if ((oldinfo->number > oldinfo->initial_entries) &&
1103 (newinfo->number <= oldinfo->initial_entries))
1106 /* Get the old counters. */
1107 get_counters(oldinfo, counters);
1108 /* Decrease module usage counts and free resource */
1109 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1110 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1111 xt_free_table_info(oldinfo);
1112 if (copy_to_user(tmp.counters, counters,
1113 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1122 free_newinfo_counters_untrans:
1123 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1124 free_newinfo_counters:
1127 xt_free_table_info(newinfo);
1131 /* We're lazy, and add to the first CPU; overflow works its fey magic
1132 * and everything is OK. */
1134 add_counter_to_entry(struct ip6t_entry *e,
1135 const struct xt_counters addme[],
1139 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1141 (long unsigned int)e->counters.pcnt,
1142 (long unsigned int)e->counters.bcnt,
1143 (long unsigned int)addme[*i].pcnt,
1144 (long unsigned int)addme[*i].bcnt);
1147 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1154 do_add_counters(void __user *user, unsigned int len)
1157 struct xt_counters_info tmp, *paddc;
1158 struct xt_table_info *private;
1161 void *loc_cpu_entry;
1163 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1166 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1169 paddc = vmalloc(len);
1173 if (copy_from_user(paddc, user, len) != 0) {
1178 t = xt_find_table_lock(AF_INET6, tmp.name);
1179 if (!t || IS_ERR(t)) {
1180 ret = t ? PTR_ERR(t) : -ENOENT;
1184 write_lock_bh(&t->lock);
1185 private = t->private;
1186 if (private->number != tmp.num_counters) {
1188 goto unlock_up_free;
1192 /* Choose the copy that is on our node */
1193 loc_cpu_entry = private->entries[smp_processor_id()];
1194 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1196 add_counter_to_entry,
1200 write_unlock_bh(&t->lock);
1210 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1214 if (!capable(CAP_NET_ADMIN))
1218 case IP6T_SO_SET_REPLACE:
1219 ret = do_replace(user, len);
1222 case IP6T_SO_SET_ADD_COUNTERS:
1223 ret = do_add_counters(user, len);
1227 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1235 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1239 if (!capable(CAP_NET_ADMIN))
1243 case IP6T_SO_GET_INFO: {
1244 char name[IP6T_TABLE_MAXNAMELEN];
1247 if (*len != sizeof(struct ip6t_getinfo)) {
1248 duprintf("length %u != %u\n", *len,
1249 sizeof(struct ip6t_getinfo));
1254 if (copy_from_user(name, user, sizeof(name)) != 0) {
1258 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1260 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1261 "ip6table_%s", name);
1262 if (t && !IS_ERR(t)) {
1263 struct ip6t_getinfo info;
1264 struct xt_table_info *private = t->private;
1266 info.valid_hooks = t->valid_hooks;
1267 memcpy(info.hook_entry, private->hook_entry,
1268 sizeof(info.hook_entry));
1269 memcpy(info.underflow, private->underflow,
1270 sizeof(info.underflow));
1271 info.num_entries = private->number;
1272 info.size = private->size;
1273 memcpy(info.name, name, sizeof(info.name));
1275 if (copy_to_user(user, &info, *len) != 0)
1282 ret = t ? PTR_ERR(t) : -ENOENT;
1286 case IP6T_SO_GET_ENTRIES: {
1287 struct ip6t_get_entries get;
1289 if (*len < sizeof(get)) {
1290 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1292 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1294 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1295 duprintf("get_entries: %u != %u\n", *len,
1296 sizeof(struct ip6t_get_entries) + get.size);
1299 ret = get_entries(&get, user);
1303 case IP6T_SO_GET_REVISION_MATCH:
1304 case IP6T_SO_GET_REVISION_TARGET: {
1305 struct ip6t_get_revision rev;
1308 if (*len != sizeof(rev)) {
1312 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1317 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1322 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1325 "ip6t_%s", rev.name);
1330 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1337 int ip6t_register_table(struct xt_table *table,
1338 const struct ip6t_replace *repl)
1341 struct xt_table_info *newinfo;
1342 static struct xt_table_info bootstrap
1343 = { 0, 0, 0, { 0 }, { 0 }, { } };
1344 void *loc_cpu_entry;
1346 newinfo = xt_alloc_table_info(repl->size);
1350 /* choose the copy on our node/cpu */
1351 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1352 memcpy(loc_cpu_entry, repl->entries, repl->size);
1354 ret = translate_table(table->name, table->valid_hooks,
1355 newinfo, loc_cpu_entry, repl->size,
1360 xt_free_table_info(newinfo);
1364 ret = xt_register_table(table, &bootstrap, newinfo);
1366 xt_free_table_info(newinfo);
1373 void ip6t_unregister_table(struct xt_table *table)
1375 struct xt_table_info *private;
1376 void *loc_cpu_entry;
1378 private = xt_unregister_table(table);
1380 /* Decrease module usage counts and free resources */
1381 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1382 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1383 xt_free_table_info(private);
1386 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1388 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1389 u_int8_t type, u_int8_t code,
1392 return (type == test_type && code >= min_code && code <= max_code)
1397 icmp6_match(const struct sk_buff *skb,
1398 const struct net_device *in,
1399 const struct net_device *out,
1400 const struct xt_match *match,
1401 const void *matchinfo,
1403 unsigned int protoff,
1406 struct icmp6hdr _icmp, *ic;
1407 const struct ip6t_icmp *icmpinfo = matchinfo;
1409 /* Must not be a fragment. */
1413 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1415 /* We've been asked to examine this packet, and we
1416 can't. Hence, no choice but to drop. */
1417 duprintf("Dropping evil ICMP tinygram.\n");
1422 return icmp6_type_code_match(icmpinfo->type,
1425 ic->icmp6_type, ic->icmp6_code,
1426 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1429 /* Called when user tries to insert an entry of this type. */
1431 icmp6_checkentry(const char *tablename,
1433 const struct xt_match *match,
1435 unsigned int hook_mask)
1437 const struct ip6t_icmp *icmpinfo = matchinfo;
1439 /* Must specify no unknown invflags */
1440 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1443 /* The built-in targets: standard (NULL) and error. */
1444 static struct xt_target ip6t_standard_target __read_mostly = {
1445 .name = IP6T_STANDARD_TARGET,
1446 .targetsize = sizeof(int),
1450 static struct xt_target ip6t_error_target __read_mostly = {
1451 .name = IP6T_ERROR_TARGET,
1452 .target = ip6t_error,
1453 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1457 static struct nf_sockopt_ops ip6t_sockopts = {
1459 .set_optmin = IP6T_BASE_CTL,
1460 .set_optmax = IP6T_SO_SET_MAX+1,
1461 .set = do_ip6t_set_ctl,
1462 .get_optmin = IP6T_BASE_CTL,
1463 .get_optmax = IP6T_SO_GET_MAX+1,
1464 .get = do_ip6t_get_ctl,
1467 static struct xt_match icmp6_matchstruct __read_mostly = {
1469 .match = &icmp6_match,
1470 .matchsize = sizeof(struct ip6t_icmp),
1471 .checkentry = icmp6_checkentry,
1472 .proto = IPPROTO_ICMPV6,
1476 static int __init ip6_tables_init(void)
1480 ret = xt_proto_init(AF_INET6);
1484 /* Noone else will be downing sem now, so we won't sleep */
1485 ret = xt_register_target(&ip6t_standard_target);
1488 ret = xt_register_target(&ip6t_error_target);
1491 ret = xt_register_match(&icmp6_matchstruct);
1495 /* Register setsockopt */
1496 ret = nf_register_sockopt(&ip6t_sockopts);
1500 printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1504 xt_unregister_match(&icmp6_matchstruct);
1506 xt_unregister_target(&ip6t_error_target);
1508 xt_unregister_target(&ip6t_standard_target);
1510 xt_proto_fini(AF_INET6);
1515 static void __exit ip6_tables_fini(void)
1517 nf_unregister_sockopt(&ip6t_sockopts);
1518 xt_unregister_match(&icmp6_matchstruct);
1519 xt_unregister_target(&ip6t_error_target);
1520 xt_unregister_target(&ip6t_standard_target);
1521 xt_proto_fini(AF_INET6);
1525 * find the offset to specified header or the protocol number of last header
1526 * if target < 0. "last header" is transport protocol header, ESP, or
1529 * If target header is found, its offset is set in *offset and return protocol
1530 * number. Otherwise, return -1.
1532 * If the first fragment doesn't contain the final protocol header or
1533 * NEXTHDR_NONE it is considered invalid.
1535 * Note that non-1st fragment is special case that "the protocol number
1536 * of last header" is "next header" field in Fragment header. In this case,
1537 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1541 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1542 int target, unsigned short *fragoff)
1544 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
1545 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
1546 unsigned int len = skb->len - start;
1551 while (nexthdr != target) {
1552 struct ipv6_opt_hdr _hdr, *hp;
1553 unsigned int hdrlen;
1555 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1561 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1564 if (nexthdr == NEXTHDR_FRAGMENT) {
1565 unsigned short _frag_off;
1567 fp = skb_header_pointer(skb,
1568 start+offsetof(struct frag_hdr,
1575 _frag_off = ntohs(*fp) & ~0x7;
1578 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1579 hp->nexthdr == NEXTHDR_NONE)) {
1581 *fragoff = _frag_off;
1587 } else if (nexthdr == NEXTHDR_AUTH)
1588 hdrlen = (hp->hdrlen + 2) << 2;
1590 hdrlen = ipv6_optlen(hp);
1592 nexthdr = hp->nexthdr;
1601 EXPORT_SYMBOL(ip6t_register_table);
1602 EXPORT_SYMBOL(ip6t_unregister_table);
1603 EXPORT_SYMBOL(ip6t_do_table);
1604 EXPORT_SYMBOL(ip6t_ext_hdr);
1605 EXPORT_SYMBOL(ipv6_find_hdr);
1607 module_init(ip6_tables_init);
1608 module_exit(ip6_tables_fini);