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) \
58 printk("IP_NF_ASSERT: %s:%s:%u\n", \
59 __func__, __FILE__, __LINE__); \
62 #define IP_NF_ASSERT(x)
66 /* All the better to debug you with... */
71 void *ip6t_alloc_initial_table(const struct xt_table *info)
73 return xt_alloc_initial_table(ip6t, IP6T);
75 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
78 We keep a set of rules for each CPU, so we can avoid write-locking
79 them in the softirq when updating the counters and therefore
80 only need to read-lock in the softirq; doing a write_lock_bh() in user
81 context stops packets coming through and allows user context to read
82 the counters or update the rules.
84 Hence the start of any table is given by get_table() below. */
86 /* Check for an extension */
88 ip6t_ext_hdr(u8 nexthdr)
90 return ( (nexthdr == IPPROTO_HOPOPTS) ||
91 (nexthdr == IPPROTO_ROUTING) ||
92 (nexthdr == IPPROTO_FRAGMENT) ||
93 (nexthdr == IPPROTO_ESP) ||
94 (nexthdr == IPPROTO_AH) ||
95 (nexthdr == IPPROTO_NONE) ||
96 (nexthdr == IPPROTO_DSTOPTS) );
99 /* Returns whether matches rule or not. */
100 /* Performance critical - called for every packet */
102 ip6_packet_match(const struct sk_buff *skb,
105 const struct ip6t_ip6 *ip6info,
106 unsigned int *protoff,
107 int *fragoff, bool *hotdrop)
110 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
112 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
114 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
115 &ip6info->src), IP6T_INV_SRCIP) ||
116 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
117 &ip6info->dst), IP6T_INV_DSTIP)) {
118 dprintf("Source or dest mismatch.\n");
120 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
121 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
122 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
123 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
124 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
125 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
129 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
131 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
132 dprintf("VIA in mismatch (%s vs %s).%s\n",
133 indev, ip6info->iniface,
134 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
138 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
140 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
141 dprintf("VIA out mismatch (%s vs %s).%s\n",
142 outdev, ip6info->outiface,
143 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
147 /* ... might want to do something with class and flowlabel here ... */
149 /* look for the desired protocol header */
150 if((ip6info->flags & IP6T_F_PROTO)) {
152 unsigned short _frag_off;
154 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
160 *fragoff = _frag_off;
162 dprintf("Packet protocol %hi ?= %s%hi.\n",
164 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
167 if (ip6info->proto == protohdr) {
168 if(ip6info->invflags & IP6T_INV_PROTO) {
174 /* We need match for the '-p all', too! */
175 if ((ip6info->proto != 0) &&
176 !(ip6info->invflags & IP6T_INV_PROTO))
182 /* should be ip6 safe */
184 ip6_checkentry(const struct ip6t_ip6 *ipv6)
186 if (ipv6->flags & ~IP6T_F_MASK) {
187 duprintf("Unknown flag bits set: %08X\n",
188 ipv6->flags & ~IP6T_F_MASK);
191 if (ipv6->invflags & ~IP6T_INV_MASK) {
192 duprintf("Unknown invflag bits set: %08X\n",
193 ipv6->invflags & ~IP6T_INV_MASK);
200 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
203 pr_info("error: `%s'\n", (const char *)par->targinfo);
208 static inline struct ip6t_entry *
209 get_entry(const void *base, unsigned int offset)
211 return (struct ip6t_entry *)(base + offset);
214 /* All zeroes == unconditional rule. */
215 /* Mildly perf critical (only if packet tracing is on) */
216 static inline bool unconditional(const struct ip6t_ip6 *ipv6)
218 static const struct ip6t_ip6 uncond;
220 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
223 static inline const struct ip6t_entry_target *
224 ip6t_get_target_c(const struct ip6t_entry *e)
226 return ip6t_get_target((struct ip6t_entry *)e);
229 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
230 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
231 /* This cries for unification! */
232 static const char *const hooknames[] = {
233 [NF_INET_PRE_ROUTING] = "PREROUTING",
234 [NF_INET_LOCAL_IN] = "INPUT",
235 [NF_INET_FORWARD] = "FORWARD",
236 [NF_INET_LOCAL_OUT] = "OUTPUT",
237 [NF_INET_POST_ROUTING] = "POSTROUTING",
240 enum nf_ip_trace_comments {
241 NF_IP6_TRACE_COMMENT_RULE,
242 NF_IP6_TRACE_COMMENT_RETURN,
243 NF_IP6_TRACE_COMMENT_POLICY,
246 static const char *const comments[] = {
247 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
248 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
249 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
252 static struct nf_loginfo trace_loginfo = {
253 .type = NF_LOG_TYPE_LOG,
257 .logflags = NF_LOG_MASK,
262 /* Mildly perf critical (only if packet tracing is on) */
264 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
265 const char *hookname, const char **chainname,
266 const char **comment, unsigned int *rulenum)
268 const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s);
270 if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
271 /* Head of user chain: ERROR target with chainname */
272 *chainname = t->target.data;
277 if (s->target_offset == sizeof(struct ip6t_entry) &&
278 strcmp(t->target.u.kernel.target->name,
279 IP6T_STANDARD_TARGET) == 0 &&
281 unconditional(&s->ipv6)) {
282 /* Tail of chains: STANDARD target (return/policy) */
283 *comment = *chainname == hookname
284 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
285 : comments[NF_IP6_TRACE_COMMENT_RETURN];
294 static void trace_packet(const struct sk_buff *skb,
296 const struct net_device *in,
297 const struct net_device *out,
298 const char *tablename,
299 const struct xt_table_info *private,
300 const struct ip6t_entry *e)
302 const void *table_base;
303 const struct ip6t_entry *root;
304 const char *hookname, *chainname, *comment;
305 const struct ip6t_entry *iter;
306 unsigned int rulenum = 0;
308 table_base = private->entries[smp_processor_id()];
309 root = get_entry(table_base, private->hook_entry[hook]);
311 hookname = chainname = hooknames[hook];
312 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
314 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
315 if (get_chainname_rulenum(iter, e, hookname,
316 &chainname, &comment, &rulenum) != 0)
319 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
320 "TRACE: %s:%s:%s:%u ",
321 tablename, chainname, comment, rulenum);
325 static inline __pure struct ip6t_entry *
326 ip6t_next_entry(const struct ip6t_entry *entry)
328 return (void *)entry + entry->next_offset;
331 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
333 ip6t_do_table(struct sk_buff *skb,
335 const struct net_device *in,
336 const struct net_device *out,
337 struct xt_table *table)
339 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
340 /* Initializing verdict to NF_DROP keeps gcc happy. */
341 unsigned int verdict = NF_DROP;
342 const char *indev, *outdev;
343 const void *table_base;
344 struct ip6t_entry *e, **jumpstack;
345 unsigned int *stackptr, origptr, cpu;
346 const struct xt_table_info *private;
347 struct xt_action_param acpar;
350 indev = in ? in->name : nulldevname;
351 outdev = out ? out->name : nulldevname;
352 /* We handle fragments by dealing with the first fragment as
353 * if it was a normal packet. All other fragments are treated
354 * normally, except that they will NEVER match rules that ask
355 * things we don't know, ie. tcp syn flag or ports). If the
356 * rule is also a fragment-specific rule, non-fragments won't
358 acpar.hotdrop = false;
361 acpar.family = NFPROTO_IPV6;
362 acpar.hooknum = hook;
364 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
367 private = table->private;
368 cpu = smp_processor_id();
369 table_base = private->entries[cpu];
370 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
371 stackptr = &private->stackptr[cpu];
374 e = get_entry(table_base, private->hook_entry[hook]);
377 const struct ip6t_entry_target *t;
378 const struct xt_entry_match *ematch;
381 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
382 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
384 e = ip6t_next_entry(e);
388 xt_ematch_foreach(ematch, e) {
389 acpar.match = ematch->u.kernel.match;
390 acpar.matchinfo = ematch->data;
391 if (!acpar.match->match(skb, &acpar))
395 ADD_COUNTER(e->counters,
396 ntohs(ipv6_hdr(skb)->payload_len) +
397 sizeof(struct ipv6hdr), 1);
399 t = ip6t_get_target_c(e);
400 IP_NF_ASSERT(t->u.kernel.target);
402 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
403 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
404 /* The packet is traced: log it */
405 if (unlikely(skb->nf_trace))
406 trace_packet(skb, hook, in, out,
407 table->name, private, e);
409 /* Standard target? */
410 if (!t->u.kernel.target->target) {
413 v = ((struct ip6t_standard_target *)t)->verdict;
415 /* Pop from stack? */
416 if (v != IP6T_RETURN) {
417 verdict = (unsigned)(-v) - 1;
421 e = get_entry(table_base,
422 private->underflow[hook]);
424 e = ip6t_next_entry(jumpstack[--*stackptr]);
427 if (table_base + v != ip6t_next_entry(e) &&
428 !(e->ipv6.flags & IP6T_F_GOTO)) {
429 if (*stackptr >= private->stacksize) {
433 jumpstack[(*stackptr)++] = e;
436 e = get_entry(table_base, v);
440 acpar.target = t->u.kernel.target;
441 acpar.targinfo = t->data;
443 verdict = t->u.kernel.target->target(skb, &acpar);
444 if (verdict == IP6T_CONTINUE)
445 e = ip6t_next_entry(e);
449 } while (!acpar.hotdrop);
451 xt_info_rdunlock_bh();
454 #ifdef DEBUG_ALLOW_ALL
463 /* Figures out from what hook each rule can be called: returns 0 if
464 there are loops. Puts hook bitmask in comefrom. */
466 mark_source_chains(const struct xt_table_info *newinfo,
467 unsigned int valid_hooks, void *entry0)
471 /* No recursion; use packet counter to save back ptrs (reset
472 to 0 as we leave), and comefrom to save source hook bitmask */
473 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
474 unsigned int pos = newinfo->hook_entry[hook];
475 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
477 if (!(valid_hooks & (1 << hook)))
480 /* Set initial back pointer. */
481 e->counters.pcnt = pos;
484 const struct ip6t_standard_target *t
485 = (void *)ip6t_get_target_c(e);
486 int visited = e->comefrom & (1 << hook);
488 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
489 printk("iptables: loop hook %u pos %u %08X.\n",
490 hook, pos, e->comefrom);
493 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
495 /* Unconditional return/END. */
496 if ((e->target_offset == sizeof(struct ip6t_entry) &&
497 (strcmp(t->target.u.user.name,
498 IP6T_STANDARD_TARGET) == 0) &&
500 unconditional(&e->ipv6)) || visited) {
501 unsigned int oldpos, size;
503 if ((strcmp(t->target.u.user.name,
504 IP6T_STANDARD_TARGET) == 0) &&
505 t->verdict < -NF_MAX_VERDICT - 1) {
506 duprintf("mark_source_chains: bad "
507 "negative verdict (%i)\n",
512 /* Return: backtrack through the last
515 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
516 #ifdef DEBUG_IP_FIREWALL_USER
518 & (1 << NF_INET_NUMHOOKS)) {
519 duprintf("Back unset "
526 pos = e->counters.pcnt;
527 e->counters.pcnt = 0;
529 /* We're at the start. */
533 e = (struct ip6t_entry *)
535 } while (oldpos == pos + e->next_offset);
538 size = e->next_offset;
539 e = (struct ip6t_entry *)
540 (entry0 + pos + size);
541 e->counters.pcnt = pos;
544 int newpos = t->verdict;
546 if (strcmp(t->target.u.user.name,
547 IP6T_STANDARD_TARGET) == 0 &&
549 if (newpos > newinfo->size -
550 sizeof(struct ip6t_entry)) {
551 duprintf("mark_source_chains: "
552 "bad verdict (%i)\n",
556 /* This a jump; chase it. */
557 duprintf("Jump rule %u -> %u\n",
560 /* ... this is a fallthru */
561 newpos = pos + e->next_offset;
563 e = (struct ip6t_entry *)
565 e->counters.pcnt = pos;
570 duprintf("Finished chain %u\n", hook);
575 static void cleanup_match(struct ip6t_entry_match *m, struct net *net)
577 struct xt_mtdtor_param par;
580 par.match = m->u.kernel.match;
581 par.matchinfo = m->data;
582 par.family = NFPROTO_IPV6;
583 if (par.match->destroy != NULL)
584 par.match->destroy(&par);
585 module_put(par.match->me);
589 check_entry(const struct ip6t_entry *e, const char *name)
591 const struct ip6t_entry_target *t;
593 if (!ip6_checkentry(&e->ipv6)) {
594 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
598 if (e->target_offset + sizeof(struct ip6t_entry_target) >
602 t = ip6t_get_target_c(e);
603 if (e->target_offset + t->u.target_size > e->next_offset)
609 static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
611 const struct ip6t_ip6 *ipv6 = par->entryinfo;
614 par->match = m->u.kernel.match;
615 par->matchinfo = m->data;
617 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
618 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
620 duprintf("ip_tables: check failed for `%s'.\n",
628 find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
630 struct xt_match *match;
633 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
636 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
637 return PTR_ERR(match);
639 m->u.kernel.match = match;
641 ret = check_match(m, par);
647 module_put(m->u.kernel.match->me);
651 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
653 struct ip6t_entry_target *t = ip6t_get_target(e);
654 struct xt_tgchk_param par = {
658 .target = t->u.kernel.target,
660 .hook_mask = e->comefrom,
661 .family = NFPROTO_IPV6,
665 t = ip6t_get_target(e);
666 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
667 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
669 duprintf("ip_tables: check failed for `%s'.\n",
670 t->u.kernel.target->name);
677 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
680 struct ip6t_entry_target *t;
681 struct xt_target *target;
684 struct xt_mtchk_param mtpar;
685 struct xt_entry_match *ematch;
687 ret = check_entry(e, name);
694 mtpar.entryinfo = &e->ipv6;
695 mtpar.hook_mask = e->comefrom;
696 mtpar.family = NFPROTO_IPV6;
697 xt_ematch_foreach(ematch, e) {
698 ret = find_check_match(ematch, &mtpar);
700 goto cleanup_matches;
704 t = ip6t_get_target(e);
705 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
707 if (IS_ERR(target)) {
708 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
709 ret = PTR_ERR(target);
710 goto cleanup_matches;
712 t->u.kernel.target = target;
714 ret = check_target(e, net, name);
719 module_put(t->u.kernel.target->me);
721 xt_ematch_foreach(ematch, e) {
724 cleanup_match(ematch, net);
729 static bool check_underflow(const struct ip6t_entry *e)
731 const struct ip6t_entry_target *t;
732 unsigned int verdict;
734 if (!unconditional(&e->ipv6))
736 t = ip6t_get_target_c(e);
737 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
739 verdict = ((struct ip6t_standard_target *)t)->verdict;
740 verdict = -verdict - 1;
741 return verdict == NF_DROP || verdict == NF_ACCEPT;
745 check_entry_size_and_hooks(struct ip6t_entry *e,
746 struct xt_table_info *newinfo,
747 const unsigned char *base,
748 const unsigned char *limit,
749 const unsigned int *hook_entries,
750 const unsigned int *underflows,
751 unsigned int valid_hooks)
755 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
756 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
757 duprintf("Bad offset %p\n", e);
762 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
763 duprintf("checking: element %p size %u\n",
768 /* Check hooks & underflows */
769 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
770 if (!(valid_hooks & (1 << h)))
772 if ((unsigned char *)e - base == hook_entries[h])
773 newinfo->hook_entry[h] = hook_entries[h];
774 if ((unsigned char *)e - base == underflows[h]) {
775 if (!check_underflow(e)) {
776 pr_err("Underflows must be unconditional and "
777 "use the STANDARD target with "
781 newinfo->underflow[h] = underflows[h];
785 /* Clear counters and comefrom */
786 e->counters = ((struct xt_counters) { 0, 0 });
791 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
793 struct xt_tgdtor_param par;
794 struct ip6t_entry_target *t;
795 struct xt_entry_match *ematch;
797 /* Cleanup all matches */
798 xt_ematch_foreach(ematch, e)
799 cleanup_match(ematch, net);
800 t = ip6t_get_target(e);
803 par.target = t->u.kernel.target;
804 par.targinfo = t->data;
805 par.family = NFPROTO_IPV6;
806 if (par.target->destroy != NULL)
807 par.target->destroy(&par);
808 module_put(par.target->me);
811 /* Checks and translates the user-supplied table segment (held in
814 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
815 const struct ip6t_replace *repl)
817 struct ip6t_entry *iter;
821 newinfo->size = repl->size;
822 newinfo->number = repl->num_entries;
824 /* Init all hooks to impossible value. */
825 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
826 newinfo->hook_entry[i] = 0xFFFFFFFF;
827 newinfo->underflow[i] = 0xFFFFFFFF;
830 duprintf("translate_table: size %u\n", newinfo->size);
832 /* Walk through entries, checking offsets. */
833 xt_entry_foreach(iter, entry0, newinfo->size) {
834 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
842 if (strcmp(ip6t_get_target(iter)->u.user.name,
843 XT_ERROR_TARGET) == 0)
844 ++newinfo->stacksize;
847 if (i != repl->num_entries) {
848 duprintf("translate_table: %u not %u entries\n",
849 i, repl->num_entries);
853 /* Check hooks all assigned */
854 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
855 /* Only hooks which are valid */
856 if (!(repl->valid_hooks & (1 << i)))
858 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
859 duprintf("Invalid hook entry %u %u\n",
860 i, repl->hook_entry[i]);
863 if (newinfo->underflow[i] == 0xFFFFFFFF) {
864 duprintf("Invalid underflow %u %u\n",
865 i, repl->underflow[i]);
870 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
873 /* Finally, each sanity check must pass */
875 xt_entry_foreach(iter, entry0, newinfo->size) {
876 ret = find_check_entry(iter, net, repl->name, repl->size);
883 xt_entry_foreach(iter, entry0, newinfo->size) {
886 cleanup_entry(iter, net);
891 /* And one copy for every other CPU */
892 for_each_possible_cpu(i) {
893 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
894 memcpy(newinfo->entries[i], entry0, newinfo->size);
901 get_counters(const struct xt_table_info *t,
902 struct xt_counters counters[])
904 struct ip6t_entry *iter;
909 /* Instead of clearing (by a previous call to memset())
910 * the counters and using adds, we set the counters
911 * with data used by 'current' CPU
913 * Bottom half has to be disabled to prevent deadlock
914 * if new softirq were to run and call ipt_do_table
917 curcpu = smp_processor_id();
920 xt_entry_foreach(iter, t->entries[curcpu], t->size) {
921 SET_COUNTER(counters[i], iter->counters.bcnt,
922 iter->counters.pcnt);
926 for_each_possible_cpu(cpu) {
931 xt_entry_foreach(iter, t->entries[cpu], t->size) {
932 ADD_COUNTER(counters[i], iter->counters.bcnt,
933 iter->counters.pcnt);
936 xt_info_wrunlock(cpu);
941 static struct xt_counters *alloc_counters(const struct xt_table *table)
943 unsigned int countersize;
944 struct xt_counters *counters;
945 const struct xt_table_info *private = table->private;
947 /* We need atomic snapshot of counters: rest doesn't change
948 (other than comefrom, which userspace doesn't care
950 countersize = sizeof(struct xt_counters) * private->number;
951 counters = vmalloc_node(countersize, numa_node_id());
953 if (counters == NULL)
954 return ERR_PTR(-ENOMEM);
956 get_counters(private, counters);
962 copy_entries_to_user(unsigned int total_size,
963 const struct xt_table *table,
964 void __user *userptr)
966 unsigned int off, num;
967 const struct ip6t_entry *e;
968 struct xt_counters *counters;
969 const struct xt_table_info *private = table->private;
971 const void *loc_cpu_entry;
973 counters = alloc_counters(table);
974 if (IS_ERR(counters))
975 return PTR_ERR(counters);
977 /* choose the copy that is on our node/cpu, ...
978 * This choice is lazy (because current thread is
979 * allowed to migrate to another cpu)
981 loc_cpu_entry = private->entries[raw_smp_processor_id()];
982 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
987 /* FIXME: use iterator macros --RR */
988 /* ... then go back and fix counters and names */
989 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
991 const struct ip6t_entry_match *m;
992 const struct ip6t_entry_target *t;
994 e = (struct ip6t_entry *)(loc_cpu_entry + off);
995 if (copy_to_user(userptr + off
996 + offsetof(struct ip6t_entry, counters),
998 sizeof(counters[num])) != 0) {
1003 for (i = sizeof(struct ip6t_entry);
1004 i < e->target_offset;
1005 i += m->u.match_size) {
1008 if (copy_to_user(userptr + off + i
1009 + offsetof(struct ip6t_entry_match,
1011 m->u.kernel.match->name,
1012 strlen(m->u.kernel.match->name)+1)
1019 t = ip6t_get_target_c(e);
1020 if (copy_to_user(userptr + off + e->target_offset
1021 + offsetof(struct ip6t_entry_target,
1023 t->u.kernel.target->name,
1024 strlen(t->u.kernel.target->name)+1) != 0) {
1035 #ifdef CONFIG_COMPAT
1036 static void compat_standard_from_user(void *dst, const void *src)
1038 int v = *(compat_int_t *)src;
1041 v += xt_compat_calc_jump(AF_INET6, v);
1042 memcpy(dst, &v, sizeof(v));
1045 static int compat_standard_to_user(void __user *dst, const void *src)
1047 compat_int_t cv = *(int *)src;
1050 cv -= xt_compat_calc_jump(AF_INET6, cv);
1051 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1054 static int compat_calc_entry(const struct ip6t_entry *e,
1055 const struct xt_table_info *info,
1056 const void *base, struct xt_table_info *newinfo)
1058 const struct xt_entry_match *ematch;
1059 const struct ip6t_entry_target *t;
1060 unsigned int entry_offset;
1063 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1064 entry_offset = (void *)e - base;
1065 xt_ematch_foreach(ematch, e)
1066 off += xt_compat_match_offset(ematch->u.kernel.match);
1067 t = ip6t_get_target_c(e);
1068 off += xt_compat_target_offset(t->u.kernel.target);
1069 newinfo->size -= off;
1070 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1074 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1075 if (info->hook_entry[i] &&
1076 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1077 newinfo->hook_entry[i] -= off;
1078 if (info->underflow[i] &&
1079 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1080 newinfo->underflow[i] -= off;
1085 static int compat_table_info(const struct xt_table_info *info,
1086 struct xt_table_info *newinfo)
1088 struct ip6t_entry *iter;
1089 void *loc_cpu_entry;
1092 if (!newinfo || !info)
1095 /* we dont care about newinfo->entries[] */
1096 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1097 newinfo->initial_entries = 0;
1098 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1099 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1100 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1108 static int get_info(struct net *net, void __user *user,
1109 const int *len, int compat)
1111 char name[IP6T_TABLE_MAXNAMELEN];
1115 if (*len != sizeof(struct ip6t_getinfo)) {
1116 duprintf("length %u != %zu\n", *len,
1117 sizeof(struct ip6t_getinfo));
1121 if (copy_from_user(name, user, sizeof(name)) != 0)
1124 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1125 #ifdef CONFIG_COMPAT
1127 xt_compat_lock(AF_INET6);
1129 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1130 "ip6table_%s", name);
1131 if (t && !IS_ERR(t)) {
1132 struct ip6t_getinfo info;
1133 const struct xt_table_info *private = t->private;
1134 #ifdef CONFIG_COMPAT
1135 struct xt_table_info tmp;
1138 ret = compat_table_info(private, &tmp);
1139 xt_compat_flush_offsets(AF_INET6);
1143 info.valid_hooks = t->valid_hooks;
1144 memcpy(info.hook_entry, private->hook_entry,
1145 sizeof(info.hook_entry));
1146 memcpy(info.underflow, private->underflow,
1147 sizeof(info.underflow));
1148 info.num_entries = private->number;
1149 info.size = private->size;
1150 strcpy(info.name, name);
1152 if (copy_to_user(user, &info, *len) != 0)
1160 ret = t ? PTR_ERR(t) : -ENOENT;
1161 #ifdef CONFIG_COMPAT
1163 xt_compat_unlock(AF_INET6);
1169 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1173 struct ip6t_get_entries get;
1176 if (*len < sizeof(get)) {
1177 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1180 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1182 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1183 duprintf("get_entries: %u != %zu\n",
1184 *len, sizeof(get) + get.size);
1188 t = xt_find_table_lock(net, AF_INET6, get.name);
1189 if (t && !IS_ERR(t)) {
1190 struct xt_table_info *private = t->private;
1191 duprintf("t->private->number = %u\n", private->number);
1192 if (get.size == private->size)
1193 ret = copy_entries_to_user(private->size,
1194 t, uptr->entrytable);
1196 duprintf("get_entries: I've got %u not %u!\n",
1197 private->size, get.size);
1203 ret = t ? PTR_ERR(t) : -ENOENT;
1209 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1210 struct xt_table_info *newinfo, unsigned int num_counters,
1211 void __user *counters_ptr)
1215 struct xt_table_info *oldinfo;
1216 struct xt_counters *counters;
1217 const void *loc_cpu_old_entry;
1218 struct ip6t_entry *iter;
1221 counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
1228 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1229 "ip6table_%s", name);
1230 if (!t || IS_ERR(t)) {
1231 ret = t ? PTR_ERR(t) : -ENOENT;
1232 goto free_newinfo_counters_untrans;
1236 if (valid_hooks != t->valid_hooks) {
1237 duprintf("Valid hook crap: %08X vs %08X\n",
1238 valid_hooks, t->valid_hooks);
1243 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1247 /* Update module usage count based on number of rules */
1248 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1249 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1250 if ((oldinfo->number > oldinfo->initial_entries) ||
1251 (newinfo->number <= oldinfo->initial_entries))
1253 if ((oldinfo->number > oldinfo->initial_entries) &&
1254 (newinfo->number <= oldinfo->initial_entries))
1257 /* Get the old counters, and synchronize with replace */
1258 get_counters(oldinfo, counters);
1260 /* Decrease module usage counts and free resource */
1261 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1262 xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
1263 cleanup_entry(iter, net);
1265 xt_free_table_info(oldinfo);
1266 if (copy_to_user(counters_ptr, counters,
1267 sizeof(struct xt_counters) * num_counters) != 0)
1276 free_newinfo_counters_untrans:
1283 do_replace(struct net *net, const void __user *user, unsigned int len)
1286 struct ip6t_replace tmp;
1287 struct xt_table_info *newinfo;
1288 void *loc_cpu_entry;
1289 struct ip6t_entry *iter;
1291 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1294 /* overflow check */
1295 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1298 newinfo = xt_alloc_table_info(tmp.size);
1302 /* choose the copy that is on our node/cpu */
1303 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1304 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1310 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1314 duprintf("ip_tables: Translated table\n");
1316 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1317 tmp.num_counters, tmp.counters);
1319 goto free_newinfo_untrans;
1322 free_newinfo_untrans:
1323 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1324 cleanup_entry(iter, net);
1326 xt_free_table_info(newinfo);
1331 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1334 unsigned int i, curcpu;
1335 struct xt_counters_info tmp;
1336 struct xt_counters *paddc;
1337 unsigned int num_counters;
1342 const struct xt_table_info *private;
1344 const void *loc_cpu_entry;
1345 struct ip6t_entry *iter;
1346 #ifdef CONFIG_COMPAT
1347 struct compat_xt_counters_info compat_tmp;
1351 size = sizeof(struct compat_xt_counters_info);
1356 size = sizeof(struct xt_counters_info);
1359 if (copy_from_user(ptmp, user, size) != 0)
1362 #ifdef CONFIG_COMPAT
1364 num_counters = compat_tmp.num_counters;
1365 name = compat_tmp.name;
1369 num_counters = tmp.num_counters;
1373 if (len != size + num_counters * sizeof(struct xt_counters))
1376 paddc = vmalloc_node(len - size, numa_node_id());
1380 if (copy_from_user(paddc, user + size, len - size) != 0) {
1385 t = xt_find_table_lock(net, AF_INET6, name);
1386 if (!t || IS_ERR(t)) {
1387 ret = t ? PTR_ERR(t) : -ENOENT;
1393 private = t->private;
1394 if (private->number != num_counters) {
1396 goto unlock_up_free;
1400 /* Choose the copy that is on our node */
1401 curcpu = smp_processor_id();
1402 xt_info_wrlock(curcpu);
1403 loc_cpu_entry = private->entries[curcpu];
1404 xt_entry_foreach(iter, loc_cpu_entry, private->size) {
1405 ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt);
1408 xt_info_wrunlock(curcpu);
1420 #ifdef CONFIG_COMPAT
1421 struct compat_ip6t_replace {
1422 char name[IP6T_TABLE_MAXNAMELEN];
1426 u32 hook_entry[NF_INET_NUMHOOKS];
1427 u32 underflow[NF_INET_NUMHOOKS];
1429 compat_uptr_t counters; /* struct ip6t_counters * */
1430 struct compat_ip6t_entry entries[0];
1434 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1435 unsigned int *size, struct xt_counters *counters,
1438 struct ip6t_entry_target *t;
1439 struct compat_ip6t_entry __user *ce;
1440 u_int16_t target_offset, next_offset;
1441 compat_uint_t origsize;
1442 const struct xt_entry_match *ematch;
1446 ce = (struct compat_ip6t_entry __user *)*dstptr;
1447 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1448 copy_to_user(&ce->counters, &counters[i],
1449 sizeof(counters[i])) != 0)
1452 *dstptr += sizeof(struct compat_ip6t_entry);
1453 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1455 xt_ematch_foreach(ematch, e) {
1456 ret = xt_compat_match_to_user(ematch, dstptr, size);
1460 target_offset = e->target_offset - (origsize - *size);
1461 t = ip6t_get_target(e);
1462 ret = xt_compat_target_to_user(t, dstptr, size);
1465 next_offset = e->next_offset - (origsize - *size);
1466 if (put_user(target_offset, &ce->target_offset) != 0 ||
1467 put_user(next_offset, &ce->next_offset) != 0)
1473 compat_find_calc_match(struct ip6t_entry_match *m,
1475 const struct ip6t_ip6 *ipv6,
1476 unsigned int hookmask,
1479 struct xt_match *match;
1481 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1482 m->u.user.revision);
1483 if (IS_ERR(match)) {
1484 duprintf("compat_check_calc_match: `%s' not found\n",
1486 return PTR_ERR(match);
1488 m->u.kernel.match = match;
1489 *size += xt_compat_match_offset(match);
1493 static void compat_release_entry(struct compat_ip6t_entry *e)
1495 struct ip6t_entry_target *t;
1496 struct xt_entry_match *ematch;
1498 /* Cleanup all matches */
1499 xt_ematch_foreach(ematch, e)
1500 module_put(ematch->u.kernel.match->me);
1501 t = compat_ip6t_get_target(e);
1502 module_put(t->u.kernel.target->me);
1506 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1507 struct xt_table_info *newinfo,
1509 const unsigned char *base,
1510 const unsigned char *limit,
1511 const unsigned int *hook_entries,
1512 const unsigned int *underflows,
1515 struct xt_entry_match *ematch;
1516 struct ip6t_entry_target *t;
1517 struct xt_target *target;
1518 unsigned int entry_offset;
1522 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1523 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1524 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1525 duprintf("Bad offset %p, limit = %p\n", e, limit);
1529 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1530 sizeof(struct compat_xt_entry_target)) {
1531 duprintf("checking: element %p size %u\n",
1536 /* For purposes of check_entry casting the compat entry is fine */
1537 ret = check_entry((struct ip6t_entry *)e, name);
1541 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1542 entry_offset = (void *)e - (void *)base;
1544 xt_ematch_foreach(ematch, e) {
1545 ret = compat_find_calc_match(ematch, name,
1546 &e->ipv6, e->comefrom, &off);
1548 goto release_matches;
1552 t = compat_ip6t_get_target(e);
1553 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1554 t->u.user.revision);
1555 if (IS_ERR(target)) {
1556 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1558 ret = PTR_ERR(target);
1559 goto release_matches;
1561 t->u.kernel.target = target;
1563 off += xt_compat_target_offset(target);
1565 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1569 /* Check hooks & underflows */
1570 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1571 if ((unsigned char *)e - base == hook_entries[h])
1572 newinfo->hook_entry[h] = hook_entries[h];
1573 if ((unsigned char *)e - base == underflows[h])
1574 newinfo->underflow[h] = underflows[h];
1577 /* Clear counters and comefrom */
1578 memset(&e->counters, 0, sizeof(e->counters));
1583 module_put(t->u.kernel.target->me);
1585 xt_ematch_foreach(ematch, e) {
1588 module_put(ematch->u.kernel.match->me);
1594 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1595 unsigned int *size, const char *name,
1596 struct xt_table_info *newinfo, unsigned char *base)
1598 struct ip6t_entry_target *t;
1599 struct xt_target *target;
1600 struct ip6t_entry *de;
1601 unsigned int origsize;
1603 struct xt_entry_match *ematch;
1607 de = (struct ip6t_entry *)*dstptr;
1608 memcpy(de, e, sizeof(struct ip6t_entry));
1609 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1611 *dstptr += sizeof(struct ip6t_entry);
1612 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1614 xt_ematch_foreach(ematch, e) {
1615 ret = xt_compat_match_from_user(ematch, dstptr, size);
1619 de->target_offset = e->target_offset - (origsize - *size);
1620 t = compat_ip6t_get_target(e);
1621 target = t->u.kernel.target;
1622 xt_compat_target_from_user(t, dstptr, size);
1624 de->next_offset = e->next_offset - (origsize - *size);
1625 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1626 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1627 newinfo->hook_entry[h] -= origsize - *size;
1628 if ((unsigned char *)de - base < newinfo->underflow[h])
1629 newinfo->underflow[h] -= origsize - *size;
1634 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1639 struct xt_mtchk_param mtpar;
1640 struct xt_entry_match *ematch;
1645 mtpar.entryinfo = &e->ipv6;
1646 mtpar.hook_mask = e->comefrom;
1647 mtpar.family = NFPROTO_IPV6;
1648 xt_ematch_foreach(ematch, e) {
1649 ret = check_match(ematch, &mtpar);
1651 goto cleanup_matches;
1655 ret = check_target(e, net, name);
1657 goto cleanup_matches;
1661 xt_ematch_foreach(ematch, e) {
1664 cleanup_match(ematch, net);
1670 translate_compat_table(struct net *net,
1672 unsigned int valid_hooks,
1673 struct xt_table_info **pinfo,
1675 unsigned int total_size,
1676 unsigned int number,
1677 unsigned int *hook_entries,
1678 unsigned int *underflows)
1681 struct xt_table_info *newinfo, *info;
1682 void *pos, *entry0, *entry1;
1683 struct compat_ip6t_entry *iter0;
1684 struct ip6t_entry *iter1;
1691 info->number = number;
1693 /* Init all hooks to impossible value. */
1694 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1695 info->hook_entry[i] = 0xFFFFFFFF;
1696 info->underflow[i] = 0xFFFFFFFF;
1699 duprintf("translate_compat_table: size %u\n", info->size);
1701 xt_compat_lock(AF_INET6);
1702 /* Walk through entries, checking offsets. */
1703 xt_entry_foreach(iter0, entry0, total_size) {
1704 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1706 entry0 + total_size,
1717 duprintf("translate_compat_table: %u not %u entries\n",
1722 /* Check hooks all assigned */
1723 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1724 /* Only hooks which are valid */
1725 if (!(valid_hooks & (1 << i)))
1727 if (info->hook_entry[i] == 0xFFFFFFFF) {
1728 duprintf("Invalid hook entry %u %u\n",
1729 i, hook_entries[i]);
1732 if (info->underflow[i] == 0xFFFFFFFF) {
1733 duprintf("Invalid underflow %u %u\n",
1740 newinfo = xt_alloc_table_info(size);
1744 newinfo->number = number;
1745 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1746 newinfo->hook_entry[i] = info->hook_entry[i];
1747 newinfo->underflow[i] = info->underflow[i];
1749 entry1 = newinfo->entries[raw_smp_processor_id()];
1752 xt_entry_foreach(iter0, entry0, total_size) {
1753 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1754 name, newinfo, entry1);
1758 xt_compat_flush_offsets(AF_INET6);
1759 xt_compat_unlock(AF_INET6);
1764 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1768 xt_entry_foreach(iter1, entry1, newinfo->size) {
1769 ret = compat_check_entry(iter1, net, name);
1776 * The first i matches need cleanup_entry (calls ->destroy)
1777 * because they had called ->check already. The other j-i
1778 * entries need only release.
1782 xt_entry_foreach(iter0, entry0, newinfo->size) {
1787 compat_release_entry(iter0);
1789 xt_entry_foreach(iter1, entry1, newinfo->size) {
1792 cleanup_entry(iter1, net);
1794 xt_free_table_info(newinfo);
1798 /* And one copy for every other CPU */
1799 for_each_possible_cpu(i)
1800 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1801 memcpy(newinfo->entries[i], entry1, newinfo->size);
1805 xt_free_table_info(info);
1809 xt_free_table_info(newinfo);
1811 xt_entry_foreach(iter0, entry0, total_size) {
1814 compat_release_entry(iter0);
1818 xt_compat_flush_offsets(AF_INET6);
1819 xt_compat_unlock(AF_INET6);
1824 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1827 struct compat_ip6t_replace tmp;
1828 struct xt_table_info *newinfo;
1829 void *loc_cpu_entry;
1830 struct ip6t_entry *iter;
1832 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1835 /* overflow check */
1836 if (tmp.size >= INT_MAX / num_possible_cpus())
1838 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1841 newinfo = xt_alloc_table_info(tmp.size);
1845 /* choose the copy that is on our node/cpu */
1846 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1847 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1853 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1854 &newinfo, &loc_cpu_entry, tmp.size,
1855 tmp.num_entries, tmp.hook_entry,
1860 duprintf("compat_do_replace: Translated table\n");
1862 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1863 tmp.num_counters, compat_ptr(tmp.counters));
1865 goto free_newinfo_untrans;
1868 free_newinfo_untrans:
1869 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1870 cleanup_entry(iter, net);
1872 xt_free_table_info(newinfo);
1877 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1882 if (!capable(CAP_NET_ADMIN))
1886 case IP6T_SO_SET_REPLACE:
1887 ret = compat_do_replace(sock_net(sk), user, len);
1890 case IP6T_SO_SET_ADD_COUNTERS:
1891 ret = do_add_counters(sock_net(sk), user, len, 1);
1895 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1902 struct compat_ip6t_get_entries {
1903 char name[IP6T_TABLE_MAXNAMELEN];
1905 struct compat_ip6t_entry entrytable[0];
1909 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1910 void __user *userptr)
1912 struct xt_counters *counters;
1913 const struct xt_table_info *private = table->private;
1917 const void *loc_cpu_entry;
1919 struct ip6t_entry *iter;
1921 counters = alloc_counters(table);
1922 if (IS_ERR(counters))
1923 return PTR_ERR(counters);
1925 /* choose the copy that is on our node/cpu, ...
1926 * This choice is lazy (because current thread is
1927 * allowed to migrate to another cpu)
1929 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1932 xt_entry_foreach(iter, loc_cpu_entry, total_size) {
1933 ret = compat_copy_entry_to_user(iter, &pos,
1934 &size, counters, i++);
1944 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1948 struct compat_ip6t_get_entries get;
1951 if (*len < sizeof(get)) {
1952 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1956 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1959 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1960 duprintf("compat_get_entries: %u != %zu\n",
1961 *len, sizeof(get) + get.size);
1965 xt_compat_lock(AF_INET6);
1966 t = xt_find_table_lock(net, AF_INET6, get.name);
1967 if (t && !IS_ERR(t)) {
1968 const struct xt_table_info *private = t->private;
1969 struct xt_table_info info;
1970 duprintf("t->private->number = %u\n", private->number);
1971 ret = compat_table_info(private, &info);
1972 if (!ret && get.size == info.size) {
1973 ret = compat_copy_entries_to_user(private->size,
1974 t, uptr->entrytable);
1976 duprintf("compat_get_entries: I've got %u not %u!\n",
1977 private->size, get.size);
1980 xt_compat_flush_offsets(AF_INET6);
1984 ret = t ? PTR_ERR(t) : -ENOENT;
1986 xt_compat_unlock(AF_INET6);
1990 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1993 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1997 if (!capable(CAP_NET_ADMIN))
2001 case IP6T_SO_GET_INFO:
2002 ret = get_info(sock_net(sk), user, len, 1);
2004 case IP6T_SO_GET_ENTRIES:
2005 ret = compat_get_entries(sock_net(sk), user, len);
2008 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2015 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2019 if (!capable(CAP_NET_ADMIN))
2023 case IP6T_SO_SET_REPLACE:
2024 ret = do_replace(sock_net(sk), user, len);
2027 case IP6T_SO_SET_ADD_COUNTERS:
2028 ret = do_add_counters(sock_net(sk), user, len, 0);
2032 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2040 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2044 if (!capable(CAP_NET_ADMIN))
2048 case IP6T_SO_GET_INFO:
2049 ret = get_info(sock_net(sk), user, len, 0);
2052 case IP6T_SO_GET_ENTRIES:
2053 ret = get_entries(sock_net(sk), user, len);
2056 case IP6T_SO_GET_REVISION_MATCH:
2057 case IP6T_SO_GET_REVISION_TARGET: {
2058 struct ip6t_get_revision rev;
2061 if (*len != sizeof(rev)) {
2065 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2070 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2075 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2078 "ip6t_%s", rev.name);
2083 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2090 struct xt_table *ip6t_register_table(struct net *net,
2091 const struct xt_table *table,
2092 const struct ip6t_replace *repl)
2095 struct xt_table_info *newinfo;
2096 struct xt_table_info bootstrap = {0};
2097 void *loc_cpu_entry;
2098 struct xt_table *new_table;
2100 newinfo = xt_alloc_table_info(repl->size);
2106 /* choose the copy on our node/cpu, but dont care about preemption */
2107 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2108 memcpy(loc_cpu_entry, repl->entries, repl->size);
2110 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2114 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2115 if (IS_ERR(new_table)) {
2116 ret = PTR_ERR(new_table);
2122 xt_free_table_info(newinfo);
2124 return ERR_PTR(ret);
2127 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2129 struct xt_table_info *private;
2130 void *loc_cpu_entry;
2131 struct module *table_owner = table->me;
2132 struct ip6t_entry *iter;
2134 private = xt_unregister_table(table);
2136 /* Decrease module usage counts and free resources */
2137 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2138 xt_entry_foreach(iter, loc_cpu_entry, private->size)
2139 cleanup_entry(iter, net);
2140 if (private->number > private->initial_entries)
2141 module_put(table_owner);
2142 xt_free_table_info(private);
2145 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2147 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2148 u_int8_t type, u_int8_t code,
2151 return (type == test_type && code >= min_code && code <= max_code)
2156 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2158 const struct icmp6hdr *ic;
2159 struct icmp6hdr _icmph;
2160 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2162 /* Must not be a fragment. */
2163 if (par->fragoff != 0)
2166 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2168 /* We've been asked to examine this packet, and we
2169 * can't. Hence, no choice but to drop.
2171 duprintf("Dropping evil ICMP tinygram.\n");
2172 par->hotdrop = true;
2176 return icmp6_type_code_match(icmpinfo->type,
2179 ic->icmp6_type, ic->icmp6_code,
2180 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2183 /* Called when user tries to insert an entry of this type. */
2184 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2186 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2188 /* Must specify no unknown invflags */
2189 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2192 /* The built-in targets: standard (NULL) and error. */
2193 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2195 .name = IP6T_STANDARD_TARGET,
2196 .targetsize = sizeof(int),
2197 .family = NFPROTO_IPV6,
2198 #ifdef CONFIG_COMPAT
2199 .compatsize = sizeof(compat_int_t),
2200 .compat_from_user = compat_standard_from_user,
2201 .compat_to_user = compat_standard_to_user,
2205 .name = IP6T_ERROR_TARGET,
2206 .target = ip6t_error,
2207 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
2208 .family = NFPROTO_IPV6,
2212 static struct nf_sockopt_ops ip6t_sockopts = {
2214 .set_optmin = IP6T_BASE_CTL,
2215 .set_optmax = IP6T_SO_SET_MAX+1,
2216 .set = do_ip6t_set_ctl,
2217 #ifdef CONFIG_COMPAT
2218 .compat_set = compat_do_ip6t_set_ctl,
2220 .get_optmin = IP6T_BASE_CTL,
2221 .get_optmax = IP6T_SO_GET_MAX+1,
2222 .get = do_ip6t_get_ctl,
2223 #ifdef CONFIG_COMPAT
2224 .compat_get = compat_do_ip6t_get_ctl,
2226 .owner = THIS_MODULE,
2229 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2232 .match = icmp6_match,
2233 .matchsize = sizeof(struct ip6t_icmp),
2234 .checkentry = icmp6_checkentry,
2235 .proto = IPPROTO_ICMPV6,
2236 .family = NFPROTO_IPV6,
2240 static int __net_init ip6_tables_net_init(struct net *net)
2242 return xt_proto_init(net, NFPROTO_IPV6);
2245 static void __net_exit ip6_tables_net_exit(struct net *net)
2247 xt_proto_fini(net, NFPROTO_IPV6);
2250 static struct pernet_operations ip6_tables_net_ops = {
2251 .init = ip6_tables_net_init,
2252 .exit = ip6_tables_net_exit,
2255 static int __init ip6_tables_init(void)
2259 ret = register_pernet_subsys(&ip6_tables_net_ops);
2263 /* Noone else will be downing sem now, so we won't sleep */
2264 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2267 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2271 /* Register setsockopt */
2272 ret = nf_register_sockopt(&ip6t_sockopts);
2276 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2280 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2282 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2284 unregister_pernet_subsys(&ip6_tables_net_ops);
2289 static void __exit ip6_tables_fini(void)
2291 nf_unregister_sockopt(&ip6t_sockopts);
2293 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2294 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2295 unregister_pernet_subsys(&ip6_tables_net_ops);
2299 * find the offset to specified header or the protocol number of last header
2300 * if target < 0. "last header" is transport protocol header, ESP, or
2303 * If target header is found, its offset is set in *offset and return protocol
2304 * number. Otherwise, return -1.
2306 * If the first fragment doesn't contain the final protocol header or
2307 * NEXTHDR_NONE it is considered invalid.
2309 * Note that non-1st fragment is special case that "the protocol number
2310 * of last header" is "next header" field in Fragment header. In this case,
2311 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2315 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2316 int target, unsigned short *fragoff)
2318 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2319 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2320 unsigned int len = skb->len - start;
2325 while (nexthdr != target) {
2326 struct ipv6_opt_hdr _hdr, *hp;
2327 unsigned int hdrlen;
2329 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2335 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2338 if (nexthdr == NEXTHDR_FRAGMENT) {
2339 unsigned short _frag_off;
2341 fp = skb_header_pointer(skb,
2342 start+offsetof(struct frag_hdr,
2349 _frag_off = ntohs(*fp) & ~0x7;
2352 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2353 hp->nexthdr == NEXTHDR_NONE)) {
2355 *fragoff = _frag_off;
2361 } else if (nexthdr == NEXTHDR_AUTH)
2362 hdrlen = (hp->hdrlen + 2) << 2;
2364 hdrlen = ipv6_optlen(hp);
2366 nexthdr = hp->nexthdr;
2375 EXPORT_SYMBOL(ip6t_register_table);
2376 EXPORT_SYMBOL(ip6t_unregister_table);
2377 EXPORT_SYMBOL(ip6t_do_table);
2378 EXPORT_SYMBOL(ip6t_ext_hdr);
2379 EXPORT_SYMBOL(ipv6_find_hdr);
2381 module_init(ip6_tables_init);
2382 module_exit(ip6_tables_fini);