2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/capability.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/poison.h>
20 #include <linux/icmpv6.h>
22 #include <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>
33 MODULE_LICENSE("GPL");
34 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
35 MODULE_DESCRIPTION("IPv6 packet filter");
37 /*#define DEBUG_IP_FIREWALL*/
38 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
39 /*#define DEBUG_IP_FIREWALL_USER*/
41 #ifdef DEBUG_IP_FIREWALL
42 #define dprintf(format, args...) printk(format , ## args)
44 #define dprintf(format, args...)
47 #ifdef DEBUG_IP_FIREWALL_USER
48 #define duprintf(format, args...) printk(format , ## args)
50 #define duprintf(format, args...)
53 #ifdef CONFIG_NETFILTER_DEBUG
54 #define IP_NF_ASSERT(x) \
57 printk("IP_NF_ASSERT: %s:%s:%u\n", \
58 __func__, __FILE__, __LINE__); \
61 #define IP_NF_ASSERT(x)
65 /* All the better to debug you with... */
71 We keep a set of rules for each CPU, so we can avoid write-locking
72 them in the softirq when updating the counters and therefore
73 only need to read-lock in the softirq; doing a write_lock_bh() in user
74 context stops packets coming through and allows user context to read
75 the counters or update the rules.
77 Hence the start of any table is given by get_table() below. */
79 /* Check for an extension */
81 ip6t_ext_hdr(u8 nexthdr)
83 return ( (nexthdr == IPPROTO_HOPOPTS) ||
84 (nexthdr == IPPROTO_ROUTING) ||
85 (nexthdr == IPPROTO_FRAGMENT) ||
86 (nexthdr == IPPROTO_ESP) ||
87 (nexthdr == IPPROTO_AH) ||
88 (nexthdr == IPPROTO_NONE) ||
89 (nexthdr == IPPROTO_DSTOPTS) );
92 /* Returns whether matches rule or not. */
93 /* Performance critical - called for every packet */
95 ip6_packet_match(const struct sk_buff *skb,
98 const struct ip6t_ip6 *ip6info,
99 unsigned int *protoff,
100 int *fragoff, bool *hotdrop)
103 const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
105 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
107 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
108 &ip6info->src), IP6T_INV_SRCIP)
109 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
110 &ip6info->dst), IP6T_INV_DSTIP)) {
111 dprintf("Source or dest mismatch.\n");
113 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
114 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
115 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
116 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
117 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
118 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
122 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
124 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
125 dprintf("VIA in mismatch (%s vs %s).%s\n",
126 indev, ip6info->iniface,
127 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
131 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
133 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
134 dprintf("VIA out mismatch (%s vs %s).%s\n",
135 outdev, ip6info->outiface,
136 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
140 /* ... might want to do something with class and flowlabel here ... */
142 /* look for the desired protocol header */
143 if((ip6info->flags & IP6T_F_PROTO)) {
145 unsigned short _frag_off;
147 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
153 *fragoff = _frag_off;
155 dprintf("Packet protocol %hi ?= %s%hi.\n",
157 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
160 if (ip6info->proto == protohdr) {
161 if(ip6info->invflags & IP6T_INV_PROTO) {
167 /* We need match for the '-p all', too! */
168 if ((ip6info->proto != 0) &&
169 !(ip6info->invflags & IP6T_INV_PROTO))
175 /* should be ip6 safe */
177 ip6_checkentry(const struct ip6t_ip6 *ipv6)
179 if (ipv6->flags & ~IP6T_F_MASK) {
180 duprintf("Unknown flag bits set: %08X\n",
181 ipv6->flags & ~IP6T_F_MASK);
184 if (ipv6->invflags & ~IP6T_INV_MASK) {
185 duprintf("Unknown invflag bits set: %08X\n",
186 ipv6->invflags & ~IP6T_INV_MASK);
193 ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
196 printk("ip6_tables: error: `%s'\n",
197 (const char *)par->targinfo);
202 /* Performance critical - called for every packet */
204 do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
205 struct xt_match_param *par)
207 par->match = m->u.kernel.match;
208 par->matchinfo = m->data;
210 /* Stop iteration if it doesn't match */
211 if (!m->u.kernel.match->match(skb, par))
217 static inline struct ip6t_entry *
218 get_entry(void *base, unsigned int offset)
220 return (struct ip6t_entry *)(base + offset);
223 /* All zeroes == unconditional rule. */
224 /* Mildly perf critical (only if packet tracing is on) */
226 unconditional(const struct ip6t_ip6 *ipv6)
230 for (i = 0; i < sizeof(*ipv6); i++)
231 if (((char *)ipv6)[i])
234 return (i == sizeof(*ipv6));
237 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
238 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
239 /* This cries for unification! */
240 static const char *const hooknames[] = {
241 [NF_INET_PRE_ROUTING] = "PREROUTING",
242 [NF_INET_LOCAL_IN] = "INPUT",
243 [NF_INET_FORWARD] = "FORWARD",
244 [NF_INET_LOCAL_OUT] = "OUTPUT",
245 [NF_INET_POST_ROUTING] = "POSTROUTING",
248 enum nf_ip_trace_comments {
249 NF_IP6_TRACE_COMMENT_RULE,
250 NF_IP6_TRACE_COMMENT_RETURN,
251 NF_IP6_TRACE_COMMENT_POLICY,
254 static const char *const comments[] = {
255 [NF_IP6_TRACE_COMMENT_RULE] = "rule",
256 [NF_IP6_TRACE_COMMENT_RETURN] = "return",
257 [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
260 static struct nf_loginfo trace_loginfo = {
261 .type = NF_LOG_TYPE_LOG,
265 .logflags = NF_LOG_MASK,
270 /* Mildly perf critical (only if packet tracing is on) */
272 get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
273 const char *hookname, const char **chainname,
274 const char **comment, unsigned int *rulenum)
276 struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
278 if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
279 /* Head of user chain: ERROR target with chainname */
280 *chainname = t->target.data;
285 if (s->target_offset == sizeof(struct ip6t_entry)
286 && strcmp(t->target.u.kernel.target->name,
287 IP6T_STANDARD_TARGET) == 0
289 && unconditional(&s->ipv6)) {
290 /* Tail of chains: STANDARD target (return/policy) */
291 *comment = *chainname == hookname
292 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
293 : comments[NF_IP6_TRACE_COMMENT_RETURN];
302 static void trace_packet(struct sk_buff *skb,
304 const struct net_device *in,
305 const struct net_device *out,
306 const char *tablename,
307 struct xt_table_info *private,
308 struct ip6t_entry *e)
311 const struct ip6t_entry *root;
312 const char *hookname, *chainname, *comment;
313 unsigned int rulenum = 0;
315 table_base = private->entries[smp_processor_id()];
316 root = get_entry(table_base, private->hook_entry[hook]);
318 hookname = chainname = hooknames[hook];
319 comment = comments[NF_IP6_TRACE_COMMENT_RULE];
321 IP6T_ENTRY_ITERATE(root,
322 private->size - private->hook_entry[hook],
323 get_chainname_rulenum,
324 e, hookname, &chainname, &comment, &rulenum);
326 nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
327 "TRACE: %s:%s:%s:%u ",
328 tablename, chainname, comment, rulenum);
332 static inline __pure struct ip6t_entry *
333 ip6t_next_entry(const struct ip6t_entry *entry)
335 return (void *)entry + entry->next_offset;
338 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
340 ip6t_do_table(struct sk_buff *skb,
342 const struct net_device *in,
343 const struct net_device *out,
344 struct xt_table *table)
346 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
347 bool hotdrop = false;
348 /* Initializing verdict to NF_DROP keeps gcc happy. */
349 unsigned int verdict = NF_DROP;
350 const char *indev, *outdev;
352 struct ip6t_entry *e, *back;
353 struct xt_table_info *private;
354 struct xt_match_param mtpar;
355 struct xt_target_param tgpar;
358 indev = in ? in->name : nulldevname;
359 outdev = out ? out->name : nulldevname;
360 /* We handle fragments by dealing with the first fragment as
361 * if it was a normal packet. All other fragments are treated
362 * normally, except that they will NEVER match rules that ask
363 * things we don't know, ie. tcp syn flag or ports). If the
364 * rule is also a fragment-specific rule, non-fragments won't
366 mtpar.hotdrop = &hotdrop;
367 mtpar.in = tgpar.in = in;
368 mtpar.out = tgpar.out = out;
369 mtpar.family = tgpar.family = NFPROTO_IPV6;
370 tgpar.hooknum = hook;
372 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
375 private = table->private;
376 table_base = private->entries[smp_processor_id()];
378 e = get_entry(table_base, private->hook_entry[hook]);
380 /* For return from builtin chain */
381 back = get_entry(table_base, private->underflow[hook]);
386 if (ip6_packet_match(skb, indev, outdev, &e->ipv6,
387 &mtpar.thoff, &mtpar.fragoff, &hotdrop)) {
388 struct ip6t_entry_target *t;
390 if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
393 ADD_COUNTER(e->counters,
394 ntohs(ipv6_hdr(skb)->payload_len) +
395 sizeof(struct ipv6hdr), 1);
397 t = ip6t_get_target(e);
398 IP_NF_ASSERT(t->u.kernel.target);
400 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
401 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
402 /* The packet is traced: log it */
403 if (unlikely(skb->nf_trace))
404 trace_packet(skb, hook, in, out,
405 table->name, private, e);
407 /* Standard target? */
408 if (!t->u.kernel.target->target) {
411 v = ((struct ip6t_standard_target *)t)->verdict;
413 /* Pop from stack? */
414 if (v != IP6T_RETURN) {
415 verdict = (unsigned)(-v) - 1;
419 back = get_entry(table_base,
423 if (table_base + v != ip6t_next_entry(e)
424 && !(e->ipv6.flags & IP6T_F_GOTO)) {
425 /* Save old back ptr in next entry */
426 struct ip6t_entry *next
427 = ip6t_next_entry(e);
429 = (void *)back - table_base;
430 /* set back pointer to next entry */
434 e = get_entry(table_base, v);
436 /* Targets which reenter must return
438 tgpar.target = t->u.kernel.target;
439 tgpar.targinfo = t->data;
441 #ifdef CONFIG_NETFILTER_DEBUG
442 ((struct ip6t_entry *)table_base)->comefrom
445 verdict = t->u.kernel.target->target(skb,
448 #ifdef CONFIG_NETFILTER_DEBUG
449 if (((struct ip6t_entry *)table_base)->comefrom
451 && verdict == IP6T_CONTINUE) {
452 printk("Target %s reentered!\n",
453 t->u.kernel.target->name);
456 ((struct ip6t_entry *)table_base)->comefrom
459 if (verdict == IP6T_CONTINUE)
460 e = ip6t_next_entry(e);
468 e = ip6t_next_entry(e);
472 #ifdef CONFIG_NETFILTER_DEBUG
473 ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
475 xt_info_rdunlock_bh();
477 #ifdef DEBUG_ALLOW_ALL
486 /* Figures out from what hook each rule can be called: returns 0 if
487 there are loops. Puts hook bitmask in comefrom. */
489 mark_source_chains(struct xt_table_info *newinfo,
490 unsigned int valid_hooks, void *entry0)
494 /* No recursion; use packet counter to save back ptrs (reset
495 to 0 as we leave), and comefrom to save source hook bitmask */
496 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
497 unsigned int pos = newinfo->hook_entry[hook];
498 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
500 if (!(valid_hooks & (1 << hook)))
503 /* Set initial back pointer. */
504 e->counters.pcnt = pos;
507 struct ip6t_standard_target *t
508 = (void *)ip6t_get_target(e);
509 int visited = e->comefrom & (1 << hook);
511 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
512 printk("iptables: loop hook %u pos %u %08X.\n",
513 hook, pos, e->comefrom);
516 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
518 /* Unconditional return/END. */
519 if ((e->target_offset == sizeof(struct ip6t_entry)
520 && (strcmp(t->target.u.user.name,
521 IP6T_STANDARD_TARGET) == 0)
523 && unconditional(&e->ipv6)) || visited) {
524 unsigned int oldpos, size;
526 if ((strcmp(t->target.u.user.name,
527 IP6T_STANDARD_TARGET) == 0) &&
528 t->verdict < -NF_MAX_VERDICT - 1) {
529 duprintf("mark_source_chains: bad "
530 "negative verdict (%i)\n",
535 /* Return: backtrack through the last
538 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
539 #ifdef DEBUG_IP_FIREWALL_USER
541 & (1 << NF_INET_NUMHOOKS)) {
542 duprintf("Back unset "
549 pos = e->counters.pcnt;
550 e->counters.pcnt = 0;
552 /* We're at the start. */
556 e = (struct ip6t_entry *)
558 } while (oldpos == pos + e->next_offset);
561 size = e->next_offset;
562 e = (struct ip6t_entry *)
563 (entry0 + pos + size);
564 e->counters.pcnt = pos;
567 int newpos = t->verdict;
569 if (strcmp(t->target.u.user.name,
570 IP6T_STANDARD_TARGET) == 0
572 if (newpos > newinfo->size -
573 sizeof(struct ip6t_entry)) {
574 duprintf("mark_source_chains: "
575 "bad verdict (%i)\n",
579 /* This a jump; chase it. */
580 duprintf("Jump rule %u -> %u\n",
583 /* ... this is a fallthru */
584 newpos = pos + e->next_offset;
586 e = (struct ip6t_entry *)
588 e->counters.pcnt = pos;
593 duprintf("Finished chain %u\n", hook);
599 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
601 struct xt_mtdtor_param par;
603 if (i && (*i)-- == 0)
606 par.match = m->u.kernel.match;
607 par.matchinfo = m->data;
608 par.family = NFPROTO_IPV6;
609 if (par.match->destroy != NULL)
610 par.match->destroy(&par);
611 module_put(par.match->me);
616 check_entry(struct ip6t_entry *e, const char *name)
618 struct ip6t_entry_target *t;
620 if (!ip6_checkentry(&e->ipv6)) {
621 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
625 if (e->target_offset + sizeof(struct ip6t_entry_target) >
629 t = ip6t_get_target(e);
630 if (e->target_offset + t->u.target_size > e->next_offset)
636 static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
639 const struct ip6t_ip6 *ipv6 = par->entryinfo;
642 par->match = m->u.kernel.match;
643 par->matchinfo = m->data;
645 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
646 ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
648 duprintf("ip_tables: check failed for `%s'.\n",
657 find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
660 struct xt_match *match;
663 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
665 "ip6t_%s", m->u.user.name);
666 if (IS_ERR(match) || !match) {
667 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
668 return match ? PTR_ERR(match) : -ENOENT;
670 m->u.kernel.match = match;
672 ret = check_match(m, par, i);
678 module_put(m->u.kernel.match->me);
682 static int check_target(struct ip6t_entry *e, const char *name)
684 struct ip6t_entry_target *t = ip6t_get_target(e);
685 struct xt_tgchk_param par = {
688 .target = t->u.kernel.target,
690 .hook_mask = e->comefrom,
691 .family = NFPROTO_IPV6,
695 t = ip6t_get_target(e);
696 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
697 e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
699 duprintf("ip_tables: check failed for `%s'.\n",
700 t->u.kernel.target->name);
707 find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
710 struct ip6t_entry_target *t;
711 struct xt_target *target;
714 struct xt_mtchk_param mtpar;
716 ret = check_entry(e, name);
722 mtpar.entryinfo = &e->ipv6;
723 mtpar.hook_mask = e->comefrom;
724 mtpar.family = NFPROTO_IPV6;
725 ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
727 goto cleanup_matches;
729 t = ip6t_get_target(e);
730 target = try_then_request_module(xt_find_target(AF_INET6,
733 "ip6t_%s", t->u.user.name);
734 if (IS_ERR(target) || !target) {
735 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
736 ret = target ? PTR_ERR(target) : -ENOENT;
737 goto cleanup_matches;
739 t->u.kernel.target = target;
741 ret = check_target(e, name);
748 module_put(t->u.kernel.target->me);
750 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
755 check_entry_size_and_hooks(struct ip6t_entry *e,
756 struct xt_table_info *newinfo,
758 unsigned char *limit,
759 const unsigned int *hook_entries,
760 const unsigned int *underflows,
765 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
766 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
767 duprintf("Bad offset %p\n", e);
772 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
773 duprintf("checking: element %p size %u\n",
778 /* Check hooks & underflows */
779 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
780 if ((unsigned char *)e - base == hook_entries[h])
781 newinfo->hook_entry[h] = hook_entries[h];
782 if ((unsigned char *)e - base == underflows[h])
783 newinfo->underflow[h] = underflows[h];
786 /* FIXME: underflows must be unconditional, standard verdicts
787 < 0 (not IP6T_RETURN). --RR */
789 /* Clear counters and comefrom */
790 e->counters = ((struct xt_counters) { 0, 0 });
798 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
800 struct xt_tgdtor_param par;
801 struct ip6t_entry_target *t;
803 if (i && (*i)-- == 0)
806 /* Cleanup all matches */
807 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
808 t = ip6t_get_target(e);
810 par.target = t->u.kernel.target;
811 par.targinfo = t->data;
812 par.family = NFPROTO_IPV6;
813 if (par.target->destroy != NULL)
814 par.target->destroy(&par);
815 module_put(par.target->me);
819 /* Checks and translates the user-supplied table segment (held in
822 translate_table(const char *name,
823 unsigned int valid_hooks,
824 struct xt_table_info *newinfo,
828 const unsigned int *hook_entries,
829 const unsigned int *underflows)
834 newinfo->size = size;
835 newinfo->number = number;
837 /* Init all hooks to impossible value. */
838 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
839 newinfo->hook_entry[i] = 0xFFFFFFFF;
840 newinfo->underflow[i] = 0xFFFFFFFF;
843 duprintf("translate_table: size %u\n", newinfo->size);
845 /* Walk through entries, checking offsets. */
846 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
847 check_entry_size_and_hooks,
851 hook_entries, underflows, &i);
856 duprintf("translate_table: %u not %u entries\n",
861 /* Check hooks all assigned */
862 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
863 /* Only hooks which are valid */
864 if (!(valid_hooks & (1 << i)))
866 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
867 duprintf("Invalid hook entry %u %u\n",
871 if (newinfo->underflow[i] == 0xFFFFFFFF) {
872 duprintf("Invalid underflow %u %u\n",
878 if (!mark_source_chains(newinfo, valid_hooks, entry0))
881 /* Finally, each sanity check must pass */
883 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
884 find_check_entry, name, size, &i);
887 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
892 /* And one copy for every other CPU */
893 for_each_possible_cpu(i) {
894 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
895 memcpy(newinfo->entries[i], entry0, newinfo->size);
903 add_entry_to_counter(const struct ip6t_entry *e,
904 struct xt_counters total[],
907 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
914 set_entry_to_counter(const struct ip6t_entry *e,
915 struct ip6t_counters total[],
918 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
925 get_counters(const struct xt_table_info *t,
926 struct xt_counters counters[])
932 /* Instead of clearing (by a previous call to memset())
933 * the counters and using adds, we set the counters
934 * with data used by 'current' CPU
936 * Bottom half has to be disabled to prevent deadlock
937 * if new softirq were to run and call ipt_do_table
940 curcpu = smp_processor_id();
943 IP6T_ENTRY_ITERATE(t->entries[curcpu],
945 set_entry_to_counter,
949 for_each_possible_cpu(cpu) {
954 IP6T_ENTRY_ITERATE(t->entries[cpu],
956 add_entry_to_counter,
959 xt_info_wrunlock(cpu);
964 static struct xt_counters *alloc_counters(struct xt_table *table)
966 unsigned int countersize;
967 struct xt_counters *counters;
968 struct xt_table_info *private = table->private;
970 /* We need atomic snapshot of counters: rest doesn't change
971 (other than comefrom, which userspace doesn't care
973 countersize = sizeof(struct xt_counters) * private->number;
974 counters = vmalloc_node(countersize, numa_node_id());
976 if (counters == NULL)
977 return ERR_PTR(-ENOMEM);
979 get_counters(private, counters);
985 copy_entries_to_user(unsigned int total_size,
986 struct xt_table *table,
987 void __user *userptr)
989 unsigned int off, num;
990 struct ip6t_entry *e;
991 struct xt_counters *counters;
992 const struct xt_table_info *private = table->private;
994 const void *loc_cpu_entry;
996 counters = alloc_counters(table);
997 if (IS_ERR(counters))
998 return PTR_ERR(counters);
1000 /* choose the copy that is on our node/cpu, ...
1001 * This choice is lazy (because current thread is
1002 * allowed to migrate to another cpu)
1004 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1005 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1010 /* FIXME: use iterator macros --RR */
1011 /* ... then go back and fix counters and names */
1012 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1014 const struct ip6t_entry_match *m;
1015 const struct ip6t_entry_target *t;
1017 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1018 if (copy_to_user(userptr + off
1019 + offsetof(struct ip6t_entry, counters),
1021 sizeof(counters[num])) != 0) {
1026 for (i = sizeof(struct ip6t_entry);
1027 i < e->target_offset;
1028 i += m->u.match_size) {
1031 if (copy_to_user(userptr + off + i
1032 + offsetof(struct ip6t_entry_match,
1034 m->u.kernel.match->name,
1035 strlen(m->u.kernel.match->name)+1)
1042 t = ip6t_get_target(e);
1043 if (copy_to_user(userptr + off + e->target_offset
1044 + offsetof(struct ip6t_entry_target,
1046 t->u.kernel.target->name,
1047 strlen(t->u.kernel.target->name)+1) != 0) {
1058 #ifdef CONFIG_COMPAT
1059 static void compat_standard_from_user(void *dst, void *src)
1061 int v = *(compat_int_t *)src;
1064 v += xt_compat_calc_jump(AF_INET6, v);
1065 memcpy(dst, &v, sizeof(v));
1068 static int compat_standard_to_user(void __user *dst, void *src)
1070 compat_int_t cv = *(int *)src;
1073 cv -= xt_compat_calc_jump(AF_INET6, cv);
1074 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1078 compat_calc_match(struct ip6t_entry_match *m, int *size)
1080 *size += xt_compat_match_offset(m->u.kernel.match);
1084 static int compat_calc_entry(struct ip6t_entry *e,
1085 const struct xt_table_info *info,
1086 void *base, struct xt_table_info *newinfo)
1088 struct ip6t_entry_target *t;
1089 unsigned int entry_offset;
1092 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1093 entry_offset = (void *)e - base;
1094 IP6T_MATCH_ITERATE(e, compat_calc_match, &off);
1095 t = ip6t_get_target(e);
1096 off += xt_compat_target_offset(t->u.kernel.target);
1097 newinfo->size -= off;
1098 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1102 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1103 if (info->hook_entry[i] &&
1104 (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1105 newinfo->hook_entry[i] -= off;
1106 if (info->underflow[i] &&
1107 (e < (struct ip6t_entry *)(base + info->underflow[i])))
1108 newinfo->underflow[i] -= off;
1113 static int compat_table_info(const struct xt_table_info *info,
1114 struct xt_table_info *newinfo)
1116 void *loc_cpu_entry;
1118 if (!newinfo || !info)
1121 /* we dont care about newinfo->entries[] */
1122 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1123 newinfo->initial_entries = 0;
1124 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1125 return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size,
1126 compat_calc_entry, info, loc_cpu_entry,
1131 static int get_info(struct net *net, void __user *user, int *len, int compat)
1133 char name[IP6T_TABLE_MAXNAMELEN];
1137 if (*len != sizeof(struct ip6t_getinfo)) {
1138 duprintf("length %u != %zu\n", *len,
1139 sizeof(struct ip6t_getinfo));
1143 if (copy_from_user(name, user, sizeof(name)) != 0)
1146 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1147 #ifdef CONFIG_COMPAT
1149 xt_compat_lock(AF_INET6);
1151 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1152 "ip6table_%s", name);
1153 if (t && !IS_ERR(t)) {
1154 struct ip6t_getinfo info;
1155 const struct xt_table_info *private = t->private;
1157 #ifdef CONFIG_COMPAT
1159 struct xt_table_info tmp;
1160 ret = compat_table_info(private, &tmp);
1161 xt_compat_flush_offsets(AF_INET6);
1165 info.valid_hooks = t->valid_hooks;
1166 memcpy(info.hook_entry, private->hook_entry,
1167 sizeof(info.hook_entry));
1168 memcpy(info.underflow, private->underflow,
1169 sizeof(info.underflow));
1170 info.num_entries = private->number;
1171 info.size = private->size;
1172 strcpy(info.name, name);
1174 if (copy_to_user(user, &info, *len) != 0)
1182 ret = t ? PTR_ERR(t) : -ENOENT;
1183 #ifdef CONFIG_COMPAT
1185 xt_compat_unlock(AF_INET6);
1191 get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
1194 struct ip6t_get_entries get;
1197 if (*len < sizeof(get)) {
1198 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1201 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1203 if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1204 duprintf("get_entries: %u != %zu\n",
1205 *len, sizeof(get) + get.size);
1209 t = xt_find_table_lock(net, AF_INET6, get.name);
1210 if (t && !IS_ERR(t)) {
1211 struct xt_table_info *private = t->private;
1212 duprintf("t->private->number = %u\n", private->number);
1213 if (get.size == private->size)
1214 ret = copy_entries_to_user(private->size,
1215 t, uptr->entrytable);
1217 duprintf("get_entries: I've got %u not %u!\n",
1218 private->size, get.size);
1224 ret = t ? PTR_ERR(t) : -ENOENT;
1230 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1231 struct xt_table_info *newinfo, unsigned int num_counters,
1232 void __user *counters_ptr)
1236 struct xt_table_info *oldinfo;
1237 struct xt_counters *counters;
1238 const void *loc_cpu_old_entry;
1241 counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
1248 t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1249 "ip6table_%s", name);
1250 if (!t || IS_ERR(t)) {
1251 ret = t ? PTR_ERR(t) : -ENOENT;
1252 goto free_newinfo_counters_untrans;
1256 if (valid_hooks != t->valid_hooks) {
1257 duprintf("Valid hook crap: %08X vs %08X\n",
1258 valid_hooks, t->valid_hooks);
1263 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1267 /* Update module usage count based on number of rules */
1268 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1269 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1270 if ((oldinfo->number > oldinfo->initial_entries) ||
1271 (newinfo->number <= oldinfo->initial_entries))
1273 if ((oldinfo->number > oldinfo->initial_entries) &&
1274 (newinfo->number <= oldinfo->initial_entries))
1277 /* Get the old counters, and synchronize with replace */
1278 get_counters(oldinfo, counters);
1280 /* Decrease module usage counts and free resource */
1281 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1282 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1284 xt_free_table_info(oldinfo);
1285 if (copy_to_user(counters_ptr, counters,
1286 sizeof(struct xt_counters) * num_counters) != 0)
1295 free_newinfo_counters_untrans:
1302 do_replace(struct net *net, void __user *user, unsigned int len)
1305 struct ip6t_replace tmp;
1306 struct xt_table_info *newinfo;
1307 void *loc_cpu_entry;
1309 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1312 /* overflow check */
1313 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1316 newinfo = xt_alloc_table_info(tmp.size);
1320 /* choose the copy that is on our node/cpu */
1321 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1322 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1328 ret = translate_table(tmp.name, tmp.valid_hooks,
1329 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1330 tmp.hook_entry, tmp.underflow);
1334 duprintf("ip_tables: Translated table\n");
1336 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1337 tmp.num_counters, tmp.counters);
1339 goto free_newinfo_untrans;
1342 free_newinfo_untrans:
1343 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1345 xt_free_table_info(newinfo);
1349 /* We're lazy, and add to the first CPU; overflow works its fey magic
1350 * and everything is OK. */
1352 add_counter_to_entry(struct ip6t_entry *e,
1353 const struct xt_counters addme[],
1356 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1363 do_add_counters(struct net *net, void __user *user, unsigned int len,
1366 unsigned int i, curcpu;
1367 struct xt_counters_info tmp;
1368 struct xt_counters *paddc;
1369 unsigned int num_counters;
1374 const struct xt_table_info *private;
1376 const void *loc_cpu_entry;
1377 #ifdef CONFIG_COMPAT
1378 struct compat_xt_counters_info compat_tmp;
1382 size = sizeof(struct compat_xt_counters_info);
1387 size = sizeof(struct xt_counters_info);
1390 if (copy_from_user(ptmp, user, size) != 0)
1393 #ifdef CONFIG_COMPAT
1395 num_counters = compat_tmp.num_counters;
1396 name = compat_tmp.name;
1400 num_counters = tmp.num_counters;
1404 if (len != size + num_counters * sizeof(struct xt_counters))
1407 paddc = vmalloc_node(len - size, numa_node_id());
1411 if (copy_from_user(paddc, user + size, len - size) != 0) {
1416 t = xt_find_table_lock(net, AF_INET6, name);
1417 if (!t || IS_ERR(t)) {
1418 ret = t ? PTR_ERR(t) : -ENOENT;
1424 private = t->private;
1425 if (private->number != num_counters) {
1427 goto unlock_up_free;
1431 /* Choose the copy that is on our node */
1432 curcpu = smp_processor_id();
1433 xt_info_wrlock(curcpu);
1434 loc_cpu_entry = private->entries[curcpu];
1435 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1437 add_counter_to_entry,
1440 xt_info_wrunlock(curcpu);
1452 #ifdef CONFIG_COMPAT
1453 struct compat_ip6t_replace {
1454 char name[IP6T_TABLE_MAXNAMELEN];
1458 u32 hook_entry[NF_INET_NUMHOOKS];
1459 u32 underflow[NF_INET_NUMHOOKS];
1461 compat_uptr_t counters; /* struct ip6t_counters * */
1462 struct compat_ip6t_entry entries[0];
1466 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1467 unsigned int *size, struct xt_counters *counters,
1470 struct ip6t_entry_target *t;
1471 struct compat_ip6t_entry __user *ce;
1472 u_int16_t target_offset, next_offset;
1473 compat_uint_t origsize;
1478 ce = (struct compat_ip6t_entry __user *)*dstptr;
1479 if (copy_to_user(ce, e, sizeof(struct ip6t_entry)))
1482 if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1485 *dstptr += sizeof(struct compat_ip6t_entry);
1486 *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1488 ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1489 target_offset = e->target_offset - (origsize - *size);
1492 t = ip6t_get_target(e);
1493 ret = xt_compat_target_to_user(t, dstptr, size);
1497 next_offset = e->next_offset - (origsize - *size);
1498 if (put_user(target_offset, &ce->target_offset))
1500 if (put_user(next_offset, &ce->next_offset))
1510 compat_find_calc_match(struct ip6t_entry_match *m,
1512 const struct ip6t_ip6 *ipv6,
1513 unsigned int hookmask,
1514 int *size, unsigned int *i)
1516 struct xt_match *match;
1518 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
1519 m->u.user.revision),
1520 "ip6t_%s", m->u.user.name);
1521 if (IS_ERR(match) || !match) {
1522 duprintf("compat_check_calc_match: `%s' not found\n",
1524 return match ? PTR_ERR(match) : -ENOENT;
1526 m->u.kernel.match = match;
1527 *size += xt_compat_match_offset(match);
1534 compat_release_match(struct ip6t_entry_match *m, unsigned int *i)
1536 if (i && (*i)-- == 0)
1539 module_put(m->u.kernel.match->me);
1544 compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i)
1546 struct ip6t_entry_target *t;
1548 if (i && (*i)-- == 0)
1551 /* Cleanup all matches */
1552 COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL);
1553 t = compat_ip6t_get_target(e);
1554 module_put(t->u.kernel.target->me);
1559 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1560 struct xt_table_info *newinfo,
1562 unsigned char *base,
1563 unsigned char *limit,
1564 unsigned int *hook_entries,
1565 unsigned int *underflows,
1569 struct ip6t_entry_target *t;
1570 struct xt_target *target;
1571 unsigned int entry_offset;
1575 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1576 if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
1577 || (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1578 duprintf("Bad offset %p, limit = %p\n", e, limit);
1582 if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1583 sizeof(struct compat_xt_entry_target)) {
1584 duprintf("checking: element %p size %u\n",
1589 /* For purposes of check_entry casting the compat entry is fine */
1590 ret = check_entry((struct ip6t_entry *)e, name);
1594 off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1595 entry_offset = (void *)e - (void *)base;
1597 ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name,
1598 &e->ipv6, e->comefrom, &off, &j);
1600 goto release_matches;
1602 t = compat_ip6t_get_target(e);
1603 target = try_then_request_module(xt_find_target(AF_INET6,
1605 t->u.user.revision),
1606 "ip6t_%s", t->u.user.name);
1607 if (IS_ERR(target) || !target) {
1608 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1610 ret = target ? PTR_ERR(target) : -ENOENT;
1611 goto release_matches;
1613 t->u.kernel.target = target;
1615 off += xt_compat_target_offset(target);
1617 ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1621 /* Check hooks & underflows */
1622 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1623 if ((unsigned char *)e - base == hook_entries[h])
1624 newinfo->hook_entry[h] = hook_entries[h];
1625 if ((unsigned char *)e - base == underflows[h])
1626 newinfo->underflow[h] = underflows[h];
1629 /* Clear counters and comefrom */
1630 memset(&e->counters, 0, sizeof(e->counters));
1637 module_put(t->u.kernel.target->me);
1639 IP6T_MATCH_ITERATE(e, compat_release_match, &j);
1644 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1645 unsigned int *size, const char *name,
1646 struct xt_table_info *newinfo, unsigned char *base)
1648 struct ip6t_entry_target *t;
1649 struct xt_target *target;
1650 struct ip6t_entry *de;
1651 unsigned int origsize;
1656 de = (struct ip6t_entry *)*dstptr;
1657 memcpy(de, e, sizeof(struct ip6t_entry));
1658 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1660 *dstptr += sizeof(struct ip6t_entry);
1661 *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1663 ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user,
1667 de->target_offset = e->target_offset - (origsize - *size);
1668 t = compat_ip6t_get_target(e);
1669 target = t->u.kernel.target;
1670 xt_compat_target_from_user(t, dstptr, size);
1672 de->next_offset = e->next_offset - (origsize - *size);
1673 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1674 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1675 newinfo->hook_entry[h] -= origsize - *size;
1676 if ((unsigned char *)de - base < newinfo->underflow[h])
1677 newinfo->underflow[h] -= origsize - *size;
1682 static int compat_check_entry(struct ip6t_entry *e, const char *name,
1687 struct xt_mtchk_param mtpar;
1691 mtpar.entryinfo = &e->ipv6;
1692 mtpar.hook_mask = e->comefrom;
1693 mtpar.family = NFPROTO_IPV6;
1694 ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j);
1696 goto cleanup_matches;
1698 ret = check_target(e, name);
1700 goto cleanup_matches;
1706 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
1711 translate_compat_table(const char *name,
1712 unsigned int valid_hooks,
1713 struct xt_table_info **pinfo,
1715 unsigned int total_size,
1716 unsigned int number,
1717 unsigned int *hook_entries,
1718 unsigned int *underflows)
1721 struct xt_table_info *newinfo, *info;
1722 void *pos, *entry0, *entry1;
1729 info->number = number;
1731 /* Init all hooks to impossible value. */
1732 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1733 info->hook_entry[i] = 0xFFFFFFFF;
1734 info->underflow[i] = 0xFFFFFFFF;
1737 duprintf("translate_compat_table: size %u\n", info->size);
1739 xt_compat_lock(AF_INET6);
1740 /* Walk through entries, checking offsets. */
1741 ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1742 check_compat_entry_size_and_hooks,
1743 info, &size, entry0,
1744 entry0 + total_size,
1745 hook_entries, underflows, &j, name);
1751 duprintf("translate_compat_table: %u not %u entries\n",
1756 /* Check hooks all assigned */
1757 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1758 /* Only hooks which are valid */
1759 if (!(valid_hooks & (1 << i)))
1761 if (info->hook_entry[i] == 0xFFFFFFFF) {
1762 duprintf("Invalid hook entry %u %u\n",
1763 i, hook_entries[i]);
1766 if (info->underflow[i] == 0xFFFFFFFF) {
1767 duprintf("Invalid underflow %u %u\n",
1774 newinfo = xt_alloc_table_info(size);
1778 newinfo->number = number;
1779 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1780 newinfo->hook_entry[i] = info->hook_entry[i];
1781 newinfo->underflow[i] = info->underflow[i];
1783 entry1 = newinfo->entries[raw_smp_processor_id()];
1786 ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1787 compat_copy_entry_from_user,
1788 &pos, &size, name, newinfo, entry1);
1789 xt_compat_flush_offsets(AF_INET6);
1790 xt_compat_unlock(AF_INET6);
1795 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1799 ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1803 COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1804 compat_release_entry, &j);
1805 IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1806 xt_free_table_info(newinfo);
1810 /* And one copy for every other CPU */
1811 for_each_possible_cpu(i)
1812 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1813 memcpy(newinfo->entries[i], entry1, newinfo->size);
1817 xt_free_table_info(info);
1821 xt_free_table_info(newinfo);
1823 COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1826 xt_compat_flush_offsets(AF_INET6);
1827 xt_compat_unlock(AF_INET6);
1832 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1835 struct compat_ip6t_replace tmp;
1836 struct xt_table_info *newinfo;
1837 void *loc_cpu_entry;
1839 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1842 /* overflow check */
1843 if (tmp.size >= INT_MAX / num_possible_cpus())
1845 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1848 newinfo = xt_alloc_table_info(tmp.size);
1852 /* choose the copy that is on our node/cpu */
1853 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1854 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1860 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1861 &newinfo, &loc_cpu_entry, tmp.size,
1862 tmp.num_entries, tmp.hook_entry,
1867 duprintf("compat_do_replace: Translated table\n");
1869 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1870 tmp.num_counters, compat_ptr(tmp.counters));
1872 goto free_newinfo_untrans;
1875 free_newinfo_untrans:
1876 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1878 xt_free_table_info(newinfo);
1883 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1888 if (!capable(CAP_NET_ADMIN))
1892 case IP6T_SO_SET_REPLACE:
1893 ret = compat_do_replace(sock_net(sk), user, len);
1896 case IP6T_SO_SET_ADD_COUNTERS:
1897 ret = do_add_counters(sock_net(sk), user, len, 1);
1901 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1908 struct compat_ip6t_get_entries {
1909 char name[IP6T_TABLE_MAXNAMELEN];
1911 struct compat_ip6t_entry entrytable[0];
1915 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1916 void __user *userptr)
1918 struct xt_counters *counters;
1919 const struct xt_table_info *private = table->private;
1923 const void *loc_cpu_entry;
1926 counters = alloc_counters(table);
1927 if (IS_ERR(counters))
1928 return PTR_ERR(counters);
1930 /* choose the copy that is on our node/cpu, ...
1931 * This choice is lazy (because current thread is
1932 * allowed to migrate to another cpu)
1934 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1937 ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size,
1938 compat_copy_entry_to_user,
1939 &pos, &size, counters, &i);
1946 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1950 struct compat_ip6t_get_entries get;
1953 if (*len < sizeof(get)) {
1954 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1958 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1961 if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1962 duprintf("compat_get_entries: %u != %zu\n",
1963 *len, sizeof(get) + get.size);
1967 xt_compat_lock(AF_INET6);
1968 t = xt_find_table_lock(net, AF_INET6, get.name);
1969 if (t && !IS_ERR(t)) {
1970 const struct xt_table_info *private = t->private;
1971 struct xt_table_info info;
1972 duprintf("t->private->number = %u\n", private->number);
1973 ret = compat_table_info(private, &info);
1974 if (!ret && get.size == info.size) {
1975 ret = compat_copy_entries_to_user(private->size,
1976 t, uptr->entrytable);
1978 duprintf("compat_get_entries: I've got %u not %u!\n",
1979 private->size, get.size);
1982 xt_compat_flush_offsets(AF_INET6);
1986 ret = t ? PTR_ERR(t) : -ENOENT;
1988 xt_compat_unlock(AF_INET6);
1992 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1995 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1999 if (!capable(CAP_NET_ADMIN))
2003 case IP6T_SO_GET_INFO:
2004 ret = get_info(sock_net(sk), user, len, 1);
2006 case IP6T_SO_GET_ENTRIES:
2007 ret = compat_get_entries(sock_net(sk), user, len);
2010 ret = do_ip6t_get_ctl(sk, cmd, user, len);
2017 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2021 if (!capable(CAP_NET_ADMIN))
2025 case IP6T_SO_SET_REPLACE:
2026 ret = do_replace(sock_net(sk), user, len);
2029 case IP6T_SO_SET_ADD_COUNTERS:
2030 ret = do_add_counters(sock_net(sk), user, len, 0);
2034 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
2042 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2046 if (!capable(CAP_NET_ADMIN))
2050 case IP6T_SO_GET_INFO:
2051 ret = get_info(sock_net(sk), user, len, 0);
2054 case IP6T_SO_GET_ENTRIES:
2055 ret = get_entries(sock_net(sk), user, len);
2058 case IP6T_SO_GET_REVISION_MATCH:
2059 case IP6T_SO_GET_REVISION_TARGET: {
2060 struct ip6t_get_revision rev;
2063 if (*len != sizeof(rev)) {
2067 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2072 if (cmd == IP6T_SO_GET_REVISION_TARGET)
2077 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2080 "ip6t_%s", rev.name);
2085 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2092 struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table,
2093 const struct ip6t_replace *repl)
2096 struct xt_table_info *newinfo;
2097 struct xt_table_info bootstrap
2098 = { 0, 0, 0, { 0 }, { 0 }, { } };
2099 void *loc_cpu_entry;
2100 struct xt_table *new_table;
2102 newinfo = xt_alloc_table_info(repl->size);
2108 /* choose the copy on our node/cpu, but dont care about preemption */
2109 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2110 memcpy(loc_cpu_entry, repl->entries, repl->size);
2112 ret = translate_table(table->name, table->valid_hooks,
2113 newinfo, loc_cpu_entry, repl->size,
2120 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2121 if (IS_ERR(new_table)) {
2122 ret = PTR_ERR(new_table);
2128 xt_free_table_info(newinfo);
2130 return ERR_PTR(ret);
2133 void ip6t_unregister_table(struct xt_table *table)
2135 struct xt_table_info *private;
2136 void *loc_cpu_entry;
2137 struct module *table_owner = table->me;
2139 private = xt_unregister_table(table);
2141 /* Decrease module usage counts and free resources */
2142 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2143 IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2144 if (private->number > private->initial_entries)
2145 module_put(table_owner);
2146 xt_free_table_info(private);
2149 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2151 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2152 u_int8_t type, u_int8_t code,
2155 return (type == test_type && code >= min_code && code <= max_code)
2160 icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
2162 const struct icmp6hdr *ic;
2163 struct icmp6hdr _icmph;
2164 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2166 /* Must not be a fragment. */
2167 if (par->fragoff != 0)
2170 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2172 /* We've been asked to examine this packet, and we
2173 * can't. Hence, no choice but to drop.
2175 duprintf("Dropping evil ICMP tinygram.\n");
2176 *par->hotdrop = true;
2180 return icmp6_type_code_match(icmpinfo->type,
2183 ic->icmp6_type, ic->icmp6_code,
2184 !!(icmpinfo->invflags&IP6T_ICMP_INV));
2187 /* Called when user tries to insert an entry of this type. */
2188 static bool icmp6_checkentry(const struct xt_mtchk_param *par)
2190 const struct ip6t_icmp *icmpinfo = par->matchinfo;
2192 /* Must specify no unknown invflags */
2193 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
2196 /* The built-in targets: standard (NULL) and error. */
2197 static struct xt_target ip6t_standard_target __read_mostly = {
2198 .name = IP6T_STANDARD_TARGET,
2199 .targetsize = sizeof(int),
2200 .family = NFPROTO_IPV6,
2201 #ifdef CONFIG_COMPAT
2202 .compatsize = sizeof(compat_int_t),
2203 .compat_from_user = compat_standard_from_user,
2204 .compat_to_user = compat_standard_to_user,
2208 static struct xt_target ip6t_error_target __read_mostly = {
2209 .name = IP6T_ERROR_TARGET,
2210 .target = ip6t_error,
2211 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
2212 .family = NFPROTO_IPV6,
2215 static struct nf_sockopt_ops ip6t_sockopts = {
2217 .set_optmin = IP6T_BASE_CTL,
2218 .set_optmax = IP6T_SO_SET_MAX+1,
2219 .set = do_ip6t_set_ctl,
2220 #ifdef CONFIG_COMPAT
2221 .compat_set = compat_do_ip6t_set_ctl,
2223 .get_optmin = IP6T_BASE_CTL,
2224 .get_optmax = IP6T_SO_GET_MAX+1,
2225 .get = do_ip6t_get_ctl,
2226 #ifdef CONFIG_COMPAT
2227 .compat_get = compat_do_ip6t_get_ctl,
2229 .owner = THIS_MODULE,
2232 static struct xt_match icmp6_matchstruct __read_mostly = {
2234 .match = icmp6_match,
2235 .matchsize = sizeof(struct ip6t_icmp),
2236 .checkentry = icmp6_checkentry,
2237 .proto = IPPROTO_ICMPV6,
2238 .family = NFPROTO_IPV6,
2241 static int __net_init ip6_tables_net_init(struct net *net)
2243 return xt_proto_init(net, NFPROTO_IPV6);
2246 static void __net_exit ip6_tables_net_exit(struct net *net)
2248 xt_proto_fini(net, NFPROTO_IPV6);
2251 static struct pernet_operations ip6_tables_net_ops = {
2252 .init = ip6_tables_net_init,
2253 .exit = ip6_tables_net_exit,
2256 static int __init ip6_tables_init(void)
2260 ret = register_pernet_subsys(&ip6_tables_net_ops);
2264 /* Noone else will be downing sem now, so we won't sleep */
2265 ret = xt_register_target(&ip6t_standard_target);
2268 ret = xt_register_target(&ip6t_error_target);
2271 ret = xt_register_match(&icmp6_matchstruct);
2275 /* Register setsockopt */
2276 ret = nf_register_sockopt(&ip6t_sockopts);
2280 printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
2284 xt_unregister_match(&icmp6_matchstruct);
2286 xt_unregister_target(&ip6t_error_target);
2288 xt_unregister_target(&ip6t_standard_target);
2290 unregister_pernet_subsys(&ip6_tables_net_ops);
2295 static void __exit ip6_tables_fini(void)
2297 nf_unregister_sockopt(&ip6t_sockopts);
2299 xt_unregister_match(&icmp6_matchstruct);
2300 xt_unregister_target(&ip6t_error_target);
2301 xt_unregister_target(&ip6t_standard_target);
2303 unregister_pernet_subsys(&ip6_tables_net_ops);
2307 * find the offset to specified header or the protocol number of last header
2308 * if target < 0. "last header" is transport protocol header, ESP, or
2311 * If target header is found, its offset is set in *offset and return protocol
2312 * number. Otherwise, return -1.
2314 * If the first fragment doesn't contain the final protocol header or
2315 * NEXTHDR_NONE it is considered invalid.
2317 * Note that non-1st fragment is special case that "the protocol number
2318 * of last header" is "next header" field in Fragment header. In this case,
2319 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2323 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2324 int target, unsigned short *fragoff)
2326 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2327 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2328 unsigned int len = skb->len - start;
2333 while (nexthdr != target) {
2334 struct ipv6_opt_hdr _hdr, *hp;
2335 unsigned int hdrlen;
2337 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2343 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2346 if (nexthdr == NEXTHDR_FRAGMENT) {
2347 unsigned short _frag_off;
2349 fp = skb_header_pointer(skb,
2350 start+offsetof(struct frag_hdr,
2357 _frag_off = ntohs(*fp) & ~0x7;
2360 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2361 hp->nexthdr == NEXTHDR_NONE)) {
2363 *fragoff = _frag_off;
2369 } else if (nexthdr == NEXTHDR_AUTH)
2370 hdrlen = (hp->hdrlen + 2) << 2;
2372 hdrlen = ipv6_optlen(hp);
2374 nexthdr = hp->nexthdr;
2383 EXPORT_SYMBOL(ip6t_register_table);
2384 EXPORT_SYMBOL(ip6t_unregister_table);
2385 EXPORT_SYMBOL(ip6t_do_table);
2386 EXPORT_SYMBOL(ip6t_ext_hdr);
2387 EXPORT_SYMBOL(ipv6_find_hdr);
2389 module_init(ip6_tables_init);
2390 module_exit(ip6_tables_fini);