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_entry(struct ip6t_entry *e, const char *name)
612 struct ip6t_entry_target *t;
614 if (!ip6_checkentry(&e->ipv6)) {
615 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
619 if (e->target_offset + sizeof(struct ip6t_entry_target) >
623 t = ip6t_get_target(e);
624 if (e->target_offset + t->u.target_size > e->next_offset)
630 static inline int check_match(struct ip6t_entry_match *m, const char *name,
631 const struct ip6t_ip6 *ipv6,
632 unsigned int hookmask, unsigned int *i)
634 struct xt_match *match;
637 match = m->u.kernel.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);
641 if (!ret && m->u.kernel.match->checkentry
642 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
644 duprintf("ip_tables: check failed for `%s'.\n",
645 m->u.kernel.match->name);
654 find_check_match(struct ip6t_entry_match *m,
656 const struct ip6t_ip6 *ipv6,
657 unsigned int hookmask,
660 struct xt_match *match;
663 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
665 "ip6t_%s", m->u.user.name);
666 if (IS_ERR(match) || !match) {
667 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
668 return match ? PTR_ERR(match) : -ENOENT;
670 m->u.kernel.match = match;
672 ret = check_match(m, name, ipv6, hookmask, i);
678 module_put(m->u.kernel.match->me);
682 static inline int check_target(struct ip6t_entry *e, const char *name)
684 struct ip6t_entry_target *t;
685 struct xt_target *target;
688 t = ip6t_get_target(e);
689 target = t->u.kernel.target;
690 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
691 name, e->comefrom, e->ipv6.proto,
692 e->ipv6.invflags & IP6T_INV_PROTO);
693 if (!ret && t->u.kernel.target->checkentry
694 && !t->u.kernel.target->checkentry(name, e, target, t->data,
696 duprintf("ip_tables: check failed for `%s'.\n",
697 t->u.kernel.target->name);
704 find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
707 struct ip6t_entry_target *t;
708 struct xt_target *target;
712 ret = check_entry(e, name);
717 ret = IP6T_MATCH_ITERATE(e, find_check_match, name, &e->ipv6,
720 goto cleanup_matches;
722 t = ip6t_get_target(e);
723 target = try_then_request_module(xt_find_target(AF_INET6,
726 "ip6t_%s", t->u.user.name);
727 if (IS_ERR(target) || !target) {
728 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
729 ret = target ? PTR_ERR(target) : -ENOENT;
730 goto cleanup_matches;
732 t->u.kernel.target = target;
734 ret = check_target(e, name);
741 module_put(t->u.kernel.target->me);
743 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
748 check_entry_size_and_hooks(struct ip6t_entry *e,
749 struct xt_table_info *newinfo,
751 unsigned char *limit,
752 const unsigned int *hook_entries,
753 const unsigned int *underflows,
758 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
759 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
760 duprintf("Bad offset %p\n", e);
765 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
766 duprintf("checking: element %p size %u\n",
771 /* Check hooks & underflows */
772 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
773 if ((unsigned char *)e - base == hook_entries[h])
774 newinfo->hook_entry[h] = hook_entries[h];
775 if ((unsigned char *)e - base == underflows[h])
776 newinfo->underflow[h] = underflows[h];
779 /* FIXME: underflows must be unconditional, standard verdicts
780 < 0 (not IP6T_RETURN). --RR */
782 /* Clear counters and comefrom */
783 e->counters = ((struct xt_counters) { 0, 0 });
791 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
793 struct ip6t_entry_target *t;
795 if (i && (*i)-- == 0)
798 /* Cleanup all matches */
799 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
800 t = ip6t_get_target(e);
801 if (t->u.kernel.target->destroy)
802 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
803 module_put(t->u.kernel.target->me);
807 /* Checks and translates the user-supplied table segment (held in
810 translate_table(const char *name,
811 unsigned int valid_hooks,
812 struct xt_table_info *newinfo,
816 const unsigned int *hook_entries,
817 const unsigned int *underflows)
822 newinfo->size = size;
823 newinfo->number = number;
825 /* Init all hooks to impossible value. */
826 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
827 newinfo->hook_entry[i] = 0xFFFFFFFF;
828 newinfo->underflow[i] = 0xFFFFFFFF;
831 duprintf("translate_table: size %u\n", newinfo->size);
833 /* Walk through entries, checking offsets. */
834 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
835 check_entry_size_and_hooks,
839 hook_entries, underflows, &i);
844 duprintf("translate_table: %u not %u entries\n",
849 /* Check hooks all assigned */
850 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
851 /* Only hooks which are valid */
852 if (!(valid_hooks & (1 << i)))
854 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
855 duprintf("Invalid hook entry %u %u\n",
859 if (newinfo->underflow[i] == 0xFFFFFFFF) {
860 duprintf("Invalid underflow %u %u\n",
866 if (!mark_source_chains(newinfo, valid_hooks, entry0))
869 /* Finally, each sanity check must pass */
871 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
872 find_check_entry, name, size, &i);
875 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
880 /* And one copy for every other CPU */
881 for_each_possible_cpu(i) {
882 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
883 memcpy(newinfo->entries[i], entry0, newinfo->size);
891 add_entry_to_counter(const struct ip6t_entry *e,
892 struct xt_counters total[],
895 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
902 set_entry_to_counter(const struct ip6t_entry *e,
903 struct ip6t_counters total[],
906 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
913 get_counters(const struct xt_table_info *t,
914 struct xt_counters counters[])
920 /* Instead of clearing (by a previous call to memset())
921 * the counters and using adds, we set the counters
922 * with data used by 'current' CPU
923 * We dont care about preemption here.
925 curcpu = raw_smp_processor_id();
928 IP6T_ENTRY_ITERATE(t->entries[curcpu],
930 set_entry_to_counter,
934 for_each_possible_cpu(cpu) {
938 IP6T_ENTRY_ITERATE(t->entries[cpu],
940 add_entry_to_counter,
946 static inline struct xt_counters *alloc_counters(struct xt_table *table)
948 unsigned int countersize;
949 struct xt_counters *counters;
950 struct xt_table_info *private = table->private;
952 /* We need atomic snapshot of counters: rest doesn't change
953 (other than comefrom, which userspace doesn't care
955 countersize = sizeof(struct xt_counters) * private->number;
956 counters = vmalloc_node(countersize, numa_node_id());
958 if (counters == NULL)
959 return ERR_PTR(-ENOMEM);
961 /* First, sum counters... */
962 write_lock_bh(&table->lock);
963 get_counters(private, counters);
964 write_unlock_bh(&table->lock);
970 copy_entries_to_user(unsigned int total_size,
971 struct xt_table *table,
972 void __user *userptr)
974 unsigned int off, num;
975 struct ip6t_entry *e;
976 struct xt_counters *counters;
977 struct xt_table_info *private = table->private;
981 counters = alloc_counters(table);
982 if (IS_ERR(counters))
983 return PTR_ERR(counters);
985 /* choose the copy that is on ourc node/cpu */
986 loc_cpu_entry = private->entries[raw_smp_processor_id()];
987 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
992 /* FIXME: use iterator macros --RR */
993 /* ... then go back and fix counters and names */
994 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
996 struct ip6t_entry_match *m;
997 struct ip6t_entry_target *t;
999 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1000 if (copy_to_user(userptr + off
1001 + offsetof(struct ip6t_entry, counters),
1003 sizeof(counters[num])) != 0) {
1008 for (i = sizeof(struct ip6t_entry);
1009 i < e->target_offset;
1010 i += m->u.match_size) {
1013 if (copy_to_user(userptr + off + i
1014 + offsetof(struct ip6t_entry_match,
1016 m->u.kernel.match->name,
1017 strlen(m->u.kernel.match->name)+1)
1024 t = ip6t_get_target(e);
1025 if (copy_to_user(userptr + off + e->target_offset
1026 + offsetof(struct ip6t_entry_target,
1028 t->u.kernel.target->name,
1029 strlen(t->u.kernel.target->name)+1) != 0) {
1040 static int get_info(void __user *user, int *len)
1042 char name[IP6T_TABLE_MAXNAMELEN];
1046 if (*len != sizeof(struct ip6t_getinfo)) {
1047 duprintf("length %u != %u\n", *len,
1048 sizeof(struct ip6t_getinfo));
1052 if (copy_from_user(name, user, sizeof(name)) != 0)
1055 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1057 t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
1058 "ip6table_%s", name);
1059 if (t && !IS_ERR(t)) {
1060 struct ip6t_getinfo info;
1061 struct xt_table_info *private = t->private;
1063 info.valid_hooks = t->valid_hooks;
1064 memcpy(info.hook_entry, private->hook_entry,
1065 sizeof(info.hook_entry));
1066 memcpy(info.underflow, private->underflow,
1067 sizeof(info.underflow));
1068 info.num_entries = private->number;
1069 info.size = private->size;
1070 memcpy(info.name, name, sizeof(info.name));
1072 if (copy_to_user(user, &info, *len) != 0)
1080 ret = t ? PTR_ERR(t) : -ENOENT;
1085 get_entries(const struct ip6t_get_entries *entries,
1086 struct ip6t_get_entries __user *uptr)
1091 t = xt_find_table_lock(AF_INET6, entries->name);
1092 if (t && !IS_ERR(t)) {
1093 struct xt_table_info *private = t->private;
1094 duprintf("t->private->number = %u\n", private->number);
1095 if (entries->size == private->size)
1096 ret = copy_entries_to_user(private->size,
1097 t, uptr->entrytable);
1099 duprintf("get_entries: I've got %u not %u!\n",
1100 private->size, entries->size);
1106 ret = t ? PTR_ERR(t) : -ENOENT;
1112 do_replace(void __user *user, unsigned int len)
1115 struct ip6t_replace tmp;
1117 struct xt_table_info *newinfo, *oldinfo;
1118 struct xt_counters *counters;
1119 void *loc_cpu_entry, *loc_cpu_old_entry;
1121 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1124 /* overflow check */
1125 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1128 newinfo = xt_alloc_table_info(tmp.size);
1132 /* choose the copy that is on our node/cpu */
1133 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1134 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1140 counters = vmalloc_node(tmp.num_counters * sizeof(struct xt_counters),
1147 ret = translate_table(tmp.name, tmp.valid_hooks,
1148 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1149 tmp.hook_entry, tmp.underflow);
1151 goto free_newinfo_counters;
1153 duprintf("ip_tables: Translated table\n");
1155 t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
1156 "ip6table_%s", tmp.name);
1157 if (!t || IS_ERR(t)) {
1158 ret = t ? PTR_ERR(t) : -ENOENT;
1159 goto free_newinfo_counters_untrans;
1163 if (tmp.valid_hooks != t->valid_hooks) {
1164 duprintf("Valid hook crap: %08X vs %08X\n",
1165 tmp.valid_hooks, t->valid_hooks);
1170 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
1174 /* Update module usage count based on number of rules */
1175 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1176 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1177 if ((oldinfo->number > oldinfo->initial_entries) ||
1178 (newinfo->number <= oldinfo->initial_entries))
1180 if ((oldinfo->number > oldinfo->initial_entries) &&
1181 (newinfo->number <= oldinfo->initial_entries))
1184 /* Get the old counters. */
1185 get_counters(oldinfo, counters);
1186 /* Decrease module usage counts and free resource */
1187 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1188 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1189 xt_free_table_info(oldinfo);
1190 if (copy_to_user(tmp.counters, counters,
1191 sizeof(struct xt_counters) * tmp.num_counters) != 0)
1200 free_newinfo_counters_untrans:
1201 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1202 free_newinfo_counters:
1205 xt_free_table_info(newinfo);
1209 /* We're lazy, and add to the first CPU; overflow works its fey magic
1210 * and everything is OK. */
1212 add_counter_to_entry(struct ip6t_entry *e,
1213 const struct xt_counters addme[],
1217 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1219 (long unsigned int)e->counters.pcnt,
1220 (long unsigned int)e->counters.bcnt,
1221 (long unsigned int)addme[*i].pcnt,
1222 (long unsigned int)addme[*i].bcnt);
1225 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1232 do_add_counters(void __user *user, unsigned int len)
1235 struct xt_counters_info tmp, *paddc;
1236 struct xt_table_info *private;
1239 void *loc_cpu_entry;
1241 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1244 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
1247 paddc = vmalloc_node(len, numa_node_id());
1251 if (copy_from_user(paddc, user, len) != 0) {
1256 t = xt_find_table_lock(AF_INET6, tmp.name);
1257 if (!t || IS_ERR(t)) {
1258 ret = t ? PTR_ERR(t) : -ENOENT;
1262 write_lock_bh(&t->lock);
1263 private = t->private;
1264 if (private->number != tmp.num_counters) {
1266 goto unlock_up_free;
1270 /* Choose the copy that is on our node */
1271 loc_cpu_entry = private->entries[smp_processor_id()];
1272 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1274 add_counter_to_entry,
1278 write_unlock_bh(&t->lock);
1288 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1292 if (!capable(CAP_NET_ADMIN))
1296 case IP6T_SO_SET_REPLACE:
1297 ret = do_replace(user, len);
1300 case IP6T_SO_SET_ADD_COUNTERS:
1301 ret = do_add_counters(user, len);
1305 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1313 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1317 if (!capable(CAP_NET_ADMIN))
1321 case IP6T_SO_GET_INFO:
1322 ret = get_info(user, len);
1325 case IP6T_SO_GET_ENTRIES: {
1326 struct ip6t_get_entries get;
1328 if (*len < sizeof(get)) {
1329 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1331 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1333 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1334 duprintf("get_entries: %u != %u\n", *len,
1335 sizeof(struct ip6t_get_entries) + get.size);
1338 ret = get_entries(&get, user);
1342 case IP6T_SO_GET_REVISION_MATCH:
1343 case IP6T_SO_GET_REVISION_TARGET: {
1344 struct ip6t_get_revision rev;
1347 if (*len != sizeof(rev)) {
1351 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1356 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1361 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1364 "ip6t_%s", rev.name);
1369 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1376 int ip6t_register_table(struct xt_table *table,
1377 const struct ip6t_replace *repl)
1380 struct xt_table_info *newinfo;
1381 struct xt_table_info bootstrap
1382 = { 0, 0, 0, { 0 }, { 0 }, { } };
1383 void *loc_cpu_entry;
1385 newinfo = xt_alloc_table_info(repl->size);
1389 /* choose the copy on our node/cpu */
1390 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1391 memcpy(loc_cpu_entry, repl->entries, repl->size);
1393 ret = translate_table(table->name, table->valid_hooks,
1394 newinfo, loc_cpu_entry, repl->size,
1399 xt_free_table_info(newinfo);
1403 ret = xt_register_table(table, &bootstrap, newinfo);
1405 xt_free_table_info(newinfo);
1412 void ip6t_unregister_table(struct xt_table *table)
1414 struct xt_table_info *private;
1415 void *loc_cpu_entry;
1417 private = xt_unregister_table(table);
1419 /* Decrease module usage counts and free resources */
1420 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1421 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
1422 xt_free_table_info(private);
1425 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1427 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1428 u_int8_t type, u_int8_t code,
1431 return (type == test_type && code >= min_code && code <= max_code)
1436 icmp6_match(const struct sk_buff *skb,
1437 const struct net_device *in,
1438 const struct net_device *out,
1439 const struct xt_match *match,
1440 const void *matchinfo,
1442 unsigned int protoff,
1445 struct icmp6hdr _icmp, *ic;
1446 const struct ip6t_icmp *icmpinfo = matchinfo;
1448 /* Must not be a fragment. */
1452 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1454 /* We've been asked to examine this packet, and we
1455 can't. Hence, no choice but to drop. */
1456 duprintf("Dropping evil ICMP tinygram.\n");
1461 return icmp6_type_code_match(icmpinfo->type,
1464 ic->icmp6_type, ic->icmp6_code,
1465 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1468 /* Called when user tries to insert an entry of this type. */
1470 icmp6_checkentry(const char *tablename,
1472 const struct xt_match *match,
1474 unsigned int hook_mask)
1476 const struct ip6t_icmp *icmpinfo = matchinfo;
1478 /* Must specify no unknown invflags */
1479 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1482 /* The built-in targets: standard (NULL) and error. */
1483 static struct xt_target ip6t_standard_target __read_mostly = {
1484 .name = IP6T_STANDARD_TARGET,
1485 .targetsize = sizeof(int),
1489 static struct xt_target ip6t_error_target __read_mostly = {
1490 .name = IP6T_ERROR_TARGET,
1491 .target = ip6t_error,
1492 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1496 static struct nf_sockopt_ops ip6t_sockopts = {
1498 .set_optmin = IP6T_BASE_CTL,
1499 .set_optmax = IP6T_SO_SET_MAX+1,
1500 .set = do_ip6t_set_ctl,
1501 .get_optmin = IP6T_BASE_CTL,
1502 .get_optmax = IP6T_SO_GET_MAX+1,
1503 .get = do_ip6t_get_ctl,
1504 .owner = THIS_MODULE,
1507 static struct xt_match icmp6_matchstruct __read_mostly = {
1509 .match = &icmp6_match,
1510 .matchsize = sizeof(struct ip6t_icmp),
1511 .checkentry = icmp6_checkentry,
1512 .proto = IPPROTO_ICMPV6,
1516 static int __init ip6_tables_init(void)
1520 ret = xt_proto_init(AF_INET6);
1524 /* Noone else will be downing sem now, so we won't sleep */
1525 ret = xt_register_target(&ip6t_standard_target);
1528 ret = xt_register_target(&ip6t_error_target);
1531 ret = xt_register_match(&icmp6_matchstruct);
1535 /* Register setsockopt */
1536 ret = nf_register_sockopt(&ip6t_sockopts);
1540 printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1544 xt_unregister_match(&icmp6_matchstruct);
1546 xt_unregister_target(&ip6t_error_target);
1548 xt_unregister_target(&ip6t_standard_target);
1550 xt_proto_fini(AF_INET6);
1555 static void __exit ip6_tables_fini(void)
1557 nf_unregister_sockopt(&ip6t_sockopts);
1558 xt_unregister_match(&icmp6_matchstruct);
1559 xt_unregister_target(&ip6t_error_target);
1560 xt_unregister_target(&ip6t_standard_target);
1561 xt_proto_fini(AF_INET6);
1565 * find the offset to specified header or the protocol number of last header
1566 * if target < 0. "last header" is transport protocol header, ESP, or
1569 * If target header is found, its offset is set in *offset and return protocol
1570 * number. Otherwise, return -1.
1572 * If the first fragment doesn't contain the final protocol header or
1573 * NEXTHDR_NONE it is considered invalid.
1575 * Note that non-1st fragment is special case that "the protocol number
1576 * of last header" is "next header" field in Fragment header. In this case,
1577 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1581 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
1582 int target, unsigned short *fragoff)
1584 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
1585 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
1586 unsigned int len = skb->len - start;
1591 while (nexthdr != target) {
1592 struct ipv6_opt_hdr _hdr, *hp;
1593 unsigned int hdrlen;
1595 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
1601 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1604 if (nexthdr == NEXTHDR_FRAGMENT) {
1605 unsigned short _frag_off;
1607 fp = skb_header_pointer(skb,
1608 start+offsetof(struct frag_hdr,
1615 _frag_off = ntohs(*fp) & ~0x7;
1618 ((!ipv6_ext_hdr(hp->nexthdr)) ||
1619 hp->nexthdr == NEXTHDR_NONE)) {
1621 *fragoff = _frag_off;
1627 } else if (nexthdr == NEXTHDR_AUTH)
1628 hdrlen = (hp->hdrlen + 2) << 2;
1630 hdrlen = ipv6_optlen(hp);
1632 nexthdr = hp->nexthdr;
1641 EXPORT_SYMBOL(ip6t_register_table);
1642 EXPORT_SYMBOL(ip6t_unregister_table);
1643 EXPORT_SYMBOL(ip6t_do_table);
1644 EXPORT_SYMBOL(ip6t_ext_hdr);
1645 EXPORT_SYMBOL(ipv6_find_hdr);
1647 module_init(ip6_tables_init);
1648 module_exit(ip6_tables_fini);