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 DEBUG_IP_FIREWALL*/
35 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
36 /*#define DEBUG_IP_FIREWALL_USER*/
38 #ifdef DEBUG_IP_FIREWALL
39 #define dprintf(format, args...) printk(format , ## args)
41 #define dprintf(format, args...)
44 #ifdef DEBUG_IP_FIREWALL_USER
45 #define duprintf(format, args...) printk(format , ## args)
47 #define duprintf(format, args...)
50 #ifdef CONFIG_NETFILTER_DEBUG
51 #define IP_NF_ASSERT(x) \
54 printk("IP_NF_ASSERT: %s:%s:%u\n", \
55 __FUNCTION__, __FILE__, __LINE__); \
58 #define IP_NF_ASSERT(x)
62 /* All the better to debug you with... */
68 We keep a set of rules for each CPU, so we can avoid write-locking
69 them in the softirq when updating the counters and therefore
70 only need to read-lock in the softirq; doing a write_lock_bh() in user
71 context stops packets coming through and allows user context to read
72 the counters or update the rules.
74 Hence the start of any table is given by get_table() below. */
76 /* Check for an extension */
78 ip6t_ext_hdr(u8 nexthdr)
80 return ( (nexthdr == IPPROTO_HOPOPTS) ||
81 (nexthdr == IPPROTO_ROUTING) ||
82 (nexthdr == IPPROTO_FRAGMENT) ||
83 (nexthdr == IPPROTO_ESP) ||
84 (nexthdr == IPPROTO_AH) ||
85 (nexthdr == IPPROTO_NONE) ||
86 (nexthdr == IPPROTO_DSTOPTS) );
89 /* Returns whether matches rule or not. */
91 ip6_packet_match(const struct sk_buff *skb,
94 const struct ip6t_ip6 *ip6info,
95 unsigned int *protoff,
96 int *fragoff, bool *hotdrop)
100 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
102 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
104 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
105 &ip6info->src), IP6T_INV_SRCIP)
106 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
107 &ip6info->dst), IP6T_INV_DSTIP)) {
108 dprintf("Source or dest mismatch.\n");
110 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
111 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
112 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
113 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
114 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
115 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
119 /* Look for ifname matches; this should unroll nicely. */
120 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
121 ret |= (((const unsigned long *)indev)[i]
122 ^ ((const unsigned long *)ip6info->iniface)[i])
123 & ((const unsigned long *)ip6info->iniface_mask)[i];
126 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
127 dprintf("VIA in mismatch (%s vs %s).%s\n",
128 indev, ip6info->iniface,
129 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
133 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
134 ret |= (((const unsigned long *)outdev)[i]
135 ^ ((const unsigned long *)ip6info->outiface)[i])
136 & ((const unsigned long *)ip6info->outiface_mask)[i];
139 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
140 dprintf("VIA out mismatch (%s vs %s).%s\n",
141 outdev, ip6info->outiface,
142 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
146 /* ... might want to do something with class and flowlabel here ... */
148 /* look for the desired protocol header */
149 if((ip6info->flags & IP6T_F_PROTO)) {
151 unsigned short _frag_off;
153 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
159 *fragoff = _frag_off;
161 dprintf("Packet protocol %hi ?= %s%hi.\n",
163 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
166 if (ip6info->proto == protohdr) {
167 if(ip6info->invflags & IP6T_INV_PROTO) {
173 /* We need match for the '-p all', too! */
174 if ((ip6info->proto != 0) &&
175 !(ip6info->invflags & IP6T_INV_PROTO))
181 /* should be ip6 safe */
183 ip6_checkentry(const struct ip6t_ip6 *ipv6)
185 if (ipv6->flags & ~IP6T_F_MASK) {
186 duprintf("Unknown flag bits set: %08X\n",
187 ipv6->flags & ~IP6T_F_MASK);
190 if (ipv6->invflags & ~IP6T_INV_MASK) {
191 duprintf("Unknown invflag bits set: %08X\n",
192 ipv6->invflags & ~IP6T_INV_MASK);
199 ip6t_error(struct sk_buff *skb,
200 const struct net_device *in,
201 const struct net_device *out,
202 unsigned int hooknum,
203 const struct xt_target *target,
204 const void *targinfo)
207 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
213 bool do_match(struct ip6t_entry_match *m,
214 const struct sk_buff *skb,
215 const struct net_device *in,
216 const struct net_device *out,
218 unsigned int protoff,
221 /* Stop iteration if it doesn't match */
222 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
223 offset, protoff, hotdrop))
229 static inline struct ip6t_entry *
230 get_entry(void *base, unsigned int offset)
232 return (struct ip6t_entry *)(base + offset);
235 /* All zeroes == unconditional rule. */
237 unconditional(const struct ip6t_ip6 *ipv6)
241 for (i = 0; i < sizeof(*ipv6); i++)
242 if (((char *)ipv6)[i])
245 return (i == sizeof(*ipv6));
248 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
249 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
250 /* This cries for unification! */
251 static const char *hooknames[] = {
252 [NF_INET_PRE_ROUTING] = "PREROUTING",
253 [NF_INET_LOCAL_IN] = "INPUT",
254 [NF_INET_FORWARD] = "FORWARD",
255 [NF_INET_LOCAL_OUT] = "OUTPUT",
256 [NF_INET_POST_ROUTING] = "POSTROUTING",
259 enum nf_ip_trace_comments {
260 NF_IP6_TRACE_COMMENT_RULE,
261 NF_IP6_TRACE_COMMENT_RETURN,
262 NF_IP6_TRACE_COMMENT_POLICY,
265 static const char *comments[] = {
266 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
267 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
268 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
271 static struct nf_loginfo trace_loginfo = {
272 .type = NF_LOG_TYPE_LOG,
276 .logflags = NF_LOG_MASK,
282 get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
283 char *hookname, char **chainname,
284 char **comment, unsigned int *rulenum)
286 struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
288 if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
289 /* Head of user chain: ERROR target with chainname */
290 *chainname = t->target.data;
295 if (s->target_offset == sizeof(struct ip6t_entry)
296 && strcmp(t->target.u.kernel.target->name,
297 IP6T_STANDARD_TARGET) == 0
299 && unconditional(&s->ipv6)) {
300 /* Tail of chains: STANDARD target (return/policy) */
301 *comment = *chainname == hookname
302 ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY]
303 : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN];
312 static void trace_packet(struct sk_buff *skb,
314 const struct net_device *in,
315 const struct net_device *out,
317 struct xt_table_info *private,
318 struct ip6t_entry *e)
321 struct ip6t_entry *root;
322 char *hookname, *chainname, *comment;
323 unsigned int rulenum = 0;
325 table_base = (void *)private->entries[smp_processor_id()];
326 root = get_entry(table_base, private->hook_entry[hook]);
328 hookname = chainname = (char *)hooknames[hook];
329 comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE];
331 IP6T_ENTRY_ITERATE(root,
332 private->size - private->hook_entry[hook],
333 get_chainname_rulenum,
334 e, hookname, &chainname, &comment, &rulenum);
336 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
337 "TRACE: %s:%s:%s:%u ",
338 tablename, chainname, comment, rulenum);
342 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
344 ip6t_do_table(struct sk_buff *skb,
346 const struct net_device *in,
347 const struct net_device *out,
348 struct xt_table *table)
350 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
352 unsigned int protoff = 0;
353 bool hotdrop = false;
354 /* Initializing verdict to NF_DROP keeps gcc happy. */
355 unsigned int verdict = NF_DROP;
356 const char *indev, *outdev;
358 struct ip6t_entry *e, *back;
359 struct xt_table_info *private;
362 indev = in ? in->name : nulldevname;
363 outdev = out ? out->name : nulldevname;
364 /* We handle fragments by dealing with the first fragment as
365 * if it was a normal packet. All other fragments are treated
366 * normally, except that they will NEVER match rules that ask
367 * things we don't know, ie. tcp syn flag or ports). If the
368 * rule is also a fragment-specific rule, non-fragments won't
371 read_lock_bh(&table->lock);
372 private = table->private;
373 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
374 table_base = (void *)private->entries[smp_processor_id()];
375 e = get_entry(table_base, private->hook_entry[hook]);
377 /* For return from builtin chain */
378 back = get_entry(table_base, private->underflow[hook]);
383 if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
384 &protoff, &offset, &hotdrop)) {
385 struct ip6t_entry_target *t;
387 if (IP6T_MATCH_ITERATE(e, do_match,
389 offset, protoff, &hotdrop) != 0)
392 ADD_COUNTER(e->counters,
393 ntohs(ipv6_hdr(skb)->payload_len) +
394 sizeof(struct ipv6hdr), 1);
396 t = ip6t_get_target(e);
397 IP_NF_ASSERT(t->u.kernel.target);
399 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
400 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
401 /* The packet is traced: log it */
402 if (unlikely(skb->nf_trace))
403 trace_packet(skb, hook, in, out,
404 table->name, private, e);
406 /* Standard target? */
407 if (!t->u.kernel.target->target) {
410 v = ((struct ip6t_standard_target *)t)->verdict;
412 /* Pop from stack? */
413 if (v != IP6T_RETURN) {
414 verdict = (unsigned)(-v) - 1;
418 back = get_entry(table_base,
422 if (table_base + v != (void *)e + e->next_offset
423 && !(e->ipv6.flags & IP6T_F_GOTO)) {
424 /* Save old back ptr in next entry */
425 struct ip6t_entry *next
426 = (void *)e + e->next_offset;
428 = (void *)back - table_base;
429 /* set back pointer to next entry */
433 e = get_entry(table_base, v);
435 /* Targets which reenter must return
437 #ifdef CONFIG_NETFILTER_DEBUG
438 ((struct ip6t_entry *)table_base)->comefrom
441 verdict = t->u.kernel.target->target(skb,
447 #ifdef CONFIG_NETFILTER_DEBUG
448 if (((struct ip6t_entry *)table_base)->comefrom
450 && verdict == IP6T_CONTINUE) {
451 printk("Target %s reentered!\n",
452 t->u.kernel.target->name);
455 ((struct ip6t_entry *)table_base)->comefrom
458 if (verdict == IP6T_CONTINUE)
459 e = (void *)e + e->next_offset;
467 e = (void *)e + e->next_offset;
471 #ifdef CONFIG_NETFILTER_DEBUG
472 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
474 read_unlock_bh(&table->lock);
476 #ifdef DEBUG_ALLOW_ALL
485 /* Figures out from what hook each rule can be called: returns 0 if
486 there are loops. Puts hook bitmask in comefrom. */
488 mark_source_chains(struct xt_table_info *newinfo,
489 unsigned int valid_hooks, void *entry0)
493 /* No recursion; use packet counter to save back ptrs (reset
494 to 0 as we leave), and comefrom to save source hook bitmask */
495 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
496 unsigned int pos = newinfo->hook_entry[hook];
498 = (struct ip6t_entry *)(entry0 + pos);
499 int visited = e->comefrom & (1 << hook);
501 if (!(valid_hooks & (1 << hook)))
504 /* Set initial back pointer. */
505 e->counters.pcnt = pos;
508 struct ip6t_standard_target *t
509 = (void *)ip6t_get_target(e);
511 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
512 printk("iptables: loop hook %u pos %u %08X.\n",
513 hook, pos, e->comefrom);
517 |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
519 /* Unconditional return/END. */
520 if ((e->target_offset == sizeof(struct ip6t_entry)
521 && (strcmp(t->target.u.user.name,
522 IP6T_STANDARD_TARGET) == 0)
524 && unconditional(&e->ipv6)) || visited) {
525 unsigned int oldpos, size;
527 if (t->verdict < -NF_MAX_VERDICT - 1) {
528 duprintf("mark_source_chains: bad "
529 "negative verdict (%i)\n",
534 /* Return: backtrack through the last
537 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
538 #ifdef DEBUG_IP_FIREWALL_USER
540 & (1 << NF_INET_NUMHOOKS)) {
541 duprintf("Back unset "
548 pos = e->counters.pcnt;
549 e->counters.pcnt = 0;
551 /* We're at the start. */
555 e = (struct ip6t_entry *)
557 } while (oldpos == pos + e->next_offset);
560 size = e->next_offset;
561 e = (struct ip6t_entry *)
562 (entry0 + pos + size);
563 e->counters.pcnt = pos;
566 int newpos = t->verdict;
568 if (strcmp(t->target.u.user.name,
569 IP6T_STANDARD_TARGET) == 0
571 if (newpos > newinfo->size -
572 sizeof(struct ip6t_entry)) {
573 duprintf("mark_source_chains: "
574 "bad verdict (%i)\n",
578 /* This a jump; chase it. */
579 duprintf("Jump rule %u -> %u\n",
582 /* ... this is a fallthru */
583 newpos = pos + e->next_offset;
585 e = (struct ip6t_entry *)
587 e->counters.pcnt = pos;
592 duprintf("Finished chain %u\n", hook);
598 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
600 if (i && (*i)-- == 0)
603 if (m->u.kernel.match->destroy)
604 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
605 module_put(m->u.kernel.match->me);
610 check_match(struct ip6t_entry_match *m,
612 const struct ip6t_ip6 *ipv6,
613 unsigned int hookmask,
616 struct xt_match *match;
619 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
621 "ip6t_%s", m->u.user.name);
622 if (IS_ERR(match) || !match) {
623 duprintf("check_match: `%s' not found\n", m->u.user.name);
624 return match ? PTR_ERR(match) : -ENOENT;
626 m->u.kernel.match = match;
628 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
629 name, hookmask, ipv6->proto,
630 ipv6->invflags & IP6T_INV_PROTO);
634 if (m->u.kernel.match->checkentry
635 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
637 duprintf("ip_tables: check failed for `%s'.\n",
638 m->u.kernel.match->name);
646 module_put(m->u.kernel.match->me);
651 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
654 struct ip6t_entry_target *t;
655 struct xt_target *target;
659 if (!ip6_checkentry(&e->ipv6)) {
660 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
664 if (e->target_offset + sizeof(struct ip6t_entry_target) >
669 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
671 goto cleanup_matches;
673 t = ip6t_get_target(e);
675 if (e->target_offset + t->u.target_size > e->next_offset)
676 goto cleanup_matches;
677 target = try_then_request_module(xt_find_target(AF_INET6,
680 "ip6t_%s", t->u.user.name);
681 if (IS_ERR(target) || !target) {
682 duprintf("check_entry: `%s' not found\n", t->u.user.name);
683 ret = target ? PTR_ERR(target) : -ENOENT;
684 goto cleanup_matches;
686 t->u.kernel.target = target;
688 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
689 name, e->comefrom, e->ipv6.proto,
690 e->ipv6.invflags & IP6T_INV_PROTO);
694 if (t->u.kernel.target->checkentry
695 && !t->u.kernel.target->checkentry(name, e, target, t->data,
697 duprintf("ip_tables: check failed for `%s'.\n",
698 t->u.kernel.target->name);
706 module_put(t->u.kernel.target->me);
708 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
713 check_entry_size_and_hooks(struct ip6t_entry *e,
714 struct xt_table_info *newinfo,
716 unsigned char *limit,
717 const unsigned int *hook_entries,
718 const unsigned int *underflows,
723 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
724 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
725 duprintf("Bad offset %p\n", e);
730 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
731 duprintf("checking: element %p size %u\n",
736 /* Check hooks & underflows */
737 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
738 if ((unsigned char *)e - base == hook_entries[h])
739 newinfo->hook_entry[h] = hook_entries[h];
740 if ((unsigned char *)e - base == underflows[h])
741 newinfo->underflow[h] = underflows[h];
744 /* FIXME: underflows must be unconditional, standard verdicts
745 < 0 (not IP6T_RETURN). --RR */
747 /* Clear counters and comefrom */
748 e->counters = ((struct xt_counters) { 0, 0 });
756 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
758 struct ip6t_entry_target *t;
760 if (i && (*i)-- == 0)
763 /* Cleanup all matches */
764 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
765 t = ip6t_get_target(e);
766 if (t->u.kernel.target->destroy)
767 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
768 module_put(t->u.kernel.target->me);
772 /* Checks and translates the user-supplied table segment (held in
775 translate_table(const char *name,
776 unsigned int valid_hooks,
777 struct xt_table_info *newinfo,
781 const unsigned int *hook_entries,
782 const unsigned int *underflows)
787 newinfo->size = size;
788 newinfo->number = number;
790 /* Init all hooks to impossible value. */
791 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
792 newinfo->hook_entry[i] = 0xFFFFFFFF;
793 newinfo->underflow[i] = 0xFFFFFFFF;
796 duprintf("translate_table: size %u\n", newinfo->size);
798 /* Walk through entries, checking offsets. */
799 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
800 check_entry_size_and_hooks,
804 hook_entries, underflows, &i);
809 duprintf("translate_table: %u not %u entries\n",
814 /* Check hooks all assigned */
815 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
816 /* Only hooks which are valid */
817 if (!(valid_hooks & (1 << i)))
819 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
820 duprintf("Invalid hook entry %u %u\n",
824 if (newinfo->underflow[i] == 0xFFFFFFFF) {
825 duprintf("Invalid underflow %u %u\n",
831 if (!mark_source_chains(newinfo, valid_hooks, entry0))
834 /* Finally, each sanity check must pass */
836 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
837 check_entry, name, size, &i);
840 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
845 /* And one copy for every other CPU */
846 for_each_possible_cpu(i) {
847 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
848 memcpy(newinfo->entries[i], entry0, newinfo->size);
856 add_entry_to_counter(const struct ip6t_entry *e,
857 struct xt_counters total[],
860 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
867 set_entry_to_counter(const struct ip6t_entry *e,
868 struct ip6t_counters total[],
871 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
878 get_counters(const struct xt_table_info *t,
879 struct xt_counters counters[])
885 /* Instead of clearing (by a previous call to memset())
886 * the counters and using adds, we set the counters
887 * with data used by 'current' CPU
888 * We dont care about preemption here.
890 curcpu = raw_smp_processor_id();
893 IP6T_ENTRY_ITERATE(t->entries[curcpu],
895 set_entry_to_counter,
899 for_each_possible_cpu(cpu) {
903 IP6T_ENTRY_ITERATE(t->entries[cpu],
905 add_entry_to_counter,
912 copy_entries_to_user(unsigned int total_size,
913 struct xt_table *table,
914 void __user *userptr)
916 unsigned int off, num, countersize;
917 struct ip6t_entry *e;
918 struct xt_counters *counters;
919 struct xt_table_info *private = table->private;
923 /* We need atomic snapshot of counters: rest doesn't change
924 (other than comefrom, which userspace doesn't care
926 countersize = sizeof(struct xt_counters) * private->number;
927 counters = vmalloc(countersize);
929 if (counters == NULL)
932 /* First, sum counters... */
933 write_lock_bh(&table->lock);
934 get_counters(private, counters);
935 write_unlock_bh(&table->lock);
937 /* choose the copy that is on ourc node/cpu */
938 loc_cpu_entry = private->entries[raw_smp_processor_id()];
939 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
944 /* FIXME: use iterator macros --RR */
945 /* ... then go back and fix counters and names */
946 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
948 struct ip6t_entry_match *m;
949 struct ip6t_entry_target *t;
951 e = (struct ip6t_entry *)(loc_cpu_entry + off);
952 if (copy_to_user(userptr + off
953 + offsetof(struct ip6t_entry, counters),
955 sizeof(counters[num])) != 0) {
960 for (i = sizeof(struct ip6t_entry);
961 i < e->target_offset;
962 i += m->u.match_size) {
965 if (copy_to_user(userptr + off + i
966 + offsetof(struct ip6t_entry_match,
968 m->u.kernel.match->name,
969 strlen(m->u.kernel.match->name)+1)
976 t = ip6t_get_target(e);
977 if (copy_to_user(userptr + off + e->target_offset
978 + offsetof(struct ip6t_entry_target,
980 t->u.kernel.target->name,
981 strlen(t->u.kernel.target->name)+1) != 0) {
993 get_entries(const struct ip6t_get_entries *entries,
994 struct ip6t_get_entries __user *uptr)
999 t = xt_find_table_lock(AF_INET6, entries->name);
1000 if (t && !IS_ERR(t)) {
1001 struct xt_table_info *private = t->private;
1002 duprintf("t->private->number = %u\n", private->number);
1003 if (entries->size == private->size)
1004 ret = copy_entries_to_user(private->size,
1005 t, uptr->entrytable);
1007 duprintf("get_entries: I've got %u not %u!\n",
1008 private->size, entries->size);
1014 ret = t ? PTR_ERR(t) : -ENOENT;
1020 do_replace(void __user *user, unsigned int len)
1023 struct ip6t_replace tmp;
1025 struct xt_table_info *newinfo, *oldinfo;
1026 struct xt_counters *counters;
1027 void *loc_cpu_entry, *loc_cpu_old_entry;
1029 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1032 /* overflow check */
1033 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1036 newinfo = xt_alloc_table_info(tmp.size);
1040 /* choose the copy that is on our node/cpu */
1041 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1042 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1048 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
1054 ret = translate_table(tmp.name, tmp.valid_hooks,
1055 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1056 tmp.hook_entry, tmp.underflow);
1058 goto free_newinfo_counters;
1060 duprintf("ip_tables: Translated table\n");
1062 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1063 "ip6table_%s", tmp.name);
1064 if (!t || IS_ERR(t)) {
1065 ret = t ? PTR_ERR(t) : -ENOENT;
1066 goto free_newinfo_counters_untrans;
1070 if (tmp.valid_hooks != t->valid_hooks) {
1071 duprintf("Valid hook crap: %08X vs %08X\n",
1072 tmp.valid_hooks, t->valid_hooks);
1077 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1081 /* Update module usage count based on number of rules */
1082 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1083 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1084 if ((oldinfo->number > oldinfo->initial_entries) ||
1085 (newinfo->number <= oldinfo->initial_entries))
1087 if ((oldinfo->number > oldinfo->initial_entries) &&
1088 (newinfo->number <= oldinfo->initial_entries))
1091 /* Get the old counters. */
1092 get_counters(oldinfo, counters);
1093 /* Decrease module usage counts and free resource */
1094 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1095 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1096 xt_free_table_info(oldinfo);
1097 if (copy_to_user(tmp.counters, counters,
1098 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1107 free_newinfo_counters_untrans:
1108 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1109 free_newinfo_counters:
1112 xt_free_table_info(newinfo);
1116 /* We're lazy, and add to the first CPU; overflow works its fey magic
1117 * and everything is OK. */
1119 add_counter_to_entry(struct ip6t_entry *e,
1120 const struct xt_counters addme[],
1124 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1126 (long unsigned int)e->counters.pcnt,
1127 (long unsigned int)e->counters.bcnt,
1128 (long unsigned int)addme[*i].pcnt,
1129 (long unsigned int)addme[*i].bcnt);
1132 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1139 do_add_counters(void __user *user, unsigned int len)
1142 struct xt_counters_info tmp, *paddc;
1143 struct xt_table_info *private;
1146 void *loc_cpu_entry;
1148 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1151 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1154 paddc = vmalloc(len);
1158 if (copy_from_user(paddc, user, len) != 0) {
1163 t = xt_find_table_lock(AF_INET6, tmp.name);
1164 if (!t || IS_ERR(t)) {
1165 ret = t ? PTR_ERR(t) : -ENOENT;
1169 write_lock_bh(&t->lock);
1170 private = t->private;
1171 if (private->number != tmp.num_counters) {
1173 goto unlock_up_free;
1177 /* Choose the copy that is on our node */
1178 loc_cpu_entry = private->entries[smp_processor_id()];
1179 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1181 add_counter_to_entry,
1185 write_unlock_bh(&t->lock);
1195 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1199 if (!capable(CAP_NET_ADMIN))
1203 case IP6T_SO_SET_REPLACE:
1204 ret = do_replace(user, len);
1207 case IP6T_SO_SET_ADD_COUNTERS:
1208 ret = do_add_counters(user, len);
1212 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1220 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1224 if (!capable(CAP_NET_ADMIN))
1228 case IP6T_SO_GET_INFO: {
1229 char name[IP6T_TABLE_MAXNAMELEN];
1232 if (*len != sizeof(struct ip6t_getinfo)) {
1233 duprintf("length %u != %u\n", *len,
1234 sizeof(struct ip6t_getinfo));
1239 if (copy_from_user(name, user, sizeof(name)) != 0) {
1243 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1245 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1246 "ip6table_%s", name);
1247 if (t && !IS_ERR(t)) {
1248 struct ip6t_getinfo info;
1249 struct xt_table_info *private = t->private;
1251 info.valid_hooks = t->valid_hooks;
1252 memcpy(info.hook_entry, private->hook_entry,
1253 sizeof(info.hook_entry));
1254 memcpy(info.underflow, private->underflow,
1255 sizeof(info.underflow));
1256 info.num_entries = private->number;
1257 info.size = private->size;
1258 memcpy(info.name, name, sizeof(info.name));
1260 if (copy_to_user(user, &info, *len) != 0)
1267 ret = t ? PTR_ERR(t) : -ENOENT;
1271 case IP6T_SO_GET_ENTRIES: {
1272 struct ip6t_get_entries get;
1274 if (*len < sizeof(get)) {
1275 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1277 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1279 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1280 duprintf("get_entries: %u != %u\n", *len,
1281 sizeof(struct ip6t_get_entries) + get.size);
1284 ret = get_entries(&get, user);
1288 case IP6T_SO_GET_REVISION_MATCH:
1289 case IP6T_SO_GET_REVISION_TARGET: {
1290 struct ip6t_get_revision rev;
1293 if (*len != sizeof(rev)) {
1297 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1302 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1307 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1310 "ip6t_%s", rev.name);
1315 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1322 int ip6t_register_table(struct xt_table *table,
1323 const struct ip6t_replace *repl)
1326 struct xt_table_info *newinfo;
1327 struct xt_table_info bootstrap
1328 = { 0, 0, 0, { 0 }, { 0 }, { } };
1329 void *loc_cpu_entry;
1331 newinfo = xt_alloc_table_info(repl->size);
1335 /* choose the copy on our node/cpu */
1336 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1337 memcpy(loc_cpu_entry, repl->entries, repl->size);
1339 ret = translate_table(table->name, table->valid_hooks,
1340 newinfo, loc_cpu_entry, repl->size,
1345 xt_free_table_info(newinfo);
1349 ret = xt_register_table(table, &bootstrap, newinfo);
1351 xt_free_table_info(newinfo);
1358 void ip6t_unregister_table(struct xt_table *table)
1360 struct xt_table_info *private;
1361 void *loc_cpu_entry;
1363 private = xt_unregister_table(table);
1365 /* Decrease module usage counts and free resources */
1366 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1367 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1368 xt_free_table_info(private);
1371 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1373 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1374 u_int8_t type, u_int8_t code,
1377 return (type == test_type && code >= min_code && code <= max_code)
1382 icmp6_match(const struct sk_buff *skb,
1383 const struct net_device *in,
1384 const struct net_device *out,
1385 const struct xt_match *match,
1386 const void *matchinfo,
1388 unsigned int protoff,
1391 struct icmp6hdr _icmp, *ic;
1392 const struct ip6t_icmp *icmpinfo = matchinfo;
1394 /* Must not be a fragment. */
1398 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1400 /* We've been asked to examine this packet, and we
1401 can't. Hence, no choice but to drop. */
1402 duprintf("Dropping evil ICMP tinygram.\n");
1407 return icmp6_type_code_match(icmpinfo->type,
1410 ic->icmp6_type, ic->icmp6_code,
1411 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1414 /* Called when user tries to insert an entry of this type. */
1416 icmp6_checkentry(const char *tablename,
1418 const struct xt_match *match,
1420 unsigned int hook_mask)
1422 const struct ip6t_icmp *icmpinfo = matchinfo;
1424 /* Must specify no unknown invflags */
1425 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1428 /* The built-in targets: standard (NULL) and error. */
1429 static struct xt_target ip6t_standard_target __read_mostly = {
1430 .name = IP6T_STANDARD_TARGET,
1431 .targetsize = sizeof(int),
1435 static struct xt_target ip6t_error_target __read_mostly = {
1436 .name = IP6T_ERROR_TARGET,
1437 .target = ip6t_error,
1438 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1442 static struct nf_sockopt_ops ip6t_sockopts = {
1444 .set_optmin = IP6T_BASE_CTL,
1445 .set_optmax = IP6T_SO_SET_MAX+1,
1446 .set = do_ip6t_set_ctl,
1447 .get_optmin = IP6T_BASE_CTL,
1448 .get_optmax = IP6T_SO_GET_MAX+1,
1449 .get = do_ip6t_get_ctl,
1450 .owner = THIS_MODULE,
1453 static struct xt_match icmp6_matchstruct __read_mostly = {
1455 .match = &icmp6_match,
1456 .matchsize = sizeof(struct ip6t_icmp),
1457 .checkentry = icmp6_checkentry,
1458 .proto = IPPROTO_ICMPV6,
1462 static int __init ip6_tables_init(void)
1466 ret = xt_proto_init(AF_INET6);
1470 /* Noone else will be downing sem now, so we won't sleep */
1471 ret = xt_register_target(&ip6t_standard_target);
1474 ret = xt_register_target(&ip6t_error_target);
1477 ret = xt_register_match(&icmp6_matchstruct);
1481 /* Register setsockopt */
1482 ret = nf_register_sockopt(&ip6t_sockopts);
1486 printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1490 xt_unregister_match(&icmp6_matchstruct);
1492 xt_unregister_target(&ip6t_error_target);
1494 xt_unregister_target(&ip6t_standard_target);
1496 xt_proto_fini(AF_INET6);
1501 static void __exit ip6_tables_fini(void)
1503 nf_unregister_sockopt(&ip6t_sockopts);
1504 xt_unregister_match(&icmp6_matchstruct);
1505 xt_unregister_target(&ip6t_error_target);
1506 xt_unregister_target(&ip6t_standard_target);
1507 xt_proto_fini(AF_INET6);
1511 * find the offset to specified header or the protocol number of last header
1512 * if target < 0. "last header" is transport protocol header, ESP, or
1515 * If target header is found, its offset is set in *offset and return protocol
1516 * number. Otherwise, return -1.
1518 * If the first fragment doesn't contain the final protocol header or
1519 * NEXTHDR_NONE it is considered invalid.
1521 * Note that non-1st fragment is special case that "the protocol number
1522 * of last header" is "next header" field in Fragment header. In this case,
1523 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1527 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1528 int target, unsigned short *fragoff)
1530 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
1531 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
1532 unsigned int len = skb->len - start;
1537 while (nexthdr != target) {
1538 struct ipv6_opt_hdr _hdr, *hp;
1539 unsigned int hdrlen;
1541 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1547 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1550 if (nexthdr == NEXTHDR_FRAGMENT) {
1551 unsigned short _frag_off;
1553 fp = skb_header_pointer(skb,
1554 start+offsetof(struct frag_hdr,
1561 _frag_off = ntohs(*fp) & ~0x7;
1564 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1565 hp->nexthdr == NEXTHDR_NONE)) {
1567 *fragoff = _frag_off;
1573 } else if (nexthdr == NEXTHDR_AUTH)
1574 hdrlen = (hp->hdrlen + 2) << 2;
1576 hdrlen = ipv6_optlen(hp);
1578 nexthdr = hp->nexthdr;
1587 EXPORT_SYMBOL(ip6t_register_table);
1588 EXPORT_SYMBOL(ip6t_unregister_table);
1589 EXPORT_SYMBOL(ip6t_do_table);
1590 EXPORT_SYMBOL(ip6t_ext_hdr);
1591 EXPORT_SYMBOL(ipv6_find_hdr);
1593 module_init(ip6_tables_init);
1594 module_exit(ip6_tables_fini);