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 *skb,
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_INET_PRE_ROUTING] = "PREROUTING",
262 [NF_INET_LOCAL_IN] = "INPUT",
263 [NF_INET_FORWARD] = "FORWARD",
264 [NF_INET_LOCAL_OUT] = "OUTPUT",
265 [NF_INET_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 *skb,
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(skb, 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(skb)->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(skb->nf_trace))
413 trace_packet(skb, 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(skb,
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_INET_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_INET_NUMHOOKS)) {
522 printk("iptables: loop hook %u pos %u %08X.\n",
523 hook, pos, e->comefrom);
527 |= ((1 << hook) | (1 << NF_INET_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_INET_NUMHOOKS);
548 #ifdef DEBUG_IP_FIREWALL_USER
550 & (1 << NF_INET_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_INET_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_INET_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_INET_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.num_counters >= INT_MAX / sizeof(struct xt_counters))
1048 newinfo = xt_alloc_table_info(tmp.size);
1052 /* choose the copy that is on our node/cpu */
1053 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1054 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1060 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1066 ret = translate_table(tmp.name, tmp.valid_hooks,
1067 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1068 tmp.hook_entry, tmp.underflow);
1070 goto free_newinfo_counters;
1072 duprintf("ip_tables: Translated table\n");
1074 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1075 "ip6table_%s", tmp.name);
1076 if (!t || IS_ERR(t)) {
1077 ret = t ? PTR_ERR(t) : -ENOENT;
1078 goto free_newinfo_counters_untrans;
1082 if (tmp.valid_hooks != t->valid_hooks) {
1083 duprintf("Valid hook crap: %08X vs %08X\n",
1084 tmp.valid_hooks, t->valid_hooks);
1089 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1093 /* Update module usage count based on number of rules */
1094 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1095 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1096 if ((oldinfo->number > oldinfo->initial_entries) ||
1097 (newinfo->number <= oldinfo->initial_entries))
1099 if ((oldinfo->number > oldinfo->initial_entries) &&
1100 (newinfo->number <= oldinfo->initial_entries))
1103 /* Get the old counters. */
1104 get_counters(oldinfo, counters);
1105 /* Decrease module usage counts and free resource */
1106 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1107 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1108 xt_free_table_info(oldinfo);
1109 if (copy_to_user(tmp.counters, counters,
1110 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1119 free_newinfo_counters_untrans:
1120 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1121 free_newinfo_counters:
1124 xt_free_table_info(newinfo);
1128 /* We're lazy, and add to the first CPU; overflow works its fey magic
1129 * and everything is OK. */
1131 add_counter_to_entry(struct ip6t_entry *e,
1132 const struct xt_counters addme[],
1136 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1138 (long unsigned int)e->counters.pcnt,
1139 (long unsigned int)e->counters.bcnt,
1140 (long unsigned int)addme[*i].pcnt,
1141 (long unsigned int)addme[*i].bcnt);
1144 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1151 do_add_counters(void __user *user, unsigned int len)
1154 struct xt_counters_info tmp, *paddc;
1155 struct xt_table_info *private;
1158 void *loc_cpu_entry;
1160 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1163 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1166 paddc = vmalloc(len);
1170 if (copy_from_user(paddc, user, len) != 0) {
1175 t = xt_find_table_lock(AF_INET6, tmp.name);
1176 if (!t || IS_ERR(t)) {
1177 ret = t ? PTR_ERR(t) : -ENOENT;
1181 write_lock_bh(&t->lock);
1182 private = t->private;
1183 if (private->number != tmp.num_counters) {
1185 goto unlock_up_free;
1189 /* Choose the copy that is on our node */
1190 loc_cpu_entry = private->entries[smp_processor_id()];
1191 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1193 add_counter_to_entry,
1197 write_unlock_bh(&t->lock);
1207 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1211 if (!capable(CAP_NET_ADMIN))
1215 case IP6T_SO_SET_REPLACE:
1216 ret = do_replace(user, len);
1219 case IP6T_SO_SET_ADD_COUNTERS:
1220 ret = do_add_counters(user, len);
1224 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1232 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1236 if (!capable(CAP_NET_ADMIN))
1240 case IP6T_SO_GET_INFO: {
1241 char name[IP6T_TABLE_MAXNAMELEN];
1244 if (*len != sizeof(struct ip6t_getinfo)) {
1245 duprintf("length %u != %u\n", *len,
1246 sizeof(struct ip6t_getinfo));
1251 if (copy_from_user(name, user, sizeof(name)) != 0) {
1255 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1257 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1258 "ip6table_%s", name);
1259 if (t && !IS_ERR(t)) {
1260 struct ip6t_getinfo info;
1261 struct xt_table_info *private = t->private;
1263 info.valid_hooks = t->valid_hooks;
1264 memcpy(info.hook_entry, private->hook_entry,
1265 sizeof(info.hook_entry));
1266 memcpy(info.underflow, private->underflow,
1267 sizeof(info.underflow));
1268 info.num_entries = private->number;
1269 info.size = private->size;
1270 memcpy(info.name, name, sizeof(info.name));
1272 if (copy_to_user(user, &info, *len) != 0)
1279 ret = t ? PTR_ERR(t) : -ENOENT;
1283 case IP6T_SO_GET_ENTRIES: {
1284 struct ip6t_get_entries get;
1286 if (*len < sizeof(get)) {
1287 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1289 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1291 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1292 duprintf("get_entries: %u != %u\n", *len,
1293 sizeof(struct ip6t_get_entries) + get.size);
1296 ret = get_entries(&get, user);
1300 case IP6T_SO_GET_REVISION_MATCH:
1301 case IP6T_SO_GET_REVISION_TARGET: {
1302 struct ip6t_get_revision rev;
1305 if (*len != sizeof(rev)) {
1309 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1314 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1319 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1322 "ip6t_%s", rev.name);
1327 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1334 int ip6t_register_table(struct xt_table *table,
1335 const struct ip6t_replace *repl)
1338 struct xt_table_info *newinfo;
1339 struct xt_table_info bootstrap
1340 = { 0, 0, 0, { 0 }, { 0 }, { } };
1341 void *loc_cpu_entry;
1343 newinfo = xt_alloc_table_info(repl->size);
1347 /* choose the copy on our node/cpu */
1348 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1349 memcpy(loc_cpu_entry, repl->entries, repl->size);
1351 ret = translate_table(table->name, table->valid_hooks,
1352 newinfo, loc_cpu_entry, repl->size,
1357 xt_free_table_info(newinfo);
1361 ret = xt_register_table(table, &bootstrap, newinfo);
1363 xt_free_table_info(newinfo);
1370 void ip6t_unregister_table(struct xt_table *table)
1372 struct xt_table_info *private;
1373 void *loc_cpu_entry;
1375 private = xt_unregister_table(table);
1377 /* Decrease module usage counts and free resources */
1378 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1379 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1380 xt_free_table_info(private);
1383 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1385 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1386 u_int8_t type, u_int8_t code,
1389 return (type == test_type && code >= min_code && code <= max_code)
1394 icmp6_match(const struct sk_buff *skb,
1395 const struct net_device *in,
1396 const struct net_device *out,
1397 const struct xt_match *match,
1398 const void *matchinfo,
1400 unsigned int protoff,
1403 struct icmp6hdr _icmp, *ic;
1404 const struct ip6t_icmp *icmpinfo = matchinfo;
1406 /* Must not be a fragment. */
1410 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1412 /* We've been asked to examine this packet, and we
1413 can't. Hence, no choice but to drop. */
1414 duprintf("Dropping evil ICMP tinygram.\n");
1419 return icmp6_type_code_match(icmpinfo->type,
1422 ic->icmp6_type, ic->icmp6_code,
1423 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1426 /* Called when user tries to insert an entry of this type. */
1428 icmp6_checkentry(const char *tablename,
1430 const struct xt_match *match,
1432 unsigned int hook_mask)
1434 const struct ip6t_icmp *icmpinfo = matchinfo;
1436 /* Must specify no unknown invflags */
1437 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1440 /* The built-in targets: standard (NULL) and error. */
1441 static struct xt_target ip6t_standard_target __read_mostly = {
1442 .name = IP6T_STANDARD_TARGET,
1443 .targetsize = sizeof(int),
1447 static struct xt_target ip6t_error_target __read_mostly = {
1448 .name = IP6T_ERROR_TARGET,
1449 .target = ip6t_error,
1450 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1454 static struct nf_sockopt_ops ip6t_sockopts = {
1456 .set_optmin = IP6T_BASE_CTL,
1457 .set_optmax = IP6T_SO_SET_MAX+1,
1458 .set = do_ip6t_set_ctl,
1459 .get_optmin = IP6T_BASE_CTL,
1460 .get_optmax = IP6T_SO_GET_MAX+1,
1461 .get = do_ip6t_get_ctl,
1462 .owner = THIS_MODULE,
1465 static struct xt_match icmp6_matchstruct __read_mostly = {
1467 .match = &icmp6_match,
1468 .matchsize = sizeof(struct ip6t_icmp),
1469 .checkentry = icmp6_checkentry,
1470 .proto = IPPROTO_ICMPV6,
1474 static int __init ip6_tables_init(void)
1478 ret = xt_proto_init(AF_INET6);
1482 /* Noone else will be downing sem now, so we won't sleep */
1483 ret = xt_register_target(&ip6t_standard_target);
1486 ret = xt_register_target(&ip6t_error_target);
1489 ret = xt_register_match(&icmp6_matchstruct);
1493 /* Register setsockopt */
1494 ret = nf_register_sockopt(&ip6t_sockopts);
1498 printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1502 xt_unregister_match(&icmp6_matchstruct);
1504 xt_unregister_target(&ip6t_error_target);
1506 xt_unregister_target(&ip6t_standard_target);
1508 xt_proto_fini(AF_INET6);
1513 static void __exit ip6_tables_fini(void)
1515 nf_unregister_sockopt(&ip6t_sockopts);
1516 xt_unregister_match(&icmp6_matchstruct);
1517 xt_unregister_target(&ip6t_error_target);
1518 xt_unregister_target(&ip6t_standard_target);
1519 xt_proto_fini(AF_INET6);
1523 * find the offset to specified header or the protocol number of last header
1524 * if target < 0. "last header" is transport protocol header, ESP, or
1527 * If target header is found, its offset is set in *offset and return protocol
1528 * number. Otherwise, return -1.
1530 * If the first fragment doesn't contain the final protocol header or
1531 * NEXTHDR_NONE it is considered invalid.
1533 * Note that non-1st fragment is special case that "the protocol number
1534 * of last header" is "next header" field in Fragment header. In this case,
1535 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1539 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1540 int target, unsigned short *fragoff)
1542 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
1543 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
1544 unsigned int len = skb->len - start;
1549 while (nexthdr != target) {
1550 struct ipv6_opt_hdr _hdr, *hp;
1551 unsigned int hdrlen;
1553 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1559 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1562 if (nexthdr == NEXTHDR_FRAGMENT) {
1563 unsigned short _frag_off;
1565 fp = skb_header_pointer(skb,
1566 start+offsetof(struct frag_hdr,
1573 _frag_off = ntohs(*fp) & ~0x7;
1576 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1577 hp->nexthdr == NEXTHDR_NONE)) {
1579 *fragoff = _frag_off;
1585 } else if (nexthdr == NEXTHDR_AUTH)
1586 hdrlen = (hp->hdrlen + 2) << 2;
1588 hdrlen = ipv6_optlen(hp);
1590 nexthdr = hp->nexthdr;
1599 EXPORT_SYMBOL(ip6t_register_table);
1600 EXPORT_SYMBOL(ip6t_unregister_table);
1601 EXPORT_SYMBOL(ip6t_do_table);
1602 EXPORT_SYMBOL(ip6t_ext_hdr);
1603 EXPORT_SYMBOL(ipv6_find_hdr);
1605 module_init(ip6_tables_init);
1606 module_exit(ip6_tables_fini);