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>
6 * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/kernel.h>
16 #include <linux/capability.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/poison.h>
24 #include <linux/icmpv6.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter_ipv6/ip6_tables.h>
34 #include <linux/netfilter/x_tables.h>
35 #include <net/netfilter/nf_log.h>
36 #include "../../netfilter/xt_repldata.h"
38 MODULE_LICENSE("GPL");
39 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
40 MODULE_DESCRIPTION("IPv6 packet filter");
42 /*#define DEBUG_IP_FIREWALL*/
43 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44 /*#define DEBUG_IP_FIREWALL_USER*/
46 #ifdef DEBUG_IP_FIREWALL
47 #define dprintf(format, args...) pr_info(format , ## args)
49 #define dprintf(format, args...)
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) pr_info(format , ## args)
55 #define duprintf(format, args...)
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x) WARN_ON(!(x))
61 #define IP_NF_ASSERT(x)
65 /* All the better to debug you with... */
70 void *ip6t_alloc_initial_table(const struct xt_table *info)
72 return xt_alloc_initial_table(ip6t, IP6T);
74 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
77 We keep a set of rules for each CPU, so we can avoid write-locking
78 them in the softirq when updating the counters and therefore
79 only need to read-lock in the softirq; doing a write_lock_bh() in user
80 context stops packets coming through and allows user context to read
81 the counters or update the rules.
83 Hence the start of any table is given by get_table() below. */
85 /* Returns whether matches rule or not. */
86 /* Performance critical - called for every packet */
88 ip6_packet_match(const struct sk_buff *skb,
91 const struct ip6t_ip6 *ip6info,
92 unsigned int *protoff,
93 int *fragoff, bool *hotdrop)
96 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
98 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
100 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
101 &ip6info->src), IP6T_INV_SRCIP) ||
102 FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
103 &ip6info->dst), IP6T_INV_DSTIP)) {
104 dprintf("Source or dest mismatch.\n");
106 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
107 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
108 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
109 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
110 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
111 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
115 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
117 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
118 dprintf("VIA in mismatch (%s vs %s).%s\n",
119 indev, ip6info->iniface,
120 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
124 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
126 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
127 dprintf("VIA out mismatch (%s vs %s).%s\n",
128 outdev, ip6info->outiface,
129 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
133 /* ... might want to do something with class and flowlabel here ... */
135 /* look for the desired protocol header */
136 if((ip6info->flags & IP6T_F_PROTO)) {
138 unsigned short _frag_off;
140 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
146 *fragoff = _frag_off;
148 dprintf("Packet protocol %hi ?= %s%hi.\n",
150 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
153 if (ip6info->proto == protohdr) {
154 if(ip6info->invflags & IP6T_INV_PROTO) {
160 /* We need match for the '-p all', too! */
161 if ((ip6info->proto != 0) &&
162 !(ip6info->invflags & IP6T_INV_PROTO))
168 /* should be ip6 safe */
170 ip6_checkentry(const struct ip6t_ip6 *ipv6)
172 if (ipv6->flags & ~IP6T_F_MASK) {
173 duprintf("Unknown flag bits set: %08X\n",
174 ipv6->flags & ~IP6T_F_MASK);
177 if (ipv6->invflags & ~IP6T_INV_MASK) {
178 duprintf("Unknown invflag bits set: %08X\n",
179 ipv6->invflags & ~IP6T_INV_MASK);
186 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
188 net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo);
193 static inline struct ip6t_entry *
194 get_entry(const void *base, unsigned int offset)
196 return (struct ip6t_entry *)(base + offset);
199 /* All zeroes == unconditional rule. */
200 /* Mildly perf critical (only if packet tracing is on) */
201 static inline bool unconditional(const struct ip6t_ip6 *ipv6)
203 static const struct ip6t_ip6 uncond;
205 return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
208 static inline const struct xt_entry_target *
209 ip6t_get_target_c(const struct ip6t_entry *e)
211 return ip6t_get_target((struct ip6t_entry *)e);
214 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
215 /* This cries for unification! */
216 static const char *const hooknames[] = {
217 [NF_INET_PRE_ROUTING] = "PREROUTING",
218 [NF_INET_LOCAL_IN] = "INPUT",
219 [NF_INET_FORWARD] = "FORWARD",
220 [NF_INET_LOCAL_OUT] = "OUTPUT",
221 [NF_INET_POST_ROUTING] = "POSTROUTING",
224 enum nf_ip_trace_comments {
225 NF_IP6_TRACE_COMMENT_RULE,
226 NF_IP6_TRACE_COMMENT_RETURN,
227 NF_IP6_TRACE_COMMENT_POLICY,
230 static const char *const comments[] = {
231 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
232 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
233 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
236 static struct nf_loginfo trace_loginfo = {
237 .type = NF_LOG_TYPE_LOG,
240 .level = LOGLEVEL_WARNING,
241 .logflags = NF_LOG_MASK,
246 /* Mildly perf critical (only if packet tracing is on) */
248 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
249 const char *hookname, const char **chainname,
250 const char **comment, unsigned int *rulenum)
252 const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
254 if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
255 /* Head of user chain: ERROR target with chainname */
256 *chainname = t->target.data;
261 if (s->target_offset == sizeof(struct ip6t_entry) &&
262 strcmp(t->target.u.kernel.target->name,
263 XT_STANDARD_TARGET) == 0 &&
265 unconditional(&s->ipv6)) {
266 /* Tail of chains: STANDARD target (return/policy) */
267 *comment = *chainname == hookname
268 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
269 : comments[NF_IP6_TRACE_COMMENT_RETURN];
278 static void trace_packet(const struct sk_buff *skb,
280 const struct net_device *in,
281 const struct net_device *out,
282 const char *tablename,
283 const struct xt_table_info *private,
284 const struct ip6t_entry *e)
286 const struct ip6t_entry *root;
287 const char *hookname, *chainname, *comment;
288 const struct ip6t_entry *iter;
289 unsigned int rulenum = 0;
290 struct net *net = dev_net(in ? in : out);
292 root = get_entry(private->entries, private->hook_entry[hook]);
294 hookname = chainname = hooknames[hook];
295 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
297 xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
298 if (get_chainname_rulenum(iter, e, hookname,
299 &chainname, &comment, &rulenum) != 0)
302 nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
303 "TRACE: %s:%s:%s:%u ",
304 tablename, chainname, comment, rulenum);
308 static inline __pure struct ip6t_entry *
309 ip6t_next_entry(const struct ip6t_entry *entry)
311 return (void *)entry + entry->next_offset;
314 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
316 ip6t_do_table(struct sk_buff *skb,
318 const struct nf_hook_state *state,
319 struct xt_table *table)
321 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
322 /* Initializing verdict to NF_DROP keeps gcc happy. */
323 unsigned int verdict = NF_DROP;
324 const char *indev, *outdev;
325 const void *table_base;
326 struct ip6t_entry *e, **jumpstack;
327 unsigned int stackidx, cpu;
328 const struct xt_table_info *private;
329 struct xt_action_param acpar;
334 indev = state->in ? state->in->name : nulldevname;
335 outdev = state->out ? state->out->name : nulldevname;
336 /* We handle fragments by dealing with the first fragment as
337 * if it was a normal packet. All other fragments are treated
338 * normally, except that they will NEVER match rules that ask
339 * things we don't know, ie. tcp syn flag or ports). If the
340 * rule is also a fragment-specific rule, non-fragments won't
342 acpar.hotdrop = false;
343 acpar.in = state->in;
344 acpar.out = state->out;
345 acpar.family = NFPROTO_IPV6;
346 acpar.hooknum = hook;
348 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
351 addend = xt_write_recseq_begin();
352 private = table->private;
354 * Ensure we load private-> members after we've fetched the base
357 smp_read_barrier_depends();
358 cpu = smp_processor_id();
359 table_base = private->entries;
360 jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
362 /* Switch to alternate jumpstack if we're being invoked via TEE.
363 * TEE issues XT_CONTINUE verdict on original skb so we must not
364 * clobber the jumpstack.
366 * For recursion via REJECT or SYNPROXY the stack will be clobbered
367 * but it is no problem since absolute verdict is issued by these.
369 if (static_key_false(&xt_tee_enabled))
370 jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
372 e = get_entry(table_base, private->hook_entry[hook]);
375 const struct xt_entry_target *t;
376 const struct xt_entry_match *ematch;
377 struct xt_counters *counter;
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 counter = xt_get_this_cpu_counter(&e->counters);
396 ADD_COUNTER(*counter, skb->len, 1);
398 t = ip6t_get_target_c(e);
399 IP_NF_ASSERT(t->u.kernel.target);
401 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
402 /* The packet is traced: log it */
403 if (unlikely(skb->nf_trace))
404 trace_packet(skb, hook, state->in, state->out,
405 table->name, private, e);
407 /* Standard target? */
408 if (!t->u.kernel.target->target) {
411 v = ((struct xt_standard_target *)t)->verdict;
413 /* Pop from stack? */
414 if (v != XT_RETURN) {
415 verdict = (unsigned int)(-v) - 1;
419 e = get_entry(table_base,
420 private->underflow[hook]);
422 e = ip6t_next_entry(jumpstack[--stackidx]);
425 if (table_base + v != ip6t_next_entry(e) &&
426 !(e->ipv6.flags & IP6T_F_GOTO)) {
427 jumpstack[stackidx++] = e;
430 e = get_entry(table_base, v);
434 acpar.target = t->u.kernel.target;
435 acpar.targinfo = t->data;
437 verdict = t->u.kernel.target->target(skb, &acpar);
438 if (verdict == XT_CONTINUE)
439 e = ip6t_next_entry(e);
443 } while (!acpar.hotdrop);
445 xt_write_recseq_end(addend);
448 #ifdef DEBUG_ALLOW_ALL
457 /* Figures out from what hook each rule can be called: returns 0 if
458 * there are loops. Puts hook bitmask in comefrom.
460 * Keeps track of largest call depth seen and stores it in newinfo->stacksize.
463 mark_source_chains(struct xt_table_info *newinfo,
464 unsigned int valid_hooks, void *entry0)
466 unsigned int calldepth, max_calldepth = 0;
469 /* No recursion; use packet counter to save back ptrs (reset
470 to 0 as we leave), and comefrom to save source hook bitmask */
471 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
472 unsigned int pos = newinfo->hook_entry[hook];
473 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
475 if (!(valid_hooks & (1 << hook)))
478 /* Set initial back pointer. */
479 e->counters.pcnt = pos;
483 const struct xt_standard_target *t
484 = (void *)ip6t_get_target_c(e);
485 int visited = e->comefrom & (1 << hook);
487 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
488 pr_err("iptables: loop hook %u pos %u %08X.\n",
489 hook, pos, e->comefrom);
492 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
494 /* Unconditional return/END. */
495 if ((e->target_offset == sizeof(struct ip6t_entry) &&
496 (strcmp(t->target.u.user.name,
497 XT_STANDARD_TARGET) == 0) &&
499 unconditional(&e->ipv6)) || visited) {
500 unsigned int oldpos, size;
502 if ((strcmp(t->target.u.user.name,
503 XT_STANDARD_TARGET) == 0) &&
504 t->verdict < -NF_MAX_VERDICT - 1) {
505 duprintf("mark_source_chains: bad "
506 "negative verdict (%i)\n",
511 /* Return: backtrack through the last
514 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
515 #ifdef DEBUG_IP_FIREWALL_USER
517 & (1 << NF_INET_NUMHOOKS)) {
518 duprintf("Back unset "
525 pos = e->counters.pcnt;
526 e->counters.pcnt = 0;
528 /* We're at the start. */
532 e = (struct ip6t_entry *)
534 } while (oldpos == pos + e->next_offset);
537 size = e->next_offset;
538 e = (struct ip6t_entry *)
539 (entry0 + pos + size);
540 e->counters.pcnt = pos;
545 int newpos = t->verdict;
547 if (strcmp(t->target.u.user.name,
548 XT_STANDARD_TARGET) == 0 &&
550 if (newpos > newinfo->size -
551 sizeof(struct ip6t_entry)) {
552 duprintf("mark_source_chains: "
553 "bad verdict (%i)\n",
557 if (entry0 + newpos != ip6t_next_entry(e) &&
558 !(e->ipv6.flags & IP6T_F_GOTO) &&
559 ++calldepth > max_calldepth)
560 max_calldepth = calldepth;
562 /* This a jump; chase it. */
563 duprintf("Jump rule %u -> %u\n",
566 /* ... this is a fallthru */
567 newpos = pos + e->next_offset;
569 e = (struct ip6t_entry *)
571 e->counters.pcnt = pos;
576 duprintf("Finished chain %u\n", hook);
578 newinfo->stacksize = max_calldepth;
582 static void cleanup_match(struct xt_entry_match *m, struct net *net)
584 struct xt_mtdtor_param par;
587 par.match = m->u.kernel.match;
588 par.matchinfo = m->data;
589 par.family = NFPROTO_IPV6;
590 if (par.match->destroy != NULL)
591 par.match->destroy(&par);
592 module_put(par.match->me);
596 check_entry(const struct ip6t_entry *e, const char *name)
598 const struct xt_entry_target *t;
600 if (!ip6_checkentry(&e->ipv6)) {
601 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
605 if (e->target_offset + sizeof(struct xt_entry_target) >
609 t = ip6t_get_target_c(e);
610 if (e->target_offset + t->u.target_size > e->next_offset)
616 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
618 const struct ip6t_ip6 *ipv6 = par->entryinfo;
621 par->match = m->u.kernel.match;
622 par->matchinfo = m->data;
624 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
625 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
627 duprintf("ip_tables: check failed for `%s'.\n",
635 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
637 struct xt_match *match;
640 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
643 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
644 return PTR_ERR(match);
646 m->u.kernel.match = match;
648 ret = check_match(m, par);
654 module_put(m->u.kernel.match->me);
658 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
660 struct xt_entry_target *t = ip6t_get_target(e);
661 struct xt_tgchk_param par = {
665 .target = t->u.kernel.target,
667 .hook_mask = e->comefrom,
668 .family = NFPROTO_IPV6,
672 t = ip6t_get_target(e);
673 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
674 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
676 duprintf("ip_tables: check failed for `%s'.\n",
677 t->u.kernel.target->name);
684 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
687 struct xt_entry_target *t;
688 struct xt_target *target;
691 struct xt_mtchk_param mtpar;
692 struct xt_entry_match *ematch;
694 ret = check_entry(e, name);
698 e->counters.pcnt = xt_percpu_counter_alloc();
699 if (IS_ERR_VALUE(e->counters.pcnt))
705 mtpar.entryinfo = &e->ipv6;
706 mtpar.hook_mask = e->comefrom;
707 mtpar.family = NFPROTO_IPV6;
708 xt_ematch_foreach(ematch, e) {
709 ret = find_check_match(ematch, &mtpar);
711 goto cleanup_matches;
715 t = ip6t_get_target(e);
716 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
718 if (IS_ERR(target)) {
719 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
720 ret = PTR_ERR(target);
721 goto cleanup_matches;
723 t->u.kernel.target = target;
725 ret = check_target(e, net, name);
730 module_put(t->u.kernel.target->me);
732 xt_ematch_foreach(ematch, e) {
735 cleanup_match(ematch, net);
738 xt_percpu_counter_free(e->counters.pcnt);
743 static bool check_underflow(const struct ip6t_entry *e)
745 const struct xt_entry_target *t;
746 unsigned int verdict;
748 if (!unconditional(&e->ipv6))
750 t = ip6t_get_target_c(e);
751 if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
753 verdict = ((struct xt_standard_target *)t)->verdict;
754 verdict = -verdict - 1;
755 return verdict == NF_DROP || verdict == NF_ACCEPT;
759 check_entry_size_and_hooks(struct ip6t_entry *e,
760 struct xt_table_info *newinfo,
761 const unsigned char *base,
762 const unsigned char *limit,
763 const unsigned int *hook_entries,
764 const unsigned int *underflows,
765 unsigned int valid_hooks)
769 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
770 (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
771 duprintf("Bad offset %p\n", e);
776 < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
777 duprintf("checking: element %p size %u\n",
782 /* Check hooks & underflows */
783 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
784 if (!(valid_hooks & (1 << h)))
786 if ((unsigned char *)e - base == hook_entries[h])
787 newinfo->hook_entry[h] = hook_entries[h];
788 if ((unsigned char *)e - base == underflows[h]) {
789 if (!check_underflow(e)) {
790 pr_err("Underflows must be unconditional and "
791 "use the STANDARD target with "
795 newinfo->underflow[h] = underflows[h];
799 /* Clear counters and comefrom */
800 e->counters = ((struct xt_counters) { 0, 0 });
805 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
807 struct xt_tgdtor_param par;
808 struct xt_entry_target *t;
809 struct xt_entry_match *ematch;
811 /* Cleanup all matches */
812 xt_ematch_foreach(ematch, e)
813 cleanup_match(ematch, net);
814 t = ip6t_get_target(e);
817 par.target = t->u.kernel.target;
818 par.targinfo = t->data;
819 par.family = NFPROTO_IPV6;
820 if (par.target->destroy != NULL)
821 par.target->destroy(&par);
822 module_put(par.target->me);
824 xt_percpu_counter_free(e->counters.pcnt);
827 /* Checks and translates the user-supplied table segment (held in
830 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
831 const struct ip6t_replace *repl)
833 struct ip6t_entry *iter;
837 newinfo->size = repl->size;
838 newinfo->number = repl->num_entries;
840 /* Init all hooks to impossible value. */
841 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
842 newinfo->hook_entry[i] = 0xFFFFFFFF;
843 newinfo->underflow[i] = 0xFFFFFFFF;
846 duprintf("translate_table: size %u\n", newinfo->size);
848 /* Walk through entries, checking offsets. */
849 xt_entry_foreach(iter, entry0, newinfo->size) {
850 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
860 if (i != repl->num_entries) {
861 duprintf("translate_table: %u not %u entries\n",
862 i, repl->num_entries);
866 /* Check hooks all assigned */
867 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
868 /* Only hooks which are valid */
869 if (!(repl->valid_hooks & (1 << i)))
871 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
872 duprintf("Invalid hook entry %u %u\n",
873 i, repl->hook_entry[i]);
876 if (newinfo->underflow[i] == 0xFFFFFFFF) {
877 duprintf("Invalid underflow %u %u\n",
878 i, repl->underflow[i]);
883 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
886 /* Finally, each sanity check must pass */
888 xt_entry_foreach(iter, entry0, newinfo->size) {
889 ret = find_check_entry(iter, net, repl->name, repl->size);
896 xt_entry_foreach(iter, entry0, newinfo->size) {
899 cleanup_entry(iter, net);
908 get_counters(const struct xt_table_info *t,
909 struct xt_counters counters[])
911 struct ip6t_entry *iter;
915 for_each_possible_cpu(cpu) {
916 seqcount_t *s = &per_cpu(xt_recseq, cpu);
919 xt_entry_foreach(iter, t->entries, t->size) {
920 struct xt_counters *tmp;
924 tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
926 start = read_seqcount_begin(s);
929 } while (read_seqcount_retry(s, start));
931 ADD_COUNTER(counters[i], bcnt, pcnt);
937 static struct xt_counters *alloc_counters(const struct xt_table *table)
939 unsigned int countersize;
940 struct xt_counters *counters;
941 const struct xt_table_info *private = table->private;
943 /* We need atomic snapshot of counters: rest doesn't change
944 (other than comefrom, which userspace doesn't care
946 countersize = sizeof(struct xt_counters) * private->number;
947 counters = vzalloc(countersize);
949 if (counters == NULL)
950 return ERR_PTR(-ENOMEM);
952 get_counters(private, counters);
958 copy_entries_to_user(unsigned int total_size,
959 const struct xt_table *table,
960 void __user *userptr)
962 unsigned int off, num;
963 const struct ip6t_entry *e;
964 struct xt_counters *counters;
965 const struct xt_table_info *private = table->private;
967 const void *loc_cpu_entry;
969 counters = alloc_counters(table);
970 if (IS_ERR(counters))
971 return PTR_ERR(counters);
973 loc_cpu_entry = private->entries;
974 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
979 /* FIXME: use iterator macros --RR */
980 /* ... then go back and fix counters and names */
981 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
983 const struct xt_entry_match *m;
984 const struct xt_entry_target *t;
986 e = (struct ip6t_entry *)(loc_cpu_entry + off);
987 if (copy_to_user(userptr + off
988 + offsetof(struct ip6t_entry, counters),
990 sizeof(counters[num])) != 0) {
995 for (i = sizeof(struct ip6t_entry);
996 i < e->target_offset;
997 i += m->u.match_size) {
1000 if (copy_to_user(userptr + off + i
1001 + offsetof(struct xt_entry_match,
1003 m->u.kernel.match->name,
1004 strlen(m->u.kernel.match->name)+1)
1011 t = ip6t_get_target_c(e);
1012 if (copy_to_user(userptr + off + e->target_offset
1013 + offsetof(struct xt_entry_target,
1015 t->u.kernel.target->name,
1016 strlen(t->u.kernel.target->name)+1) != 0) {
1027 #ifdef CONFIG_COMPAT
1028 static void compat_standard_from_user(void *dst, const void *src)
1030 int v = *(compat_int_t *)src;
1033 v += xt_compat_calc_jump(AF_INET6, v);
1034 memcpy(dst, &v, sizeof(v));
1037 static int compat_standard_to_user(void __user *dst, const void *src)
1039 compat_int_t cv = *(int *)src;
1042 cv -= xt_compat_calc_jump(AF_INET6, cv);
1043 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1046 static int compat_calc_entry(const struct ip6t_entry *e,
1047 const struct xt_table_info *info,
1048 const void *base, struct xt_table_info *newinfo)
1050 const struct xt_entry_match *ematch;
1051 const struct xt_entry_target *t;
1052 unsigned int entry_offset;
1055 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1056 entry_offset = (void *)e - base;
1057 xt_ematch_foreach(ematch, e)
1058 off += xt_compat_match_offset(ematch->u.kernel.match);
1059 t = ip6t_get_target_c(e);
1060 off += xt_compat_target_offset(t->u.kernel.target);
1061 newinfo->size -= off;
1062 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1066 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1067 if (info->hook_entry[i] &&
1068 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1069 newinfo->hook_entry[i] -= off;
1070 if (info->underflow[i] &&
1071 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1072 newinfo->underflow[i] -= off;
1077 static int compat_table_info(const struct xt_table_info *info,
1078 struct xt_table_info *newinfo)
1080 struct ip6t_entry *iter;
1081 const void *loc_cpu_entry;
1084 if (!newinfo || !info)
1087 /* we dont care about newinfo->entries */
1088 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1089 newinfo->initial_entries = 0;
1090 loc_cpu_entry = info->entries;
1091 xt_compat_init_offsets(AF_INET6, info->number);
1092 xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1093 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1101 static int get_info(struct net *net, void __user *user,
1102 const int *len, int compat)
1104 char name[XT_TABLE_MAXNAMELEN];
1108 if (*len != sizeof(struct ip6t_getinfo)) {
1109 duprintf("length %u != %zu\n", *len,
1110 sizeof(struct ip6t_getinfo));
1114 if (copy_from_user(name, user, sizeof(name)) != 0)
1117 name[XT_TABLE_MAXNAMELEN-1] = '\0';
1118 #ifdef CONFIG_COMPAT
1120 xt_compat_lock(AF_INET6);
1122 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1123 "ip6table_%s", name);
1124 if (!IS_ERR_OR_NULL(t)) {
1125 struct ip6t_getinfo info;
1126 const struct xt_table_info *private = t->private;
1127 #ifdef CONFIG_COMPAT
1128 struct xt_table_info tmp;
1131 ret = compat_table_info(private, &tmp);
1132 xt_compat_flush_offsets(AF_INET6);
1136 memset(&info, 0, sizeof(info));
1137 info.valid_hooks = t->valid_hooks;
1138 memcpy(info.hook_entry, private->hook_entry,
1139 sizeof(info.hook_entry));
1140 memcpy(info.underflow, private->underflow,
1141 sizeof(info.underflow));
1142 info.num_entries = private->number;
1143 info.size = private->size;
1144 strcpy(info.name, name);
1146 if (copy_to_user(user, &info, *len) != 0)
1154 ret = t ? PTR_ERR(t) : -ENOENT;
1155 #ifdef CONFIG_COMPAT
1157 xt_compat_unlock(AF_INET6);
1163 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1167 struct ip6t_get_entries get;
1170 if (*len < sizeof(get)) {
1171 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1174 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1176 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1177 duprintf("get_entries: %u != %zu\n",
1178 *len, sizeof(get) + get.size);
1182 t = xt_find_table_lock(net, AF_INET6, get.name);
1183 if (!IS_ERR_OR_NULL(t)) {
1184 struct xt_table_info *private = t->private;
1185 duprintf("t->private->number = %u\n", private->number);
1186 if (get.size == private->size)
1187 ret = copy_entries_to_user(private->size,
1188 t, uptr->entrytable);
1190 duprintf("get_entries: I've got %u not %u!\n",
1191 private->size, get.size);
1197 ret = t ? PTR_ERR(t) : -ENOENT;
1203 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1204 struct xt_table_info *newinfo, unsigned int num_counters,
1205 void __user *counters_ptr)
1209 struct xt_table_info *oldinfo;
1210 struct xt_counters *counters;
1211 struct ip6t_entry *iter;
1214 counters = vzalloc(num_counters * sizeof(struct xt_counters));
1220 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1221 "ip6table_%s", name);
1222 if (IS_ERR_OR_NULL(t)) {
1223 ret = t ? PTR_ERR(t) : -ENOENT;
1224 goto free_newinfo_counters_untrans;
1228 if (valid_hooks != t->valid_hooks) {
1229 duprintf("Valid hook crap: %08X vs %08X\n",
1230 valid_hooks, t->valid_hooks);
1235 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1239 /* Update module usage count based on number of rules */
1240 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1241 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1242 if ((oldinfo->number > oldinfo->initial_entries) ||
1243 (newinfo->number <= oldinfo->initial_entries))
1245 if ((oldinfo->number > oldinfo->initial_entries) &&
1246 (newinfo->number <= oldinfo->initial_entries))
1249 /* Get the old counters, and synchronize with replace */
1250 get_counters(oldinfo, counters);
1252 /* Decrease module usage counts and free resource */
1253 xt_entry_foreach(iter, oldinfo->entries, oldinfo->size)
1254 cleanup_entry(iter, net);
1256 xt_free_table_info(oldinfo);
1257 if (copy_to_user(counters_ptr, counters,
1258 sizeof(struct xt_counters) * num_counters) != 0) {
1259 /* Silent error, can't fail, new table is already in place */
1260 net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
1269 free_newinfo_counters_untrans:
1276 do_replace(struct net *net, const void __user *user, unsigned int len)
1279 struct ip6t_replace tmp;
1280 struct xt_table_info *newinfo;
1281 void *loc_cpu_entry;
1282 struct ip6t_entry *iter;
1284 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1287 /* overflow check */
1288 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1290 if (tmp.num_counters == 0)
1293 tmp.name[sizeof(tmp.name)-1] = 0;
1295 newinfo = xt_alloc_table_info(tmp.size);
1299 loc_cpu_entry = newinfo->entries;
1300 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1306 ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1310 duprintf("ip_tables: Translated table\n");
1312 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1313 tmp.num_counters, tmp.counters);
1315 goto free_newinfo_untrans;
1318 free_newinfo_untrans:
1319 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1320 cleanup_entry(iter, net);
1322 xt_free_table_info(newinfo);
1327 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1331 struct xt_counters_info tmp;
1332 struct xt_counters *paddc;
1333 unsigned int num_counters;
1338 const struct xt_table_info *private;
1340 struct ip6t_entry *iter;
1341 unsigned int addend;
1342 #ifdef CONFIG_COMPAT
1343 struct compat_xt_counters_info compat_tmp;
1347 size = sizeof(struct compat_xt_counters_info);
1352 size = sizeof(struct xt_counters_info);
1355 if (copy_from_user(ptmp, user, size) != 0)
1358 #ifdef CONFIG_COMPAT
1360 num_counters = compat_tmp.num_counters;
1361 name = compat_tmp.name;
1365 num_counters = tmp.num_counters;
1369 if (len != size + num_counters * sizeof(struct xt_counters))
1372 paddc = vmalloc(len - size);
1376 if (copy_from_user(paddc, user + size, len - size) != 0) {
1381 t = xt_find_table_lock(net, AF_INET6, name);
1382 if (IS_ERR_OR_NULL(t)) {
1383 ret = t ? PTR_ERR(t) : -ENOENT;
1388 private = t->private;
1389 if (private->number != num_counters) {
1391 goto unlock_up_free;
1395 addend = xt_write_recseq_begin();
1396 xt_entry_foreach(iter, private->entries, private->size) {
1397 struct xt_counters *tmp;
1399 tmp = xt_get_this_cpu_counter(&iter->counters);
1400 ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1403 xt_write_recseq_end(addend);
1414 #ifdef CONFIG_COMPAT
1415 struct compat_ip6t_replace {
1416 char name[XT_TABLE_MAXNAMELEN];
1420 u32 hook_entry[NF_INET_NUMHOOKS];
1421 u32 underflow[NF_INET_NUMHOOKS];
1423 compat_uptr_t counters; /* struct xt_counters * */
1424 struct compat_ip6t_entry entries[0];
1428 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1429 unsigned int *size, struct xt_counters *counters,
1432 struct xt_entry_target *t;
1433 struct compat_ip6t_entry __user *ce;
1434 u_int16_t target_offset, next_offset;
1435 compat_uint_t origsize;
1436 const struct xt_entry_match *ematch;
1440 ce = (struct compat_ip6t_entry __user *)*dstptr;
1441 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1442 copy_to_user(&ce->counters, &counters[i],
1443 sizeof(counters[i])) != 0)
1446 *dstptr += sizeof(struct compat_ip6t_entry);
1447 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1449 xt_ematch_foreach(ematch, e) {
1450 ret = xt_compat_match_to_user(ematch, dstptr, size);
1454 target_offset = e->target_offset - (origsize - *size);
1455 t = ip6t_get_target(e);
1456 ret = xt_compat_target_to_user(t, dstptr, size);
1459 next_offset = e->next_offset - (origsize - *size);
1460 if (put_user(target_offset, &ce->target_offset) != 0 ||
1461 put_user(next_offset, &ce->next_offset) != 0)
1467 compat_find_calc_match(struct xt_entry_match *m,
1469 const struct ip6t_ip6 *ipv6,
1472 struct xt_match *match;
1474 match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1475 m->u.user.revision);
1476 if (IS_ERR(match)) {
1477 duprintf("compat_check_calc_match: `%s' not found\n",
1479 return PTR_ERR(match);
1481 m->u.kernel.match = match;
1482 *size += xt_compat_match_offset(match);
1486 static void compat_release_entry(struct compat_ip6t_entry *e)
1488 struct xt_entry_target *t;
1489 struct xt_entry_match *ematch;
1491 /* Cleanup all matches */
1492 xt_ematch_foreach(ematch, e)
1493 module_put(ematch->u.kernel.match->me);
1494 t = compat_ip6t_get_target(e);
1495 module_put(t->u.kernel.target->me);
1499 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1500 struct xt_table_info *newinfo,
1502 const unsigned char *base,
1503 const unsigned char *limit,
1504 const unsigned int *hook_entries,
1505 const unsigned int *underflows,
1508 struct xt_entry_match *ematch;
1509 struct xt_entry_target *t;
1510 struct xt_target *target;
1511 unsigned int entry_offset;
1515 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1516 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1517 (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1518 duprintf("Bad offset %p, limit = %p\n", e, limit);
1522 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1523 sizeof(struct compat_xt_entry_target)) {
1524 duprintf("checking: element %p size %u\n",
1529 /* For purposes of check_entry casting the compat entry is fine */
1530 ret = check_entry((struct ip6t_entry *)e, name);
1534 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1535 entry_offset = (void *)e - (void *)base;
1537 xt_ematch_foreach(ematch, e) {
1538 ret = compat_find_calc_match(ematch, name, &e->ipv6, &off);
1540 goto release_matches;
1544 t = compat_ip6t_get_target(e);
1545 target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1546 t->u.user.revision);
1547 if (IS_ERR(target)) {
1548 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1550 ret = PTR_ERR(target);
1551 goto release_matches;
1553 t->u.kernel.target = target;
1555 off += xt_compat_target_offset(target);
1557 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1561 /* Check hooks & underflows */
1562 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1563 if ((unsigned char *)e - base == hook_entries[h])
1564 newinfo->hook_entry[h] = hook_entries[h];
1565 if ((unsigned char *)e - base == underflows[h])
1566 newinfo->underflow[h] = underflows[h];
1569 /* Clear counters and comefrom */
1570 memset(&e->counters, 0, sizeof(e->counters));
1575 module_put(t->u.kernel.target->me);
1577 xt_ematch_foreach(ematch, e) {
1580 module_put(ematch->u.kernel.match->me);
1586 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1587 unsigned int *size, const char *name,
1588 struct xt_table_info *newinfo, unsigned char *base)
1590 struct xt_entry_target *t;
1591 struct ip6t_entry *de;
1592 unsigned int origsize;
1594 struct xt_entry_match *ematch;
1598 de = (struct ip6t_entry *)*dstptr;
1599 memcpy(de, e, sizeof(struct ip6t_entry));
1600 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1602 *dstptr += sizeof(struct ip6t_entry);
1603 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1605 xt_ematch_foreach(ematch, e) {
1606 ret = xt_compat_match_from_user(ematch, dstptr, size);
1610 de->target_offset = e->target_offset - (origsize - *size);
1611 t = compat_ip6t_get_target(e);
1612 xt_compat_target_from_user(t, dstptr, size);
1614 de->next_offset = e->next_offset - (origsize - *size);
1615 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1616 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1617 newinfo->hook_entry[h] -= origsize - *size;
1618 if ((unsigned char *)de - base < newinfo->underflow[h])
1619 newinfo->underflow[h] -= origsize - *size;
1624 static int compat_check_entry(struct ip6t_entry *e, struct net *net,
1629 struct xt_mtchk_param mtpar;
1630 struct xt_entry_match *ematch;
1632 e->counters.pcnt = xt_percpu_counter_alloc();
1633 if (IS_ERR_VALUE(e->counters.pcnt))
1638 mtpar.entryinfo = &e->ipv6;
1639 mtpar.hook_mask = e->comefrom;
1640 mtpar.family = NFPROTO_IPV6;
1641 xt_ematch_foreach(ematch, e) {
1642 ret = check_match(ematch, &mtpar);
1644 goto cleanup_matches;
1648 ret = check_target(e, net, name);
1650 goto cleanup_matches;
1654 xt_ematch_foreach(ematch, e) {
1657 cleanup_match(ematch, net);
1660 xt_percpu_counter_free(e->counters.pcnt);
1666 translate_compat_table(struct net *net,
1668 unsigned int valid_hooks,
1669 struct xt_table_info **pinfo,
1671 unsigned int total_size,
1672 unsigned int number,
1673 unsigned int *hook_entries,
1674 unsigned int *underflows)
1677 struct xt_table_info *newinfo, *info;
1678 void *pos, *entry0, *entry1;
1679 struct compat_ip6t_entry *iter0;
1680 struct ip6t_entry *iter1;
1687 info->number = number;
1689 /* Init all hooks to impossible value. */
1690 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1691 info->hook_entry[i] = 0xFFFFFFFF;
1692 info->underflow[i] = 0xFFFFFFFF;
1695 duprintf("translate_compat_table: size %u\n", info->size);
1697 xt_compat_lock(AF_INET6);
1698 xt_compat_init_offsets(AF_INET6, number);
1699 /* Walk through entries, checking offsets. */
1700 xt_entry_foreach(iter0, entry0, total_size) {
1701 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1703 entry0 + total_size,
1714 duprintf("translate_compat_table: %u not %u entries\n",
1719 /* Check hooks all assigned */
1720 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1721 /* Only hooks which are valid */
1722 if (!(valid_hooks & (1 << i)))
1724 if (info->hook_entry[i] == 0xFFFFFFFF) {
1725 duprintf("Invalid hook entry %u %u\n",
1726 i, hook_entries[i]);
1729 if (info->underflow[i] == 0xFFFFFFFF) {
1730 duprintf("Invalid underflow %u %u\n",
1737 newinfo = xt_alloc_table_info(size);
1741 newinfo->number = number;
1742 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1743 newinfo->hook_entry[i] = info->hook_entry[i];
1744 newinfo->underflow[i] = info->underflow[i];
1746 entry1 = newinfo->entries;
1749 xt_entry_foreach(iter0, entry0, total_size) {
1750 ret = compat_copy_entry_from_user(iter0, &pos, &size,
1751 name, newinfo, entry1);
1755 xt_compat_flush_offsets(AF_INET6);
1756 xt_compat_unlock(AF_INET6);
1761 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1765 xt_entry_foreach(iter1, entry1, newinfo->size) {
1766 ret = compat_check_entry(iter1, net, name);
1773 * The first i matches need cleanup_entry (calls ->destroy)
1774 * because they had called ->check already. The other j-i
1775 * entries need only release.
1779 xt_entry_foreach(iter0, entry0, newinfo->size) {
1784 compat_release_entry(iter0);
1786 xt_entry_foreach(iter1, entry1, newinfo->size) {
1789 cleanup_entry(iter1, net);
1791 xt_free_table_info(newinfo);
1797 xt_free_table_info(info);
1801 xt_free_table_info(newinfo);
1803 xt_entry_foreach(iter0, entry0, total_size) {
1806 compat_release_entry(iter0);
1810 xt_compat_flush_offsets(AF_INET6);
1811 xt_compat_unlock(AF_INET6);
1816 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1819 struct compat_ip6t_replace tmp;
1820 struct xt_table_info *newinfo;
1821 void *loc_cpu_entry;
1822 struct ip6t_entry *iter;
1824 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1827 /* overflow check */
1828 if (tmp.size >= INT_MAX / num_possible_cpus())
1830 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1832 if (tmp.num_counters == 0)
1835 tmp.name[sizeof(tmp.name)-1] = 0;
1837 newinfo = xt_alloc_table_info(tmp.size);
1841 loc_cpu_entry = newinfo->entries;
1842 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1848 ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
1849 &newinfo, &loc_cpu_entry, tmp.size,
1850 tmp.num_entries, tmp.hook_entry,
1855 duprintf("compat_do_replace: Translated table\n");
1857 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1858 tmp.num_counters, compat_ptr(tmp.counters));
1860 goto free_newinfo_untrans;
1863 free_newinfo_untrans:
1864 xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1865 cleanup_entry(iter, net);
1867 xt_free_table_info(newinfo);
1872 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1877 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1881 case IP6T_SO_SET_REPLACE:
1882 ret = compat_do_replace(sock_net(sk), user, len);
1885 case IP6T_SO_SET_ADD_COUNTERS:
1886 ret = do_add_counters(sock_net(sk), user, len, 1);
1890 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1897 struct compat_ip6t_get_entries {
1898 char name[XT_TABLE_MAXNAMELEN];
1900 struct compat_ip6t_entry entrytable[0];
1904 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1905 void __user *userptr)
1907 struct xt_counters *counters;
1908 const struct xt_table_info *private = table->private;
1913 struct ip6t_entry *iter;
1915 counters = alloc_counters(table);
1916 if (IS_ERR(counters))
1917 return PTR_ERR(counters);
1921 xt_entry_foreach(iter, private->entries, total_size) {
1922 ret = compat_copy_entry_to_user(iter, &pos,
1923 &size, counters, i++);
1933 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1937 struct compat_ip6t_get_entries get;
1940 if (*len < sizeof(get)) {
1941 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1945 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1948 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1949 duprintf("compat_get_entries: %u != %zu\n",
1950 *len, sizeof(get) + get.size);
1954 xt_compat_lock(AF_INET6);
1955 t = xt_find_table_lock(net, AF_INET6, get.name);
1956 if (!IS_ERR_OR_NULL(t)) {
1957 const struct xt_table_info *private = t->private;
1958 struct xt_table_info info;
1959 duprintf("t->private->number = %u\n", private->number);
1960 ret = compat_table_info(private, &info);
1961 if (!ret && get.size == info.size) {
1962 ret = compat_copy_entries_to_user(private->size,
1963 t, uptr->entrytable);
1965 duprintf("compat_get_entries: I've got %u not %u!\n",
1966 private->size, get.size);
1969 xt_compat_flush_offsets(AF_INET6);
1973 ret = t ? PTR_ERR(t) : -ENOENT;
1975 xt_compat_unlock(AF_INET6);
1979 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1982 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1986 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1990 case IP6T_SO_GET_INFO:
1991 ret = get_info(sock_net(sk), user, len, 1);
1993 case IP6T_SO_GET_ENTRIES:
1994 ret = compat_get_entries(sock_net(sk), user, len);
1997 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2004 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2008 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2012 case IP6T_SO_SET_REPLACE:
2013 ret = do_replace(sock_net(sk), user, len);
2016 case IP6T_SO_SET_ADD_COUNTERS:
2017 ret = do_add_counters(sock_net(sk), user, len, 0);
2021 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2029 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2033 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2037 case IP6T_SO_GET_INFO:
2038 ret = get_info(sock_net(sk), user, len, 0);
2041 case IP6T_SO_GET_ENTRIES:
2042 ret = get_entries(sock_net(sk), user, len);
2045 case IP6T_SO_GET_REVISION_MATCH:
2046 case IP6T_SO_GET_REVISION_TARGET: {
2047 struct xt_get_revision rev;
2050 if (*len != sizeof(rev)) {
2054 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2058 rev.name[sizeof(rev.name)-1] = 0;
2060 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2065 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2068 "ip6t_%s", rev.name);
2073 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2080 struct xt_table *ip6t_register_table(struct net *net,
2081 const struct xt_table *table,
2082 const struct ip6t_replace *repl)
2085 struct xt_table_info *newinfo;
2086 struct xt_table_info bootstrap = {0};
2087 void *loc_cpu_entry;
2088 struct xt_table *new_table;
2090 newinfo = xt_alloc_table_info(repl->size);
2096 loc_cpu_entry = newinfo->entries;
2097 memcpy(loc_cpu_entry, repl->entries, repl->size);
2099 ret = translate_table(net, newinfo, loc_cpu_entry, repl);
2103 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2104 if (IS_ERR(new_table)) {
2105 ret = PTR_ERR(new_table);
2111 xt_free_table_info(newinfo);
2113 return ERR_PTR(ret);
2116 void ip6t_unregister_table(struct net *net, struct xt_table *table)
2118 struct xt_table_info *private;
2119 void *loc_cpu_entry;
2120 struct module *table_owner = table->me;
2121 struct ip6t_entry *iter;
2123 private = xt_unregister_table(table);
2125 /* Decrease module usage counts and free resources */
2126 loc_cpu_entry = private->entries;
2127 xt_entry_foreach(iter, loc_cpu_entry, private->size)
2128 cleanup_entry(iter, net);
2129 if (private->number > private->initial_entries)
2130 module_put(table_owner);
2131 xt_free_table_info(private);
2134 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2136 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2137 u_int8_t type, u_int8_t code,
2140 return (type == test_type && code >= min_code && code <= max_code)
2145 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2147 const struct icmp6hdr *ic;
2148 struct icmp6hdr _icmph;
2149 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2151 /* Must not be a fragment. */
2152 if (par->fragoff != 0)
2155 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2157 /* We've been asked to examine this packet, and we
2158 * can't. Hence, no choice but to drop.
2160 duprintf("Dropping evil ICMP tinygram.\n");
2161 par->hotdrop = true;
2165 return icmp6_type_code_match(icmpinfo->type,
2168 ic->icmp6_type, ic->icmp6_code,
2169 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2172 /* Called when user tries to insert an entry of this type. */
2173 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2175 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2177 /* Must specify no unknown invflags */
2178 return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2181 /* The built-in targets: standard (NULL) and error. */
2182 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2184 .name = XT_STANDARD_TARGET,
2185 .targetsize = sizeof(int),
2186 .family = NFPROTO_IPV6,
2187 #ifdef CONFIG_COMPAT
2188 .compatsize = sizeof(compat_int_t),
2189 .compat_from_user = compat_standard_from_user,
2190 .compat_to_user = compat_standard_to_user,
2194 .name = XT_ERROR_TARGET,
2195 .target = ip6t_error,
2196 .targetsize = XT_FUNCTION_MAXNAMELEN,
2197 .family = NFPROTO_IPV6,
2201 static struct nf_sockopt_ops ip6t_sockopts = {
2203 .set_optmin = IP6T_BASE_CTL,
2204 .set_optmax = IP6T_SO_SET_MAX+1,
2205 .set = do_ip6t_set_ctl,
2206 #ifdef CONFIG_COMPAT
2207 .compat_set = compat_do_ip6t_set_ctl,
2209 .get_optmin = IP6T_BASE_CTL,
2210 .get_optmax = IP6T_SO_GET_MAX+1,
2211 .get = do_ip6t_get_ctl,
2212 #ifdef CONFIG_COMPAT
2213 .compat_get = compat_do_ip6t_get_ctl,
2215 .owner = THIS_MODULE,
2218 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2221 .match = icmp6_match,
2222 .matchsize = sizeof(struct ip6t_icmp),
2223 .checkentry = icmp6_checkentry,
2224 .proto = IPPROTO_ICMPV6,
2225 .family = NFPROTO_IPV6,
2229 static int __net_init ip6_tables_net_init(struct net *net)
2231 return xt_proto_init(net, NFPROTO_IPV6);
2234 static void __net_exit ip6_tables_net_exit(struct net *net)
2236 xt_proto_fini(net, NFPROTO_IPV6);
2239 static struct pernet_operations ip6_tables_net_ops = {
2240 .init = ip6_tables_net_init,
2241 .exit = ip6_tables_net_exit,
2244 static int __init ip6_tables_init(void)
2248 ret = register_pernet_subsys(&ip6_tables_net_ops);
2252 /* No one else will be downing sem now, so we won't sleep */
2253 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2256 ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2260 /* Register setsockopt */
2261 ret = nf_register_sockopt(&ip6t_sockopts);
2265 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2269 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2271 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2273 unregister_pernet_subsys(&ip6_tables_net_ops);
2278 static void __exit ip6_tables_fini(void)
2280 nf_unregister_sockopt(&ip6t_sockopts);
2282 xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2283 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2284 unregister_pernet_subsys(&ip6_tables_net_ops);
2287 EXPORT_SYMBOL(ip6t_register_table);
2288 EXPORT_SYMBOL(ip6t_unregister_table);
2289 EXPORT_SYMBOL(ip6t_do_table);
2291 module_init(ip6_tables_init);
2292 module_exit(ip6_tables_fini);