2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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 <net/compat.h>
23 #include <asm/uaccess.h>
24 #include <linux/mutex.h>
25 #include <linux/proc_fs.h>
26 #include <linux/err.h>
27 #include <linux/cpumask.h>
29 #include <linux/netfilter_ipv6/ip6_tables.h>
30 #include <linux/netfilter/x_tables.h>
31 #include <net/netfilter/nf_log.h>
32 #include "../../netfilter/xt_repldata.h"
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
38 /*#define DEBUG_IP_FIREWALL*/
39 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
40 /*#define DEBUG_IP_FIREWALL_USER*/
42 #ifdef DEBUG_IP_FIREWALL
43 #define dprintf(format, args...) pr_info(format , ## args)
45 #define dprintf(format, args...)
48 #ifdef DEBUG_IP_FIREWALL_USER
49 #define duprintf(format, args...) pr_info(format , ## args)
51 #define duprintf(format, args...)
54 #ifdef CONFIG_NETFILTER_DEBUG
55 #define IP_NF_ASSERT(x) WARN_ON(!(x))
57 #define IP_NF_ASSERT(x)
61 /* All the better to debug you with... */
66 void *ip6t_alloc_initial_table(const struct xt_table *info)
68 return xt_alloc_initial_table(ip6t, IP6T);
70 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
73 We keep a set of rules for each CPU, so we can avoid write-locking
74 them in the softirq when updating the counters and therefore
75 only need to read-lock in the softirq; doing a write_lock_bh() in user
76 context stops packets coming through and allows user context to read
77 the counters or update the rules.
79 Hence the start of any table is given by get_table() below. */
81 /* Check for an extension */
83 ip6t_ext_hdr(u8 nexthdr)
85 return (nexthdr == IPPROTO_HOPOPTS) ||
86 (nexthdr == IPPROTO_ROUTING) ||
87 (nexthdr == IPPROTO_FRAGMENT) ||
88 (nexthdr == IPPROTO_ESP) ||
89 (nexthdr == IPPROTO_AH) ||
90 (nexthdr == IPPROTO_NONE) ||
91 (nexthdr == IPPROTO_DSTOPTS);
94 /* Returns whether matches rule or not. */
95 /* Performance critical - called for every packet */
97 ip6_packet_match(const struct sk_buff *skb,
100 const struct ip6t_ip6 *ip6info,
101 unsigned int *protoff,
102 int *fragoff, bool *hotdrop)
105 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
107 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
109 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
110 &ip6info->src), IP6T_INV_SRCIP) ||
111 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
112 &ip6info->dst), IP6T_INV_DSTIP)) {
113 dprintf("Source or dest mismatch.\n");
115 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
116 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
117 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
118 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
119 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
120 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
124 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
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 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
135 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
136 dprintf("VIA out mismatch (%s vs %s).%s\n",
137 outdev, ip6info->outiface,
138 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
142 /* ... might want to do something with class and flowlabel here ... */
144 /* look for the desired protocol header */
145 if((ip6info->flags & IP6T_F_PROTO)) {
147 unsigned short _frag_off;
149 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
155 *fragoff = _frag_off;
157 dprintf("Packet protocol %hi ?= %s%hi.\n",
159 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
162 if (ip6info->proto == protohdr) {
163 if(ip6info->invflags & IP6T_INV_PROTO) {
169 /* We need match for the '-p all', too! */
170 if ((ip6info->proto != 0) &&
171 !(ip6info->invflags & IP6T_INV_PROTO))
177 /* should be ip6 safe */
179 ip6_checkentry(const struct ip6t_ip6 *ipv6)
181 if (ipv6->flags & ~IP6T_F_MASK) {
182 duprintf("Unknown flag bits set: %08X\n",
183 ipv6->flags & ~IP6T_F_MASK);
186 if (ipv6->invflags & ~IP6T_INV_MASK) {
187 duprintf("Unknown invflag bits set: %08X\n",
188 ipv6->invflags & ~IP6T_INV_MASK);
195 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
198 pr_info("error: `%s'\n", (const char *)par->targinfo);
203 static inline struct ip6t_entry *
204 get_entry(const void *base, unsigned int offset)
206 return (struct ip6t_entry *)(base + offset);
209 /* All zeroes == unconditional rule. */
210 /* Mildly perf critical (only if packet tracing is on) */
211 static inline bool unconditional(const struct ip6t_ip6 *ipv6)
213 static const struct ip6t_ip6 uncond;
215 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
218 static inline const struct xt_entry_target *
219 ip6t_get_target_c(const struct ip6t_entry *e)
221 return ip6t_get_target((struct ip6t_entry *)e);
224 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
225 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
226 /* This cries for unification! */
227 static const char *const hooknames[] = {
228 [NF_INET_PRE_ROUTING] = "PREROUTING",
229 [NF_INET_LOCAL_IN] = "INPUT",
230 [NF_INET_FORWARD] = "FORWARD",
231 [NF_INET_LOCAL_OUT] = "OUTPUT",
232 [NF_INET_POST_ROUTING] = "POSTROUTING",
235 enum nf_ip_trace_comments {
236 NF_IP6_TRACE_COMMENT_RULE,
237 NF_IP6_TRACE_COMMENT_RETURN,
238 NF_IP6_TRACE_COMMENT_POLICY,
241 static const char *const comments[] = {
242 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
243 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
244 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
247 static struct nf_loginfo trace_loginfo = {
248 .type = NF_LOG_TYPE_LOG,
252 .logflags = NF_LOG_MASK,
257 /* Mildly perf critical (only if packet tracing is on) */
259 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
260 const char *hookname, const char **chainname,
261 const char **comment, unsigned int *rulenum)
263 const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
265 if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
266 /* Head of user chain: ERROR target with chainname */
267 *chainname = t->target.data;
272 if (s->target_offset == sizeof(struct ip6t_entry) &&
273 strcmp(t->target.u.kernel.target->name,
274 XT_STANDARD_TARGET) == 0 &&
276 unconditional(&s->ipv6)) {
277 /* Tail of chains: STANDARD target (return/policy) */
278 *comment = *chainname == hookname
279 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
280 : comments[NF_IP6_TRACE_COMMENT_RETURN];
289 static void trace_packet(const struct sk_buff *skb,
291 const struct net_device *in,
292 const struct net_device *out,
293 const char *tablename,
294 const struct xt_table_info *private,
295 const struct ip6t_entry *e)
297 const void *table_base;
298 const struct ip6t_entry *root;
299 const char *hookname, *chainname, *comment;
300 const struct ip6t_entry *iter;
301 unsigned int rulenum = 0;
303 table_base = private->entries[smp_processor_id()];
304 root = get_entry(table_base, private->hook_entry[hook]);
306 hookname = chainname = hooknames[hook];
307 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
309 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
310 if (get_chainname_rulenum(iter, e, hookname,
311 &chainname, &comment, &rulenum) != 0)
314 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
315 "TRACE: %s:%s:%s:%u ",
316 tablename, chainname, comment, rulenum);
320 static inline __pure struct ip6t_entry *
321 ip6t_next_entry(const struct ip6t_entry *entry)
323 return (void *)entry + entry->next_offset;
326 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
328 ip6t_do_table(struct sk_buff *skb,
330 const struct net_device *in,
331 const struct net_device *out,
332 struct xt_table *table)
334 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
335 /* Initializing verdict to NF_DROP keeps gcc happy. */
336 unsigned int verdict = NF_DROP;
337 const char *indev, *outdev;
338 const void *table_base;
339 struct ip6t_entry *e, **jumpstack;
340 unsigned int *stackptr, origptr, cpu;
341 const struct xt_table_info *private;
342 struct xt_action_param acpar;
345 indev = in ? in->name : nulldevname;
346 outdev = out ? out->name : nulldevname;
347 /* We handle fragments by dealing with the first fragment as
348 * if it was a normal packet. All other fragments are treated
349 * normally, except that they will NEVER match rules that ask
350 * things we don't know, ie. tcp syn flag or ports). If the
351 * rule is also a fragment-specific rule, non-fragments won't
353 acpar.hotdrop = false;
356 acpar.family = NFPROTO_IPV6;
357 acpar.hooknum = hook;
359 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
362 private = table->private;
363 cpu = smp_processor_id();
364 table_base = private->entries[cpu];
365 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
366 stackptr = per_cpu_ptr(private->stackptr, cpu);
369 e = get_entry(table_base, private->hook_entry[hook]);
372 const struct xt_entry_target *t;
373 const struct xt_entry_match *ematch;
376 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
377 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
379 e = ip6t_next_entry(e);
383 xt_ematch_foreach(ematch, e) {
384 acpar.match = ematch->u.kernel.match;
385 acpar.matchinfo = ematch->data;
386 if (!acpar.match->match(skb, &acpar))
390 ADD_COUNTER(e->counters, skb->len, 1);
392 t = ip6t_get_target_c(e);
393 IP_NF_ASSERT(t->u.kernel.target);
395 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
396 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
397 /* The packet is traced: log it */
398 if (unlikely(skb->nf_trace))
399 trace_packet(skb, hook, in, out,
400 table->name, private, e);
402 /* Standard target? */
403 if (!t->u.kernel.target->target) {
406 v = ((struct xt_standard_target *)t)->verdict;
408 /* Pop from stack? */
409 if (v != XT_RETURN) {
410 verdict = (unsigned)(-v) - 1;
414 e = get_entry(table_base,
415 private->underflow[hook]);
417 e = ip6t_next_entry(jumpstack[--*stackptr]);
420 if (table_base + v != ip6t_next_entry(e) &&
421 !(e->ipv6.flags & IP6T_F_GOTO)) {
422 if (*stackptr >= private->stacksize) {
426 jumpstack[(*stackptr)++] = e;
429 e = get_entry(table_base, v);
433 acpar.target = t->u.kernel.target;
434 acpar.targinfo = t->data;
436 verdict = t->u.kernel.target->target(skb, &acpar);
437 if (verdict == XT_CONTINUE)
438 e = ip6t_next_entry(e);
442 } while (!acpar.hotdrop);
444 xt_info_rdunlock_bh();
447 #ifdef DEBUG_ALLOW_ALL
456 /* Figures out from what hook each rule can be called: returns 0 if
457 there are loops. Puts hook bitmask in comefrom. */
459 mark_source_chains(const struct xt_table_info *newinfo,
460 unsigned int valid_hooks, void *entry0)
464 /* No recursion; use packet counter to save back ptrs (reset
465 to 0 as we leave), and comefrom to save source hook bitmask */
466 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
467 unsigned int pos = newinfo->hook_entry[hook];
468 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
470 if (!(valid_hooks & (1 << hook)))
473 /* Set initial back pointer. */
474 e->counters.pcnt = pos;
477 const struct xt_standard_target *t
478 = (void *)ip6t_get_target_c(e);
479 int visited = e->comefrom & (1 << hook);
481 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
482 pr_err("iptables: loop hook %u pos %u %08X.\n",
483 hook, pos, e->comefrom);
486 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
488 /* Unconditional return/END. */
489 if ((e->target_offset == sizeof(struct ip6t_entry) &&
490 (strcmp(t->target.u.user.name,
491 XT_STANDARD_TARGET) == 0) &&
493 unconditional(&e->ipv6)) || visited) {
494 unsigned int oldpos, size;
496 if ((strcmp(t->target.u.user.name,
497 XT_STANDARD_TARGET) == 0) &&
498 t->verdict < -NF_MAX_VERDICT - 1) {
499 duprintf("mark_source_chains: bad "
500 "negative verdict (%i)\n",
505 /* Return: backtrack through the last
508 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
509 #ifdef DEBUG_IP_FIREWALL_USER
511 & (1 << NF_INET_NUMHOOKS)) {
512 duprintf("Back unset "
519 pos = e->counters.pcnt;
520 e->counters.pcnt = 0;
522 /* We're at the start. */
526 e = (struct ip6t_entry *)
528 } while (oldpos == pos + e->next_offset);
531 size = e->next_offset;
532 e = (struct ip6t_entry *)
533 (entry0 + pos + size);
534 e->counters.pcnt = pos;
537 int newpos = t->verdict;
539 if (strcmp(t->target.u.user.name,
540 XT_STANDARD_TARGET) == 0 &&
542 if (newpos > newinfo->size -
543 sizeof(struct ip6t_entry)) {
544 duprintf("mark_source_chains: "
545 "bad verdict (%i)\n",
549 /* This a jump; chase it. */
550 duprintf("Jump rule %u -> %u\n",
553 /* ... this is a fallthru */
554 newpos = pos + e->next_offset;
556 e = (struct ip6t_entry *)
558 e->counters.pcnt = pos;
563 duprintf("Finished chain %u\n", hook);
568 static void cleanup_match(struct xt_entry_match *m, struct net *net)
570 struct xt_mtdtor_param par;
573 par.match = m->u.kernel.match;
574 par.matchinfo = m->data;
575 par.family = NFPROTO_IPV6;
576 if (par.match->destroy != NULL)
577 par.match->destroy(&par);
578 module_put(par.match->me);
582 check_entry(const struct ip6t_entry *e, const char *name)
584 const struct xt_entry_target *t;
586 if (!ip6_checkentry(&e->ipv6)) {
587 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
591 if (e->target_offset + sizeof(struct xt_entry_target) >
595 t = ip6t_get_target_c(e);
596 if (e->target_offset + t->u.target_size > e->next_offset)
602 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
604 const struct ip6t_ip6 *ipv6 = par->entryinfo;
607 par->match = m->u.kernel.match;
608 par->matchinfo = m->data;
610 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
611 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
613 duprintf("ip_tables: check failed for `%s'.\n",
621 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
623 struct xt_match *match;
626 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
629 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
630 return PTR_ERR(match);
632 m->u.kernel.match = match;
634 ret = check_match(m, par);
640 module_put(m->u.kernel.match->me);
644 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
646 struct xt_entry_target *t = ip6t_get_target(e);
647 struct xt_tgchk_param par = {
651 .target = t->u.kernel.target,
653 .hook_mask = e->comefrom,
654 .family = NFPROTO_IPV6,
658 t = ip6t_get_target(e);
659 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
660 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
662 duprintf("ip_tables: check failed for `%s'.\n",
663 t->u.kernel.target->name);
670 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
673 struct xt_entry_target *t;
674 struct xt_target *target;
677 struct xt_mtchk_param mtpar;
678 struct xt_entry_match *ematch;
680 ret = check_entry(e, name);
687 mtpar.entryinfo = &e->ipv6;
688 mtpar.hook_mask = e->comefrom;
689 mtpar.family = NFPROTO_IPV6;
690 xt_ematch_foreach(ematch, e) {
691 ret = find_check_match(ematch, &mtpar);
693 goto cleanup_matches;
697 t = ip6t_get_target(e);
698 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
700 if (IS_ERR(target)) {
701 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
702 ret = PTR_ERR(target);
703 goto cleanup_matches;
705 t->u.kernel.target = target;
707 ret = check_target(e, net, name);
712 module_put(t->u.kernel.target->me);
714 xt_ematch_foreach(ematch, e) {
717 cleanup_match(ematch, net);
722 static bool check_underflow(const struct ip6t_entry *e)
724 const struct xt_entry_target *t;
725 unsigned int verdict;
727 if (!unconditional(&e->ipv6))
729 t = ip6t_get_target_c(e);
730 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
732 verdict = ((struct xt_standard_target *)t)->verdict;
733 verdict = -verdict - 1;
734 return verdict == NF_DROP || verdict == NF_ACCEPT;
738 check_entry_size_and_hooks(struct ip6t_entry *e,
739 struct xt_table_info *newinfo,
740 const unsigned char *base,
741 const unsigned char *limit,
742 const unsigned int *hook_entries,
743 const unsigned int *underflows,
744 unsigned int valid_hooks)
748 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
749 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
750 duprintf("Bad offset %p\n", e);
755 < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
756 duprintf("checking: element %p size %u\n",
761 /* Check hooks & underflows */
762 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
763 if (!(valid_hooks & (1 << h)))
765 if ((unsigned char *)e - base == hook_entries[h])
766 newinfo->hook_entry[h] = hook_entries[h];
767 if ((unsigned char *)e - base == underflows[h]) {
768 if (!check_underflow(e)) {
769 pr_err("Underflows must be unconditional and "
770 "use the STANDARD target with "
774 newinfo->underflow[h] = underflows[h];
778 /* Clear counters and comefrom */
779 e->counters = ((struct xt_counters) { 0, 0 });
784 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
786 struct xt_tgdtor_param par;
787 struct xt_entry_target *t;
788 struct xt_entry_match *ematch;
790 /* Cleanup all matches */
791 xt_ematch_foreach(ematch, e)
792 cleanup_match(ematch, net);
793 t = ip6t_get_target(e);
796 par.target = t->u.kernel.target;
797 par.targinfo = t->data;
798 par.family = NFPROTO_IPV6;
799 if (par.target->destroy != NULL)
800 par.target->destroy(&par);
801 module_put(par.target->me);
804 /* Checks and translates the user-supplied table segment (held in
807 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
808 const struct ip6t_replace *repl)
810 struct ip6t_entry *iter;
814 newinfo->size = repl->size;
815 newinfo->number = repl->num_entries;
817 /* Init all hooks to impossible value. */
818 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
819 newinfo->hook_entry[i] = 0xFFFFFFFF;
820 newinfo->underflow[i] = 0xFFFFFFFF;
823 duprintf("translate_table: size %u\n", newinfo->size);
825 /* Walk through entries, checking offsets. */
826 xt_entry_foreach(iter, entry0, newinfo->size) {
827 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
835 if (strcmp(ip6t_get_target(iter)->u.user.name,
836 XT_ERROR_TARGET) == 0)
837 ++newinfo->stacksize;
840 if (i != repl->num_entries) {
841 duprintf("translate_table: %u not %u entries\n",
842 i, repl->num_entries);
846 /* Check hooks all assigned */
847 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
848 /* Only hooks which are valid */
849 if (!(repl->valid_hooks & (1 << i)))
851 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
852 duprintf("Invalid hook entry %u %u\n",
853 i, repl->hook_entry[i]);
856 if (newinfo->underflow[i] == 0xFFFFFFFF) {
857 duprintf("Invalid underflow %u %u\n",
858 i, repl->underflow[i]);
863 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
866 /* Finally, each sanity check must pass */
868 xt_entry_foreach(iter, entry0, newinfo->size) {
869 ret = find_check_entry(iter, net, repl->name, repl->size);
876 xt_entry_foreach(iter, entry0, newinfo->size) {
879 cleanup_entry(iter, net);
884 /* And one copy for every other CPU */
885 for_each_possible_cpu(i) {
886 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
887 memcpy(newinfo->entries[i], entry0, newinfo->size);
894 get_counters(const struct xt_table_info *t,
895 struct xt_counters counters[])
897 struct ip6t_entry *iter;
900 unsigned int curcpu = get_cpu();
902 /* Instead of clearing (by a previous call to memset())
903 * the counters and using adds, we set the counters
904 * with data used by 'current' CPU
906 * Bottom half has to be disabled to prevent deadlock
907 * if new softirq were to run and call ipt_do_table
911 xt_entry_foreach(iter, t->entries[curcpu], t->size) {
912 SET_COUNTER(counters[i], iter->counters.bcnt,
913 iter->counters.pcnt);
917 /* Processing counters from other cpus, we can let bottom half enabled,
918 * (preemption is disabled)
921 for_each_possible_cpu(cpu) {
927 xt_entry_foreach(iter, t->entries[cpu], t->size) {
928 ADD_COUNTER(counters[i], iter->counters.bcnt,
929 iter->counters.pcnt);
932 xt_info_wrunlock(cpu);
938 static struct xt_counters *alloc_counters(const struct xt_table *table)
940 unsigned int countersize;
941 struct xt_counters *counters;
942 const struct xt_table_info *private = table->private;
944 /* We need atomic snapshot of counters: rest doesn't change
945 (other than comefrom, which userspace doesn't care
947 countersize = sizeof(struct xt_counters) * private->number;
948 counters = vmalloc(countersize);
950 if (counters == NULL)
951 return ERR_PTR(-ENOMEM);
953 get_counters(private, counters);
959 copy_entries_to_user(unsigned int total_size,
960 const struct xt_table *table,
961 void __user *userptr)
963 unsigned int off, num;
964 const struct ip6t_entry *e;
965 struct xt_counters *counters;
966 const struct xt_table_info *private = table->private;
968 const void *loc_cpu_entry;
970 counters = alloc_counters(table);
971 if (IS_ERR(counters))
972 return PTR_ERR(counters);
974 /* choose the copy that is on our node/cpu, ...
975 * This choice is lazy (because current thread is
976 * allowed to migrate to another cpu)
978 loc_cpu_entry = private->entries[raw_smp_processor_id()];
979 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
984 /* FIXME: use iterator macros --RR */
985 /* ... then go back and fix counters and names */
986 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
988 const struct xt_entry_match *m;
989 const struct xt_entry_target *t;
991 e = (struct ip6t_entry *)(loc_cpu_entry + off);
992 if (copy_to_user(userptr + off
993 + offsetof(struct ip6t_entry, counters),
995 sizeof(counters[num])) != 0) {
1000 for (i = sizeof(struct ip6t_entry);
1001 i < e->target_offset;
1002 i += m->u.match_size) {
1005 if (copy_to_user(userptr + off + i
1006 + offsetof(struct xt_entry_match,
1008 m->u.kernel.match->name,
1009 strlen(m->u.kernel.match->name)+1)
1016 t = ip6t_get_target_c(e);
1017 if (copy_to_user(userptr + off + e->target_offset
1018 + offsetof(struct xt_entry_target,
1020 t->u.kernel.target->name,
1021 strlen(t->u.kernel.target->name)+1) != 0) {
1032 #ifdef CONFIG_COMPAT
1033 static void compat_standard_from_user(void *dst, const void *src)
1035 int v = *(compat_int_t *)src;
1038 v += xt_compat_calc_jump(AF_INET6, v);
1039 memcpy(dst, &v, sizeof(v));
1042 static int compat_standard_to_user(void __user *dst, const void *src)
1044 compat_int_t cv = *(int *)src;
1047 cv -= xt_compat_calc_jump(AF_INET6, cv);
1048 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1051 static int compat_calc_entry(const struct ip6t_entry *e,
1052 const struct xt_table_info *info,
1053 const void *base, struct xt_table_info *newinfo)
1055 const struct xt_entry_match *ematch;
1056 const struct xt_entry_target *t;
1057 unsigned int entry_offset;
1060 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1061 entry_offset = (void *)e - base;
1062 xt_ematch_foreach(ematch, e)
1063 off += xt_compat_match_offset(ematch->u.kernel.match);
1064 t = ip6t_get_target_c(e);
1065 off += xt_compat_target_offset(t->u.kernel.target);
1066 newinfo->size -= off;
1067 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1071 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1072 if (info->hook_entry[i] &&
1073 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1074 newinfo->hook_entry[i] -= off;
1075 if (info->underflow[i] &&
1076 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1077 newinfo->underflow[i] -= off;
1082 static int compat_table_info(const struct xt_table_info *info,
1083 struct xt_table_info *newinfo)
1085 struct ip6t_entry *iter;
1086 void *loc_cpu_entry;
1089 if (!newinfo || !info)
1092 /* we dont care about newinfo->entries[] */
1093 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1094 newinfo->initial_entries = 0;
1095 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1096 xt_compat_init_offsets(AF_INET6, info->number);
1097 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1098 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1106 static int get_info(struct net *net, void __user *user,
1107 const int *len, int compat)
1109 char name[XT_TABLE_MAXNAMELEN];
1113 if (*len != sizeof(struct ip6t_getinfo)) {
1114 duprintf("length %u != %zu\n", *len,
1115 sizeof(struct ip6t_getinfo));
1119 if (copy_from_user(name, user, sizeof(name)) != 0)
1122 name[XT_TABLE_MAXNAMELEN-1] = '\0';
1123 #ifdef CONFIG_COMPAT
1125 xt_compat_lock(AF_INET6);
1127 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1128 "ip6table_%s", name);
1129 if (t && !IS_ERR(t)) {
1130 struct ip6t_getinfo info;
1131 const struct xt_table_info *private = t->private;
1132 #ifdef CONFIG_COMPAT
1133 struct xt_table_info tmp;
1136 ret = compat_table_info(private, &tmp);
1137 xt_compat_flush_offsets(AF_INET6);
1141 memset(&info, 0, sizeof(info));
1142 info.valid_hooks = t->valid_hooks;
1143 memcpy(info.hook_entry, private->hook_entry,
1144 sizeof(info.hook_entry));
1145 memcpy(info.underflow, private->underflow,
1146 sizeof(info.underflow));
1147 info.num_entries = private->number;
1148 info.size = private->size;
1149 strcpy(info.name, name);
1151 if (copy_to_user(user, &info, *len) != 0)
1159 ret = t ? PTR_ERR(t) : -ENOENT;
1160 #ifdef CONFIG_COMPAT
1162 xt_compat_unlock(AF_INET6);
1168 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1172 struct ip6t_get_entries get;
1175 if (*len < sizeof(get)) {
1176 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1179 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1181 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1182 duprintf("get_entries: %u != %zu\n",
1183 *len, sizeof(get) + get.size);
1187 t = xt_find_table_lock(net, AF_INET6, get.name);
1188 if (t && !IS_ERR(t)) {
1189 struct xt_table_info *private = t->private;
1190 duprintf("t->private->number = %u\n", private->number);
1191 if (get.size == private->size)
1192 ret = copy_entries_to_user(private->size,
1193 t, uptr->entrytable);
1195 duprintf("get_entries: I've got %u not %u!\n",
1196 private->size, get.size);
1202 ret = t ? PTR_ERR(t) : -ENOENT;
1208 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1209 struct xt_table_info *newinfo, unsigned int num_counters,
1210 void __user *counters_ptr)
1214 struct xt_table_info *oldinfo;
1215 struct xt_counters *counters;
1216 const void *loc_cpu_old_entry;
1217 struct ip6t_entry *iter;
1220 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1226 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1227 "ip6table_%s", name);
1228 if (!t || IS_ERR(t)) {
1229 ret = t ? PTR_ERR(t) : -ENOENT;
1230 goto free_newinfo_counters_untrans;
1234 if (valid_hooks != t->valid_hooks) {
1235 duprintf("Valid hook crap: %08X vs %08X\n",
1236 valid_hooks, t->valid_hooks);
1241 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1245 /* Update module usage count based on number of rules */
1246 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1247 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1248 if ((oldinfo->number > oldinfo->initial_entries) ||
1249 (newinfo->number <= oldinfo->initial_entries))
1251 if ((oldinfo->number > oldinfo->initial_entries) &&
1252 (newinfo->number <= oldinfo->initial_entries))
1255 /* Get the old counters, and synchronize with replace */
1256 get_counters(oldinfo, counters);
1258 /* Decrease module usage counts and free resource */
1259 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1260 xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
1261 cleanup_entry(iter, net);
1263 xt_free_table_info(oldinfo);
1264 if (copy_to_user(counters_ptr, counters,
1265 sizeof(struct xt_counters) * num_counters) != 0)
1274 free_newinfo_counters_untrans:
1281 do_replace(struct net *net, const void __user *user, unsigned int len)
1284 struct ip6t_replace tmp;
1285 struct xt_table_info *newinfo;
1286 void *loc_cpu_entry;
1287 struct ip6t_entry *iter;
1289 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1292 /* overflow check */
1293 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1296 newinfo = xt_alloc_table_info(tmp.size);
1300 /* choose the copy that is on our node/cpu */
1301 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1302 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1308 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1312 duprintf("ip_tables: Translated table\n");
1314 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1315 tmp.num_counters, tmp.counters);
1317 goto free_newinfo_untrans;
1320 free_newinfo_untrans:
1321 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1322 cleanup_entry(iter, net);
1324 xt_free_table_info(newinfo);
1329 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1332 unsigned int i, curcpu;
1333 struct xt_counters_info tmp;
1334 struct xt_counters *paddc;
1335 unsigned int num_counters;
1340 const struct xt_table_info *private;
1342 const void *loc_cpu_entry;
1343 struct ip6t_entry *iter;
1344 #ifdef CONFIG_COMPAT
1345 struct compat_xt_counters_info compat_tmp;
1349 size = sizeof(struct compat_xt_counters_info);
1354 size = sizeof(struct xt_counters_info);
1357 if (copy_from_user(ptmp, user, size) != 0)
1360 #ifdef CONFIG_COMPAT
1362 num_counters = compat_tmp.num_counters;
1363 name = compat_tmp.name;
1367 num_counters = tmp.num_counters;
1371 if (len != size + num_counters * sizeof(struct xt_counters))
1374 paddc = vmalloc(len - size);
1378 if (copy_from_user(paddc, user + size, len - size) != 0) {
1383 t = xt_find_table_lock(net, AF_INET6, name);
1384 if (!t || IS_ERR(t)) {
1385 ret = t ? PTR_ERR(t) : -ENOENT;
1391 private = t->private;
1392 if (private->number != num_counters) {
1394 goto unlock_up_free;
1398 /* Choose the copy that is on our node */
1399 curcpu = smp_processor_id();
1400 xt_info_wrlock(curcpu);
1401 loc_cpu_entry = private->entries[curcpu];
1402 xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1403 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1406 xt_info_wrunlock(curcpu);
1418 #ifdef CONFIG_COMPAT
1419 struct compat_ip6t_replace {
1420 char name[XT_TABLE_MAXNAMELEN];
1424 u32 hook_entry[NF_INET_NUMHOOKS];
1425 u32 underflow[NF_INET_NUMHOOKS];
1427 compat_uptr_t counters; /* struct xt_counters * */
1428 struct compat_ip6t_entry entries[0];
1432 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1433 unsigned int *size, struct xt_counters *counters,
1436 struct xt_entry_target *t;
1437 struct compat_ip6t_entry __user *ce;
1438 u_int16_t target_offset, next_offset;
1439 compat_uint_t origsize;
1440 const struct xt_entry_match *ematch;
1444 ce = (struct compat_ip6t_entry __user *)*dstptr;
1445 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1446 copy_to_user(&ce->counters, &counters[i],
1447 sizeof(counters[i])) != 0)
1450 *dstptr += sizeof(struct compat_ip6t_entry);
1451 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1453 xt_ematch_foreach(ematch, e) {
1454 ret = xt_compat_match_to_user(ematch, dstptr, size);
1458 target_offset = e->target_offset - (origsize - *size);
1459 t = ip6t_get_target(e);
1460 ret = xt_compat_target_to_user(t, dstptr, size);
1463 next_offset = e->next_offset - (origsize - *size);
1464 if (put_user(target_offset, &ce->target_offset) != 0 ||
1465 put_user(next_offset, &ce->next_offset) != 0)
1471 compat_find_calc_match(struct xt_entry_match *m,
1473 const struct ip6t_ip6 *ipv6,
1474 unsigned int hookmask,
1477 struct xt_match *match;
1479 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1480 m->u.user.revision);
1481 if (IS_ERR(match)) {
1482 duprintf("compat_check_calc_match: `%s' not found\n",
1484 return PTR_ERR(match);
1486 m->u.kernel.match = match;
1487 *size += xt_compat_match_offset(match);
1491 static void compat_release_entry(struct compat_ip6t_entry *e)
1493 struct xt_entry_target *t;
1494 struct xt_entry_match *ematch;
1496 /* Cleanup all matches */
1497 xt_ematch_foreach(ematch, e)
1498 module_put(ematch->u.kernel.match->me);
1499 t = compat_ip6t_get_target(e);
1500 module_put(t->u.kernel.target->me);
1504 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1505 struct xt_table_info *newinfo,
1507 const unsigned char *base,
1508 const unsigned char *limit,
1509 const unsigned int *hook_entries,
1510 const unsigned int *underflows,
1513 struct xt_entry_match *ematch;
1514 struct xt_entry_target *t;
1515 struct xt_target *target;
1516 unsigned int entry_offset;
1520 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1521 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1522 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1523 duprintf("Bad offset %p, limit = %p\n", e, limit);
1527 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1528 sizeof(struct compat_xt_entry_target)) {
1529 duprintf("checking: element %p size %u\n",
1534 /* For purposes of check_entry casting the compat entry is fine */
1535 ret = check_entry((struct ip6t_entry *)e, name);
1539 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1540 entry_offset = (void *)e - (void *)base;
1542 xt_ematch_foreach(ematch, e) {
1543 ret = compat_find_calc_match(ematch, name,
1544 &e->ipv6, e->comefrom, &off);
1546 goto release_matches;
1550 t = compat_ip6t_get_target(e);
1551 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1552 t->u.user.revision);
1553 if (IS_ERR(target)) {
1554 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1556 ret = PTR_ERR(target);
1557 goto release_matches;
1559 t->u.kernel.target = target;
1561 off += xt_compat_target_offset(target);
1563 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1567 /* Check hooks & underflows */
1568 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1569 if ((unsigned char *)e - base == hook_entries[h])
1570 newinfo->hook_entry[h] = hook_entries[h];
1571 if ((unsigned char *)e - base == underflows[h])
1572 newinfo->underflow[h] = underflows[h];
1575 /* Clear counters and comefrom */
1576 memset(&e->counters, 0, sizeof(e->counters));
1581 module_put(t->u.kernel.target->me);
1583 xt_ematch_foreach(ematch, e) {
1586 module_put(ematch->u.kernel.match->me);
1592 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1593 unsigned int *size, const char *name,
1594 struct xt_table_info *newinfo, unsigned char *base)
1596 struct xt_entry_target *t;
1597 struct xt_target *target;
1598 struct ip6t_entry *de;
1599 unsigned int origsize;
1601 struct xt_entry_match *ematch;
1605 de = (struct ip6t_entry *)*dstptr;
1606 memcpy(de, e, sizeof(struct ip6t_entry));
1607 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1609 *dstptr += sizeof(struct ip6t_entry);
1610 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1612 xt_ematch_foreach(ematch, e) {
1613 ret = xt_compat_match_from_user(ematch, dstptr, size);
1617 de->target_offset = e->target_offset - (origsize - *size);
1618 t = compat_ip6t_get_target(e);
1619 target = t->u.kernel.target;
1620 xt_compat_target_from_user(t, dstptr, size);
1622 de->next_offset = e->next_offset - (origsize - *size);
1623 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1624 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1625 newinfo->hook_entry[h] -= origsize - *size;
1626 if ((unsigned char *)de - base < newinfo->underflow[h])
1627 newinfo->underflow[h] -= origsize - *size;
1632 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1637 struct xt_mtchk_param mtpar;
1638 struct xt_entry_match *ematch;
1643 mtpar.entryinfo = &e->ipv6;
1644 mtpar.hook_mask = e->comefrom;
1645 mtpar.family = NFPROTO_IPV6;
1646 xt_ematch_foreach(ematch, e) {
1647 ret = check_match(ematch, &mtpar);
1649 goto cleanup_matches;
1653 ret = check_target(e, net, name);
1655 goto cleanup_matches;
1659 xt_ematch_foreach(ematch, e) {
1662 cleanup_match(ematch, net);
1668 translate_compat_table(struct net *net,
1670 unsigned int valid_hooks,
1671 struct xt_table_info **pinfo,
1673 unsigned int total_size,
1674 unsigned int number,
1675 unsigned int *hook_entries,
1676 unsigned int *underflows)
1679 struct xt_table_info *newinfo, *info;
1680 void *pos, *entry0, *entry1;
1681 struct compat_ip6t_entry *iter0;
1682 struct ip6t_entry *iter1;
1689 info->number = number;
1691 /* Init all hooks to impossible value. */
1692 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1693 info->hook_entry[i] = 0xFFFFFFFF;
1694 info->underflow[i] = 0xFFFFFFFF;
1697 duprintf("translate_compat_table: size %u\n", info->size);
1699 xt_compat_lock(AF_INET6);
1700 xt_compat_init_offsets(AF_INET6, number);
1701 /* Walk through entries, checking offsets. */
1702 xt_entry_foreach(iter0, entry0, total_size) {
1703 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1705 entry0 + total_size,
1716 duprintf("translate_compat_table: %u not %u entries\n",
1721 /* Check hooks all assigned */
1722 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1723 /* Only hooks which are valid */
1724 if (!(valid_hooks & (1 << i)))
1726 if (info->hook_entry[i] == 0xFFFFFFFF) {
1727 duprintf("Invalid hook entry %u %u\n",
1728 i, hook_entries[i]);
1731 if (info->underflow[i] == 0xFFFFFFFF) {
1732 duprintf("Invalid underflow %u %u\n",
1739 newinfo = xt_alloc_table_info(size);
1743 newinfo->number = number;
1744 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1745 newinfo->hook_entry[i] = info->hook_entry[i];
1746 newinfo->underflow[i] = info->underflow[i];
1748 entry1 = newinfo->entries[raw_smp_processor_id()];
1751 xt_entry_foreach(iter0, entry0, total_size) {
1752 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1753 name, newinfo, entry1);
1757 xt_compat_flush_offsets(AF_INET6);
1758 xt_compat_unlock(AF_INET6);
1763 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1767 xt_entry_foreach(iter1, entry1, newinfo->size) {
1768 ret = compat_check_entry(iter1, net, name);
1772 if (strcmp(ip6t_get_target(iter1)->u.user.name,
1773 XT_ERROR_TARGET) == 0)
1774 ++newinfo->stacksize;
1778 * The first i matches need cleanup_entry (calls ->destroy)
1779 * because they had called ->check already. The other j-i
1780 * entries need only release.
1784 xt_entry_foreach(iter0, entry0, newinfo->size) {
1789 compat_release_entry(iter0);
1791 xt_entry_foreach(iter1, entry1, newinfo->size) {
1794 cleanup_entry(iter1, net);
1796 xt_free_table_info(newinfo);
1800 /* And one copy for every other CPU */
1801 for_each_possible_cpu(i)
1802 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1803 memcpy(newinfo->entries[i], entry1, newinfo->size);
1807 xt_free_table_info(info);
1811 xt_free_table_info(newinfo);
1813 xt_entry_foreach(iter0, entry0, total_size) {
1816 compat_release_entry(iter0);
1820 xt_compat_flush_offsets(AF_INET6);
1821 xt_compat_unlock(AF_INET6);
1826 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1829 struct compat_ip6t_replace tmp;
1830 struct xt_table_info *newinfo;
1831 void *loc_cpu_entry;
1832 struct ip6t_entry *iter;
1834 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1837 /* overflow check */
1838 if (tmp.size >= INT_MAX / num_possible_cpus())
1840 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1843 newinfo = xt_alloc_table_info(tmp.size);
1847 /* choose the copy that is on our node/cpu */
1848 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1849 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1855 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1856 &newinfo, &loc_cpu_entry, tmp.size,
1857 tmp.num_entries, tmp.hook_entry,
1862 duprintf("compat_do_replace: Translated table\n");
1864 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1865 tmp.num_counters, compat_ptr(tmp.counters));
1867 goto free_newinfo_untrans;
1870 free_newinfo_untrans:
1871 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1872 cleanup_entry(iter, net);
1874 xt_free_table_info(newinfo);
1879 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1884 if (!capable(CAP_NET_ADMIN))
1888 case IP6T_SO_SET_REPLACE:
1889 ret = compat_do_replace(sock_net(sk), user, len);
1892 case IP6T_SO_SET_ADD_COUNTERS:
1893 ret = do_add_counters(sock_net(sk), user, len, 1);
1897 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1904 struct compat_ip6t_get_entries {
1905 char name[XT_TABLE_MAXNAMELEN];
1907 struct compat_ip6t_entry entrytable[0];
1911 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1912 void __user *userptr)
1914 struct xt_counters *counters;
1915 const struct xt_table_info *private = table->private;
1919 const void *loc_cpu_entry;
1921 struct ip6t_entry *iter;
1923 counters = alloc_counters(table);
1924 if (IS_ERR(counters))
1925 return PTR_ERR(counters);
1927 /* choose the copy that is on our node/cpu, ...
1928 * This choice is lazy (because current thread is
1929 * allowed to migrate to another cpu)
1931 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1934 xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1935 ret = compat_copy_entry_to_user(iter, &pos,
1936 &size, counters, i++);
1946 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1950 struct compat_ip6t_get_entries get;
1953 if (*len < sizeof(get)) {
1954 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1958 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1961 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1962 duprintf("compat_get_entries: %u != %zu\n",
1963 *len, sizeof(get) + get.size);
1967 xt_compat_lock(AF_INET6);
1968 t = xt_find_table_lock(net, AF_INET6, get.name);
1969 if (t && !IS_ERR(t)) {
1970 const struct xt_table_info *private = t->private;
1971 struct xt_table_info info;
1972 duprintf("t->private->number = %u\n", private->number);
1973 ret = compat_table_info(private, &info);
1974 if (!ret && get.size == info.size) {
1975 ret = compat_copy_entries_to_user(private->size,
1976 t, uptr->entrytable);
1978 duprintf("compat_get_entries: I've got %u not %u!\n",
1979 private->size, get.size);
1982 xt_compat_flush_offsets(AF_INET6);
1986 ret = t ? PTR_ERR(t) : -ENOENT;
1988 xt_compat_unlock(AF_INET6);
1992 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1995 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1999 if (!capable(CAP_NET_ADMIN))
2003 case IP6T_SO_GET_INFO:
2004 ret = get_info(sock_net(sk), user, len, 1);
2006 case IP6T_SO_GET_ENTRIES:
2007 ret = compat_get_entries(sock_net(sk), user, len);
2010 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2017 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2021 if (!capable(CAP_NET_ADMIN))
2025 case IP6T_SO_SET_REPLACE:
2026 ret = do_replace(sock_net(sk), user, len);
2029 case IP6T_SO_SET_ADD_COUNTERS:
2030 ret = do_add_counters(sock_net(sk), user, len, 0);
2034 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2042 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2046 if (!capable(CAP_NET_ADMIN))
2050 case IP6T_SO_GET_INFO:
2051 ret = get_info(sock_net(sk), user, len, 0);
2054 case IP6T_SO_GET_ENTRIES:
2055 ret = get_entries(sock_net(sk), user, len);
2058 case IP6T_SO_GET_REVISION_MATCH:
2059 case IP6T_SO_GET_REVISION_TARGET: {
2060 struct xt_get_revision rev;
2063 if (*len != sizeof(rev)) {
2067 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2072 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2077 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2080 "ip6t_%s", rev.name);
2085 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2092 struct xt_table *ip6t_register_table(struct net *net,
2093 const struct xt_table *table,
2094 const struct ip6t_replace *repl)
2097 struct xt_table_info *newinfo;
2098 struct xt_table_info bootstrap = {0};
2099 void *loc_cpu_entry;
2100 struct xt_table *new_table;
2102 newinfo = xt_alloc_table_info(repl->size);
2108 /* choose the copy on our node/cpu, but dont care about preemption */
2109 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2110 memcpy(loc_cpu_entry, repl->entries, repl->size);
2112 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2116 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2117 if (IS_ERR(new_table)) {
2118 ret = PTR_ERR(new_table);
2124 xt_free_table_info(newinfo);
2126 return ERR_PTR(ret);
2129 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2131 struct xt_table_info *private;
2132 void *loc_cpu_entry;
2133 struct module *table_owner = table->me;
2134 struct ip6t_entry *iter;
2136 private = xt_unregister_table(table);
2138 /* Decrease module usage counts and free resources */
2139 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2140 xt_entry_foreach(iter, loc_cpu_entry, private->size)
2141 cleanup_entry(iter, net);
2142 if (private->number > private->initial_entries)
2143 module_put(table_owner);
2144 xt_free_table_info(private);
2147 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2149 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2150 u_int8_t type, u_int8_t code,
2153 return (type == test_type && code >= min_code && code <= max_code)
2158 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2160 const struct icmp6hdr *ic;
2161 struct icmp6hdr _icmph;
2162 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2164 /* Must not be a fragment. */
2165 if (par->fragoff != 0)
2168 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2170 /* We've been asked to examine this packet, and we
2171 * can't. Hence, no choice but to drop.
2173 duprintf("Dropping evil ICMP tinygram.\n");
2174 par->hotdrop = true;
2178 return icmp6_type_code_match(icmpinfo->type,
2181 ic->icmp6_type, ic->icmp6_code,
2182 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2185 /* Called when user tries to insert an entry of this type. */
2186 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2188 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2190 /* Must specify no unknown invflags */
2191 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2194 /* The built-in targets: standard (NULL) and error. */
2195 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2197 .name = XT_STANDARD_TARGET,
2198 .targetsize = sizeof(int),
2199 .family = NFPROTO_IPV6,
2200 #ifdef CONFIG_COMPAT
2201 .compatsize = sizeof(compat_int_t),
2202 .compat_from_user = compat_standard_from_user,
2203 .compat_to_user = compat_standard_to_user,
2207 .name = XT_ERROR_TARGET,
2208 .target = ip6t_error,
2209 .targetsize = XT_FUNCTION_MAXNAMELEN,
2210 .family = NFPROTO_IPV6,
2214 static struct nf_sockopt_ops ip6t_sockopts = {
2216 .set_optmin = IP6T_BASE_CTL,
2217 .set_optmax = IP6T_SO_SET_MAX+1,
2218 .set = do_ip6t_set_ctl,
2219 #ifdef CONFIG_COMPAT
2220 .compat_set = compat_do_ip6t_set_ctl,
2222 .get_optmin = IP6T_BASE_CTL,
2223 .get_optmax = IP6T_SO_GET_MAX+1,
2224 .get = do_ip6t_get_ctl,
2225 #ifdef CONFIG_COMPAT
2226 .compat_get = compat_do_ip6t_get_ctl,
2228 .owner = THIS_MODULE,
2231 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2234 .match = icmp6_match,
2235 .matchsize = sizeof(struct ip6t_icmp),
2236 .checkentry = icmp6_checkentry,
2237 .proto = IPPROTO_ICMPV6,
2238 .family = NFPROTO_IPV6,
2242 static int __net_init ip6_tables_net_init(struct net *net)
2244 return xt_proto_init(net, NFPROTO_IPV6);
2247 static void __net_exit ip6_tables_net_exit(struct net *net)
2249 xt_proto_fini(net, NFPROTO_IPV6);
2252 static struct pernet_operations ip6_tables_net_ops = {
2253 .init = ip6_tables_net_init,
2254 .exit = ip6_tables_net_exit,
2257 static int __init ip6_tables_init(void)
2261 ret = register_pernet_subsys(&ip6_tables_net_ops);
2265 /* Noone else will be downing sem now, so we won't sleep */
2266 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2269 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2273 /* Register setsockopt */
2274 ret = nf_register_sockopt(&ip6t_sockopts);
2278 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2282 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2284 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2286 unregister_pernet_subsys(&ip6_tables_net_ops);
2291 static void __exit ip6_tables_fini(void)
2293 nf_unregister_sockopt(&ip6t_sockopts);
2295 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2296 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2297 unregister_pernet_subsys(&ip6_tables_net_ops);
2301 * find the offset to specified header or the protocol number of last header
2302 * if target < 0. "last header" is transport protocol header, ESP, or
2305 * If target header is found, its offset is set in *offset and return protocol
2306 * number. Otherwise, return -1.
2308 * If the first fragment doesn't contain the final protocol header or
2309 * NEXTHDR_NONE it is considered invalid.
2311 * Note that non-1st fragment is special case that "the protocol number
2312 * of last header" is "next header" field in Fragment header. In this case,
2313 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2317 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2318 int target, unsigned short *fragoff)
2320 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2321 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2322 unsigned int len = skb->len - start;
2327 while (nexthdr != target) {
2328 struct ipv6_opt_hdr _hdr, *hp;
2329 unsigned int hdrlen;
2331 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2337 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2340 if (nexthdr == NEXTHDR_FRAGMENT) {
2341 unsigned short _frag_off;
2343 fp = skb_header_pointer(skb,
2344 start+offsetof(struct frag_hdr,
2351 _frag_off = ntohs(*fp) & ~0x7;
2354 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2355 hp->nexthdr == NEXTHDR_NONE)) {
2357 *fragoff = _frag_off;
2363 } else if (nexthdr == NEXTHDR_AUTH)
2364 hdrlen = (hp->hdrlen + 2) << 2;
2366 hdrlen = ipv6_optlen(hp);
2368 nexthdr = hp->nexthdr;
2377 EXPORT_SYMBOL(ip6t_register_table);
2378 EXPORT_SYMBOL(ip6t_unregister_table);
2379 EXPORT_SYMBOL(ip6t_do_table);
2380 EXPORT_SYMBOL(ip6t_ext_hdr);
2381 EXPORT_SYMBOL(ipv6_find_hdr);
2383 module_init(ip6_tables_init);
2384 module_exit(ip6_tables_fini);