2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 #include <linux/capability.h>
14 #include <linux/skbuff.h>
15 #include <linux/kmod.h>
16 #include <linux/vmalloc.h>
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 #include <linux/poison.h>
20 #include <linux/icmpv6.h>
22 #include <net/compat.h>
23 #include <asm/uaccess.h>
24 #include <linux/mutex.h>
25 #include <linux/proc_fs.h>
26 #include <linux/err.h>
27 #include <linux/cpumask.h>
29 #include <linux/netfilter_ipv6/ip6_tables.h>
30 #include <linux/netfilter/x_tables.h>
31 #include <net/netfilter/nf_log.h>
32 #include "../../netfilter/xt_repldata.h"
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
38 /*#define DEBUG_IP_FIREWALL*/
39 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
40 /*#define DEBUG_IP_FIREWALL_USER*/
42 #ifdef DEBUG_IP_FIREWALL
43 #define dprintf(format, args...) pr_info(format , ## args)
45 #define dprintf(format, args...)
48 #ifdef DEBUG_IP_FIREWALL_USER
49 #define duprintf(format, args...) pr_info(format , ## args)
51 #define duprintf(format, args...)
54 #ifdef CONFIG_NETFILTER_DEBUG
55 #define IP_NF_ASSERT(x) WARN_ON(!(x))
57 #define IP_NF_ASSERT(x)
61 /* All the better to debug you with... */
66 void *ip6t_alloc_initial_table(const struct xt_table
*info
)
68 return xt_alloc_initial_table(ip6t
, IP6T
);
70 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table
);
73 We keep a set of rules for each CPU, so we can avoid write-locking
74 them in the softirq when updating the counters and therefore
75 only need to read-lock in the softirq; doing a write_lock_bh() in user
76 context stops packets coming through and allows user context to read
77 the counters or update the rules.
79 Hence the start of any table is given by get_table() below. */
81 /* Check for an extension */
83 ip6t_ext_hdr(u8 nexthdr
)
85 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
86 (nexthdr
== IPPROTO_ROUTING
) ||
87 (nexthdr
== IPPROTO_FRAGMENT
) ||
88 (nexthdr
== IPPROTO_ESP
) ||
89 (nexthdr
== IPPROTO_AH
) ||
90 (nexthdr
== IPPROTO_NONE
) ||
91 (nexthdr
== IPPROTO_DSTOPTS
) );
94 /* Returns whether matches rule or not. */
95 /* Performance critical - called for every packet */
97 ip6_packet_match(const struct sk_buff
*skb
,
100 const struct ip6t_ip6
*ip6info
,
101 unsigned int *protoff
,
102 int *fragoff
, bool *hotdrop
)
105 const struct ipv6hdr
*ipv6
= ipv6_hdr(skb
);
107 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
109 if (FWINV(ipv6_masked_addr_cmp(&ipv6
->saddr
, &ip6info
->smsk
,
110 &ip6info
->src
), IP6T_INV_SRCIP
) ||
111 FWINV(ipv6_masked_addr_cmp(&ipv6
->daddr
, &ip6info
->dmsk
,
112 &ip6info
->dst
), IP6T_INV_DSTIP
)) {
113 dprintf("Source or dest mismatch.\n");
115 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
116 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
117 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
118 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
119 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
120 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
124 ret
= ifname_compare_aligned(indev
, ip6info
->iniface
, ip6info
->iniface_mask
);
126 if (FWINV(ret
!= 0, IP6T_INV_VIA_IN
)) {
127 dprintf("VIA in mismatch (%s vs %s).%s\n",
128 indev
, ip6info
->iniface
,
129 ip6info
->invflags
&IP6T_INV_VIA_IN
?" (INV)":"");
133 ret
= ifname_compare_aligned(outdev
, ip6info
->outiface
, ip6info
->outiface_mask
);
135 if (FWINV(ret
!= 0, IP6T_INV_VIA_OUT
)) {
136 dprintf("VIA out mismatch (%s vs %s).%s\n",
137 outdev
, ip6info
->outiface
,
138 ip6info
->invflags
&IP6T_INV_VIA_OUT
?" (INV)":"");
142 /* ... might want to do something with class and flowlabel here ... */
144 /* look for the desired protocol header */
145 if((ip6info
->flags
& IP6T_F_PROTO
)) {
147 unsigned short _frag_off
;
149 protohdr
= ipv6_find_hdr(skb
, protoff
, -1, &_frag_off
);
155 *fragoff
= _frag_off
;
157 dprintf("Packet protocol %hi ?= %s%hi.\n",
159 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
162 if (ip6info
->proto
== protohdr
) {
163 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
169 /* We need match for the '-p all', too! */
170 if ((ip6info
->proto
!= 0) &&
171 !(ip6info
->invflags
& IP6T_INV_PROTO
))
177 /* should be ip6 safe */
179 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
181 if (ipv6
->flags
& ~IP6T_F_MASK
) {
182 duprintf("Unknown flag bits set: %08X\n",
183 ipv6
->flags
& ~IP6T_F_MASK
);
186 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
187 duprintf("Unknown invflag bits set: %08X\n",
188 ipv6
->invflags
& ~IP6T_INV_MASK
);
195 ip6t_error(struct sk_buff
*skb
, const struct xt_action_param
*par
)
198 pr_info("error: `%s'\n", (const char *)par
->targinfo
);
203 static inline struct ip6t_entry
*
204 get_entry(const void *base
, unsigned int offset
)
206 return (struct ip6t_entry
*)(base
+ offset
);
209 /* All zeroes == unconditional rule. */
210 /* Mildly perf critical (only if packet tracing is on) */
211 static inline bool unconditional(const struct ip6t_ip6
*ipv6
)
213 static const struct ip6t_ip6 uncond
;
215 return memcmp(ipv6
, &uncond
, sizeof(uncond
)) == 0;
218 static inline const struct ip6t_entry_target
*
219 ip6t_get_target_c(const struct ip6t_entry
*e
)
221 return ip6t_get_target((struct ip6t_entry
*)e
);
224 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
225 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
226 /* This cries for unification! */
227 static const char *const hooknames
[] = {
228 [NF_INET_PRE_ROUTING
] = "PREROUTING",
229 [NF_INET_LOCAL_IN
] = "INPUT",
230 [NF_INET_FORWARD
] = "FORWARD",
231 [NF_INET_LOCAL_OUT
] = "OUTPUT",
232 [NF_INET_POST_ROUTING
] = "POSTROUTING",
235 enum nf_ip_trace_comments
{
236 NF_IP6_TRACE_COMMENT_RULE
,
237 NF_IP6_TRACE_COMMENT_RETURN
,
238 NF_IP6_TRACE_COMMENT_POLICY
,
241 static const char *const comments
[] = {
242 [NF_IP6_TRACE_COMMENT_RULE
] = "rule",
243 [NF_IP6_TRACE_COMMENT_RETURN
] = "return",
244 [NF_IP6_TRACE_COMMENT_POLICY
] = "policy",
247 static struct nf_loginfo trace_loginfo
= {
248 .type
= NF_LOG_TYPE_LOG
,
252 .logflags
= NF_LOG_MASK
,
257 /* Mildly perf critical (only if packet tracing is on) */
259 get_chainname_rulenum(const struct ip6t_entry
*s
, const struct ip6t_entry
*e
,
260 const char *hookname
, const char **chainname
,
261 const char **comment
, unsigned int *rulenum
)
263 const struct ip6t_standard_target
*t
= (void *)ip6t_get_target_c(s
);
265 if (strcmp(t
->target
.u
.kernel
.target
->name
, IP6T_ERROR_TARGET
) == 0) {
266 /* Head of user chain: ERROR target with chainname */
267 *chainname
= t
->target
.data
;
272 if (s
->target_offset
== sizeof(struct ip6t_entry
) &&
273 strcmp(t
->target
.u
.kernel
.target
->name
,
274 IP6T_STANDARD_TARGET
) == 0 &&
276 unconditional(&s
->ipv6
)) {
277 /* Tail of chains: STANDARD target (return/policy) */
278 *comment
= *chainname
== hookname
279 ? comments
[NF_IP6_TRACE_COMMENT_POLICY
]
280 : comments
[NF_IP6_TRACE_COMMENT_RETURN
];
289 static void trace_packet(const struct sk_buff
*skb
,
291 const struct net_device
*in
,
292 const struct net_device
*out
,
293 const char *tablename
,
294 const struct xt_table_info
*private,
295 const struct ip6t_entry
*e
)
297 const void *table_base
;
298 const struct ip6t_entry
*root
;
299 const char *hookname
, *chainname
, *comment
;
300 const struct ip6t_entry
*iter
;
301 unsigned int rulenum
= 0;
303 table_base
= private->entries
[smp_processor_id()];
304 root
= get_entry(table_base
, private->hook_entry
[hook
]);
306 hookname
= chainname
= hooknames
[hook
];
307 comment
= comments
[NF_IP6_TRACE_COMMENT_RULE
];
309 xt_entry_foreach(iter
, root
, private->size
- private->hook_entry
[hook
])
310 if (get_chainname_rulenum(iter
, e
, hookname
,
311 &chainname
, &comment
, &rulenum
) != 0)
314 nf_log_packet(AF_INET6
, hook
, skb
, in
, out
, &trace_loginfo
,
315 "TRACE: %s:%s:%s:%u ",
316 tablename
, chainname
, comment
, rulenum
);
320 static inline __pure
struct ip6t_entry
*
321 ip6t_next_entry(const struct ip6t_entry
*entry
)
323 return (void *)entry
+ entry
->next_offset
;
326 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
328 ip6t_do_table(struct sk_buff
*skb
,
330 const struct net_device
*in
,
331 const struct net_device
*out
,
332 struct xt_table
*table
)
334 static const char nulldevname
[IFNAMSIZ
] __attribute__((aligned(sizeof(long))));
335 /* Initializing verdict to NF_DROP keeps gcc happy. */
336 unsigned int verdict
= NF_DROP
;
337 const char *indev
, *outdev
;
338 const void *table_base
;
339 struct ip6t_entry
*e
, **jumpstack
;
340 unsigned int *stackptr
, origptr
, cpu
;
341 const struct xt_table_info
*private;
342 struct xt_action_param acpar
;
345 indev
= in
? in
->name
: nulldevname
;
346 outdev
= out
? out
->name
: nulldevname
;
347 /* We handle fragments by dealing with the first fragment as
348 * if it was a normal packet. All other fragments are treated
349 * normally, except that they will NEVER match rules that ask
350 * things we don't know, ie. tcp syn flag or ports). If the
351 * rule is also a fragment-specific rule, non-fragments won't
353 acpar
.hotdrop
= false;
356 acpar
.family
= NFPROTO_IPV6
;
357 acpar
.hooknum
= hook
;
359 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
362 private = table
->private;
363 cpu
= smp_processor_id();
364 table_base
= private->entries
[cpu
];
365 jumpstack
= (struct ip6t_entry
**)private->jumpstack
[cpu
];
366 stackptr
= &private->stackptr
[cpu
];
369 e
= get_entry(table_base
, private->hook_entry
[hook
]);
372 const struct ip6t_entry_target
*t
;
373 const struct xt_entry_match
*ematch
;
376 if (!ip6_packet_match(skb
, indev
, outdev
, &e
->ipv6
,
377 &acpar
.thoff
, &acpar
.fragoff
, &acpar
.hotdrop
)) {
379 e
= ip6t_next_entry(e
);
383 xt_ematch_foreach(ematch
, e
) {
384 acpar
.match
= ematch
->u
.kernel
.match
;
385 acpar
.matchinfo
= ematch
->data
;
386 if (!acpar
.match
->match(skb
, &acpar
))
390 ADD_COUNTER(e
->counters
,
391 ntohs(ipv6_hdr(skb
)->payload_len
) +
392 sizeof(struct ipv6hdr
), 1);
394 t
= ip6t_get_target_c(e
);
395 IP_NF_ASSERT(t
->u
.kernel
.target
);
397 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
398 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
399 /* The packet is traced: log it */
400 if (unlikely(skb
->nf_trace
))
401 trace_packet(skb
, hook
, in
, out
,
402 table
->name
, private, e
);
404 /* Standard target? */
405 if (!t
->u
.kernel
.target
->target
) {
408 v
= ((struct ip6t_standard_target
*)t
)->verdict
;
410 /* Pop from stack? */
411 if (v
!= IP6T_RETURN
) {
412 verdict
= (unsigned)(-v
) - 1;
416 e
= get_entry(table_base
,
417 private->underflow
[hook
]);
419 e
= ip6t_next_entry(jumpstack
[--*stackptr
]);
422 if (table_base
+ v
!= ip6t_next_entry(e
) &&
423 !(e
->ipv6
.flags
& IP6T_F_GOTO
)) {
424 if (*stackptr
>= private->stacksize
) {
428 jumpstack
[(*stackptr
)++] = e
;
431 e
= get_entry(table_base
, v
);
435 acpar
.target
= t
->u
.kernel
.target
;
436 acpar
.targinfo
= t
->data
;
438 verdict
= t
->u
.kernel
.target
->target(skb
, &acpar
);
439 if (verdict
== IP6T_CONTINUE
)
440 e
= ip6t_next_entry(e
);
444 } while (!acpar
.hotdrop
);
446 xt_info_rdunlock_bh();
449 #ifdef DEBUG_ALLOW_ALL
458 /* Figures out from what hook each rule can be called: returns 0 if
459 there are loops. Puts hook bitmask in comefrom. */
461 mark_source_chains(const struct xt_table_info
*newinfo
,
462 unsigned int valid_hooks
, void *entry0
)
466 /* No recursion; use packet counter to save back ptrs (reset
467 to 0 as we leave), and comefrom to save source hook bitmask */
468 for (hook
= 0; hook
< NF_INET_NUMHOOKS
; hook
++) {
469 unsigned int pos
= newinfo
->hook_entry
[hook
];
470 struct ip6t_entry
*e
= (struct ip6t_entry
*)(entry0
+ pos
);
472 if (!(valid_hooks
& (1 << hook
)))
475 /* Set initial back pointer. */
476 e
->counters
.pcnt
= pos
;
479 const struct ip6t_standard_target
*t
480 = (void *)ip6t_get_target_c(e
);
481 int visited
= e
->comefrom
& (1 << hook
);
483 if (e
->comefrom
& (1 << NF_INET_NUMHOOKS
)) {
484 pr_err("iptables: loop hook %u pos %u %08X.\n",
485 hook
, pos
, e
->comefrom
);
488 e
->comefrom
|= ((1 << hook
) | (1 << NF_INET_NUMHOOKS
));
490 /* Unconditional return/END. */
491 if ((e
->target_offset
== sizeof(struct ip6t_entry
) &&
492 (strcmp(t
->target
.u
.user
.name
,
493 IP6T_STANDARD_TARGET
) == 0) &&
495 unconditional(&e
->ipv6
)) || visited
) {
496 unsigned int oldpos
, size
;
498 if ((strcmp(t
->target
.u
.user
.name
,
499 IP6T_STANDARD_TARGET
) == 0) &&
500 t
->verdict
< -NF_MAX_VERDICT
- 1) {
501 duprintf("mark_source_chains: bad "
502 "negative verdict (%i)\n",
507 /* Return: backtrack through the last
510 e
->comefrom
^= (1<<NF_INET_NUMHOOKS
);
511 #ifdef DEBUG_IP_FIREWALL_USER
513 & (1 << NF_INET_NUMHOOKS
)) {
514 duprintf("Back unset "
521 pos
= e
->counters
.pcnt
;
522 e
->counters
.pcnt
= 0;
524 /* We're at the start. */
528 e
= (struct ip6t_entry
*)
530 } while (oldpos
== pos
+ e
->next_offset
);
533 size
= e
->next_offset
;
534 e
= (struct ip6t_entry
*)
535 (entry0
+ pos
+ size
);
536 e
->counters
.pcnt
= pos
;
539 int newpos
= t
->verdict
;
541 if (strcmp(t
->target
.u
.user
.name
,
542 IP6T_STANDARD_TARGET
) == 0 &&
544 if (newpos
> newinfo
->size
-
545 sizeof(struct ip6t_entry
)) {
546 duprintf("mark_source_chains: "
547 "bad verdict (%i)\n",
551 /* This a jump; chase it. */
552 duprintf("Jump rule %u -> %u\n",
555 /* ... this is a fallthru */
556 newpos
= pos
+ e
->next_offset
;
558 e
= (struct ip6t_entry
*)
560 e
->counters
.pcnt
= pos
;
565 duprintf("Finished chain %u\n", hook
);
570 static void cleanup_match(struct ip6t_entry_match
*m
, struct net
*net
)
572 struct xt_mtdtor_param par
;
575 par
.match
= m
->u
.kernel
.match
;
576 par
.matchinfo
= m
->data
;
577 par
.family
= NFPROTO_IPV6
;
578 if (par
.match
->destroy
!= NULL
)
579 par
.match
->destroy(&par
);
580 module_put(par
.match
->me
);
584 check_entry(const struct ip6t_entry
*e
, const char *name
)
586 const struct ip6t_entry_target
*t
;
588 if (!ip6_checkentry(&e
->ipv6
)) {
589 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
593 if (e
->target_offset
+ sizeof(struct ip6t_entry_target
) >
597 t
= ip6t_get_target_c(e
);
598 if (e
->target_offset
+ t
->u
.target_size
> e
->next_offset
)
604 static int check_match(struct ip6t_entry_match
*m
, struct xt_mtchk_param
*par
)
606 const struct ip6t_ip6
*ipv6
= par
->entryinfo
;
609 par
->match
= m
->u
.kernel
.match
;
610 par
->matchinfo
= m
->data
;
612 ret
= xt_check_match(par
, m
->u
.match_size
- sizeof(*m
),
613 ipv6
->proto
, ipv6
->invflags
& IP6T_INV_PROTO
);
615 duprintf("ip_tables: check failed for `%s'.\n",
623 find_check_match(struct ip6t_entry_match
*m
, struct xt_mtchk_param
*par
)
625 struct xt_match
*match
;
628 match
= xt_request_find_match(NFPROTO_IPV6
, m
->u
.user
.name
,
631 duprintf("find_check_match: `%s' not found\n", m
->u
.user
.name
);
632 return PTR_ERR(match
);
634 m
->u
.kernel
.match
= match
;
636 ret
= check_match(m
, par
);
642 module_put(m
->u
.kernel
.match
->me
);
646 static int check_target(struct ip6t_entry
*e
, struct net
*net
, const char *name
)
648 struct ip6t_entry_target
*t
= ip6t_get_target(e
);
649 struct xt_tgchk_param par
= {
653 .target
= t
->u
.kernel
.target
,
655 .hook_mask
= e
->comefrom
,
656 .family
= NFPROTO_IPV6
,
660 t
= ip6t_get_target(e
);
661 ret
= xt_check_target(&par
, t
->u
.target_size
- sizeof(*t
),
662 e
->ipv6
.proto
, e
->ipv6
.invflags
& IP6T_INV_PROTO
);
664 duprintf("ip_tables: check failed for `%s'.\n",
665 t
->u
.kernel
.target
->name
);
672 find_check_entry(struct ip6t_entry
*e
, struct net
*net
, const char *name
,
675 struct ip6t_entry_target
*t
;
676 struct xt_target
*target
;
679 struct xt_mtchk_param mtpar
;
680 struct xt_entry_match
*ematch
;
682 ret
= check_entry(e
, name
);
689 mtpar
.entryinfo
= &e
->ipv6
;
690 mtpar
.hook_mask
= e
->comefrom
;
691 mtpar
.family
= NFPROTO_IPV6
;
692 xt_ematch_foreach(ematch
, e
) {
693 ret
= find_check_match(ematch
, &mtpar
);
695 goto cleanup_matches
;
699 t
= ip6t_get_target(e
);
700 target
= xt_request_find_target(NFPROTO_IPV6
, t
->u
.user
.name
,
702 if (IS_ERR(target
)) {
703 duprintf("find_check_entry: `%s' not found\n", t
->u
.user
.name
);
704 ret
= PTR_ERR(target
);
705 goto cleanup_matches
;
707 t
->u
.kernel
.target
= target
;
709 ret
= check_target(e
, net
, name
);
714 module_put(t
->u
.kernel
.target
->me
);
716 xt_ematch_foreach(ematch
, e
) {
719 cleanup_match(ematch
, net
);
724 static bool check_underflow(const struct ip6t_entry
*e
)
726 const struct ip6t_entry_target
*t
;
727 unsigned int verdict
;
729 if (!unconditional(&e
->ipv6
))
731 t
= ip6t_get_target_c(e
);
732 if (strcmp(t
->u
.user
.name
, XT_STANDARD_TARGET
) != 0)
734 verdict
= ((struct ip6t_standard_target
*)t
)->verdict
;
735 verdict
= -verdict
- 1;
736 return verdict
== NF_DROP
|| verdict
== NF_ACCEPT
;
740 check_entry_size_and_hooks(struct ip6t_entry
*e
,
741 struct xt_table_info
*newinfo
,
742 const unsigned char *base
,
743 const unsigned char *limit
,
744 const unsigned int *hook_entries
,
745 const unsigned int *underflows
,
746 unsigned int valid_hooks
)
750 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0 ||
751 (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
752 duprintf("Bad offset %p\n", e
);
757 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
758 duprintf("checking: element %p size %u\n",
763 /* Check hooks & underflows */
764 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
765 if (!(valid_hooks
& (1 << h
)))
767 if ((unsigned char *)e
- base
== hook_entries
[h
])
768 newinfo
->hook_entry
[h
] = hook_entries
[h
];
769 if ((unsigned char *)e
- base
== underflows
[h
]) {
770 if (!check_underflow(e
)) {
771 pr_err("Underflows must be unconditional and "
772 "use the STANDARD target with "
776 newinfo
->underflow
[h
] = underflows
[h
];
780 /* Clear counters and comefrom */
781 e
->counters
= ((struct xt_counters
) { 0, 0 });
786 static void cleanup_entry(struct ip6t_entry
*e
, struct net
*net
)
788 struct xt_tgdtor_param par
;
789 struct ip6t_entry_target
*t
;
790 struct xt_entry_match
*ematch
;
792 /* Cleanup all matches */
793 xt_ematch_foreach(ematch
, e
)
794 cleanup_match(ematch
, net
);
795 t
= ip6t_get_target(e
);
798 par
.target
= t
->u
.kernel
.target
;
799 par
.targinfo
= t
->data
;
800 par
.family
= NFPROTO_IPV6
;
801 if (par
.target
->destroy
!= NULL
)
802 par
.target
->destroy(&par
);
803 module_put(par
.target
->me
);
806 /* Checks and translates the user-supplied table segment (held in
809 translate_table(struct net
*net
, struct xt_table_info
*newinfo
, void *entry0
,
810 const struct ip6t_replace
*repl
)
812 struct ip6t_entry
*iter
;
816 newinfo
->size
= repl
->size
;
817 newinfo
->number
= repl
->num_entries
;
819 /* Init all hooks to impossible value. */
820 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
821 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
822 newinfo
->underflow
[i
] = 0xFFFFFFFF;
825 duprintf("translate_table: size %u\n", newinfo
->size
);
827 /* Walk through entries, checking offsets. */
828 xt_entry_foreach(iter
, entry0
, newinfo
->size
) {
829 ret
= check_entry_size_and_hooks(iter
, newinfo
, entry0
,
837 if (strcmp(ip6t_get_target(iter
)->u
.user
.name
,
838 XT_ERROR_TARGET
) == 0)
839 ++newinfo
->stacksize
;
842 if (i
!= repl
->num_entries
) {
843 duprintf("translate_table: %u not %u entries\n",
844 i
, repl
->num_entries
);
848 /* Check hooks all assigned */
849 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
850 /* Only hooks which are valid */
851 if (!(repl
->valid_hooks
& (1 << i
)))
853 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
854 duprintf("Invalid hook entry %u %u\n",
855 i
, repl
->hook_entry
[i
]);
858 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
859 duprintf("Invalid underflow %u %u\n",
860 i
, repl
->underflow
[i
]);
865 if (!mark_source_chains(newinfo
, repl
->valid_hooks
, entry0
))
868 /* Finally, each sanity check must pass */
870 xt_entry_foreach(iter
, entry0
, newinfo
->size
) {
871 ret
= find_check_entry(iter
, net
, repl
->name
, repl
->size
);
878 xt_entry_foreach(iter
, entry0
, newinfo
->size
) {
881 cleanup_entry(iter
, net
);
886 /* And one copy for every other CPU */
887 for_each_possible_cpu(i
) {
888 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry0
)
889 memcpy(newinfo
->entries
[i
], entry0
, newinfo
->size
);
896 get_counters(const struct xt_table_info
*t
,
897 struct xt_counters counters
[])
899 struct ip6t_entry
*iter
;
904 /* Instead of clearing (by a previous call to memset())
905 * the counters and using adds, we set the counters
906 * with data used by 'current' CPU
908 * Bottom half has to be disabled to prevent deadlock
909 * if new softirq were to run and call ipt_do_table
912 curcpu
= smp_processor_id();
915 xt_entry_foreach(iter
, t
->entries
[curcpu
], t
->size
) {
916 SET_COUNTER(counters
[i
], iter
->counters
.bcnt
,
917 iter
->counters
.pcnt
);
921 for_each_possible_cpu(cpu
) {
926 xt_entry_foreach(iter
, t
->entries
[cpu
], t
->size
) {
927 ADD_COUNTER(counters
[i
], iter
->counters
.bcnt
,
928 iter
->counters
.pcnt
);
931 xt_info_wrunlock(cpu
);
936 static struct xt_counters
*alloc_counters(const struct xt_table
*table
)
938 unsigned int countersize
;
939 struct xt_counters
*counters
;
940 const struct xt_table_info
*private = table
->private;
942 /* We need atomic snapshot of counters: rest doesn't change
943 (other than comefrom, which userspace doesn't care
945 countersize
= sizeof(struct xt_counters
) * private->number
;
946 counters
= vmalloc_node(countersize
, numa_node_id());
948 if (counters
== NULL
)
949 return ERR_PTR(-ENOMEM
);
951 get_counters(private, counters
);
957 copy_entries_to_user(unsigned int total_size
,
958 const struct xt_table
*table
,
959 void __user
*userptr
)
961 unsigned int off
, num
;
962 const struct ip6t_entry
*e
;
963 struct xt_counters
*counters
;
964 const struct xt_table_info
*private = table
->private;
966 const void *loc_cpu_entry
;
968 counters
= alloc_counters(table
);
969 if (IS_ERR(counters
))
970 return PTR_ERR(counters
);
972 /* choose the copy that is on our node/cpu, ...
973 * This choice is lazy (because current thread is
974 * allowed to migrate to another cpu)
976 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
977 if (copy_to_user(userptr
, loc_cpu_entry
, total_size
) != 0) {
982 /* FIXME: use iterator macros --RR */
983 /* ... then go back and fix counters and names */
984 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
986 const struct ip6t_entry_match
*m
;
987 const struct ip6t_entry_target
*t
;
989 e
= (struct ip6t_entry
*)(loc_cpu_entry
+ off
);
990 if (copy_to_user(userptr
+ off
991 + offsetof(struct ip6t_entry
, counters
),
993 sizeof(counters
[num
])) != 0) {
998 for (i
= sizeof(struct ip6t_entry
);
999 i
< e
->target_offset
;
1000 i
+= m
->u
.match_size
) {
1003 if (copy_to_user(userptr
+ off
+ i
1004 + offsetof(struct ip6t_entry_match
,
1006 m
->u
.kernel
.match
->name
,
1007 strlen(m
->u
.kernel
.match
->name
)+1)
1014 t
= ip6t_get_target_c(e
);
1015 if (copy_to_user(userptr
+ off
+ e
->target_offset
1016 + offsetof(struct ip6t_entry_target
,
1018 t
->u
.kernel
.target
->name
,
1019 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
1030 #ifdef CONFIG_COMPAT
1031 static void compat_standard_from_user(void *dst
, const void *src
)
1033 int v
= *(compat_int_t
*)src
;
1036 v
+= xt_compat_calc_jump(AF_INET6
, v
);
1037 memcpy(dst
, &v
, sizeof(v
));
1040 static int compat_standard_to_user(void __user
*dst
, const void *src
)
1042 compat_int_t cv
= *(int *)src
;
1045 cv
-= xt_compat_calc_jump(AF_INET6
, cv
);
1046 return copy_to_user(dst
, &cv
, sizeof(cv
)) ? -EFAULT
: 0;
1049 static int compat_calc_entry(const struct ip6t_entry
*e
,
1050 const struct xt_table_info
*info
,
1051 const void *base
, struct xt_table_info
*newinfo
)
1053 const struct xt_entry_match
*ematch
;
1054 const struct ip6t_entry_target
*t
;
1055 unsigned int entry_offset
;
1058 off
= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1059 entry_offset
= (void *)e
- base
;
1060 xt_ematch_foreach(ematch
, e
)
1061 off
+= xt_compat_match_offset(ematch
->u
.kernel
.match
);
1062 t
= ip6t_get_target_c(e
);
1063 off
+= xt_compat_target_offset(t
->u
.kernel
.target
);
1064 newinfo
->size
-= off
;
1065 ret
= xt_compat_add_offset(AF_INET6
, entry_offset
, off
);
1069 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1070 if (info
->hook_entry
[i
] &&
1071 (e
< (struct ip6t_entry
*)(base
+ info
->hook_entry
[i
])))
1072 newinfo
->hook_entry
[i
] -= off
;
1073 if (info
->underflow
[i
] &&
1074 (e
< (struct ip6t_entry
*)(base
+ info
->underflow
[i
])))
1075 newinfo
->underflow
[i
] -= off
;
1080 static int compat_table_info(const struct xt_table_info
*info
,
1081 struct xt_table_info
*newinfo
)
1083 struct ip6t_entry
*iter
;
1084 void *loc_cpu_entry
;
1087 if (!newinfo
|| !info
)
1090 /* we dont care about newinfo->entries[] */
1091 memcpy(newinfo
, info
, offsetof(struct xt_table_info
, entries
));
1092 newinfo
->initial_entries
= 0;
1093 loc_cpu_entry
= info
->entries
[raw_smp_processor_id()];
1094 xt_entry_foreach(iter
, loc_cpu_entry
, info
->size
) {
1095 ret
= compat_calc_entry(iter
, info
, loc_cpu_entry
, newinfo
);
1103 static int get_info(struct net
*net
, void __user
*user
,
1104 const int *len
, int compat
)
1106 char name
[IP6T_TABLE_MAXNAMELEN
];
1110 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1111 duprintf("length %u != %zu\n", *len
,
1112 sizeof(struct ip6t_getinfo
));
1116 if (copy_from_user(name
, user
, sizeof(name
)) != 0)
1119 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1120 #ifdef CONFIG_COMPAT
1122 xt_compat_lock(AF_INET6
);
1124 t
= try_then_request_module(xt_find_table_lock(net
, AF_INET6
, name
),
1125 "ip6table_%s", name
);
1126 if (t
&& !IS_ERR(t
)) {
1127 struct ip6t_getinfo info
;
1128 const struct xt_table_info
*private = t
->private;
1129 #ifdef CONFIG_COMPAT
1130 struct xt_table_info tmp
;
1133 ret
= compat_table_info(private, &tmp
);
1134 xt_compat_flush_offsets(AF_INET6
);
1138 info
.valid_hooks
= t
->valid_hooks
;
1139 memcpy(info
.hook_entry
, private->hook_entry
,
1140 sizeof(info
.hook_entry
));
1141 memcpy(info
.underflow
, private->underflow
,
1142 sizeof(info
.underflow
));
1143 info
.num_entries
= private->number
;
1144 info
.size
= private->size
;
1145 strcpy(info
.name
, name
);
1147 if (copy_to_user(user
, &info
, *len
) != 0)
1155 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1156 #ifdef CONFIG_COMPAT
1158 xt_compat_unlock(AF_INET6
);
1164 get_entries(struct net
*net
, struct ip6t_get_entries __user
*uptr
,
1168 struct ip6t_get_entries get
;
1171 if (*len
< sizeof(get
)) {
1172 duprintf("get_entries: %u < %zu\n", *len
, sizeof(get
));
1175 if (copy_from_user(&get
, uptr
, sizeof(get
)) != 0)
1177 if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1178 duprintf("get_entries: %u != %zu\n",
1179 *len
, sizeof(get
) + get
.size
);
1183 t
= xt_find_table_lock(net
, AF_INET6
, get
.name
);
1184 if (t
&& !IS_ERR(t
)) {
1185 struct xt_table_info
*private = t
->private;
1186 duprintf("t->private->number = %u\n", private->number
);
1187 if (get
.size
== private->size
)
1188 ret
= copy_entries_to_user(private->size
,
1189 t
, uptr
->entrytable
);
1191 duprintf("get_entries: I've got %u not %u!\n",
1192 private->size
, get
.size
);
1198 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1204 __do_replace(struct net
*net
, const char *name
, unsigned int valid_hooks
,
1205 struct xt_table_info
*newinfo
, unsigned int num_counters
,
1206 void __user
*counters_ptr
)
1210 struct xt_table_info
*oldinfo
;
1211 struct xt_counters
*counters
;
1212 const void *loc_cpu_old_entry
;
1213 struct ip6t_entry
*iter
;
1216 counters
= vmalloc_node(num_counters
* sizeof(struct xt_counters
),
1223 t
= try_then_request_module(xt_find_table_lock(net
, AF_INET6
, name
),
1224 "ip6table_%s", name
);
1225 if (!t
|| IS_ERR(t
)) {
1226 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1227 goto free_newinfo_counters_untrans
;
1231 if (valid_hooks
!= t
->valid_hooks
) {
1232 duprintf("Valid hook crap: %08X vs %08X\n",
1233 valid_hooks
, t
->valid_hooks
);
1238 oldinfo
= xt_replace_table(t
, num_counters
, newinfo
, &ret
);
1242 /* Update module usage count based on number of rules */
1243 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1244 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1245 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1246 (newinfo
->number
<= oldinfo
->initial_entries
))
1248 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1249 (newinfo
->number
<= oldinfo
->initial_entries
))
1252 /* Get the old counters, and synchronize with replace */
1253 get_counters(oldinfo
, counters
);
1255 /* Decrease module usage counts and free resource */
1256 loc_cpu_old_entry
= oldinfo
->entries
[raw_smp_processor_id()];
1257 xt_entry_foreach(iter
, loc_cpu_old_entry
, oldinfo
->size
)
1258 cleanup_entry(iter
, net
);
1260 xt_free_table_info(oldinfo
);
1261 if (copy_to_user(counters_ptr
, counters
,
1262 sizeof(struct xt_counters
) * num_counters
) != 0)
1271 free_newinfo_counters_untrans
:
1278 do_replace(struct net
*net
, const void __user
*user
, unsigned int len
)
1281 struct ip6t_replace tmp
;
1282 struct xt_table_info
*newinfo
;
1283 void *loc_cpu_entry
;
1284 struct ip6t_entry
*iter
;
1286 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1289 /* overflow check */
1290 if (tmp
.num_counters
>= INT_MAX
/ sizeof(struct xt_counters
))
1293 newinfo
= xt_alloc_table_info(tmp
.size
);
1297 /* choose the copy that is on our node/cpu */
1298 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1299 if (copy_from_user(loc_cpu_entry
, user
+ sizeof(tmp
),
1305 ret
= translate_table(net
, newinfo
, loc_cpu_entry
, &tmp
);
1309 duprintf("ip_tables: Translated table\n");
1311 ret
= __do_replace(net
, tmp
.name
, tmp
.valid_hooks
, newinfo
,
1312 tmp
.num_counters
, tmp
.counters
);
1314 goto free_newinfo_untrans
;
1317 free_newinfo_untrans
:
1318 xt_entry_foreach(iter
, loc_cpu_entry
, newinfo
->size
)
1319 cleanup_entry(iter
, net
);
1321 xt_free_table_info(newinfo
);
1326 do_add_counters(struct net
*net
, const void __user
*user
, unsigned int len
,
1329 unsigned int i
, curcpu
;
1330 struct xt_counters_info tmp
;
1331 struct xt_counters
*paddc
;
1332 unsigned int num_counters
;
1337 const struct xt_table_info
*private;
1339 const void *loc_cpu_entry
;
1340 struct ip6t_entry
*iter
;
1341 #ifdef CONFIG_COMPAT
1342 struct compat_xt_counters_info compat_tmp
;
1346 size
= sizeof(struct compat_xt_counters_info
);
1351 size
= sizeof(struct xt_counters_info
);
1354 if (copy_from_user(ptmp
, user
, size
) != 0)
1357 #ifdef CONFIG_COMPAT
1359 num_counters
= compat_tmp
.num_counters
;
1360 name
= compat_tmp
.name
;
1364 num_counters
= tmp
.num_counters
;
1368 if (len
!= size
+ num_counters
* sizeof(struct xt_counters
))
1371 paddc
= vmalloc_node(len
- size
, numa_node_id());
1375 if (copy_from_user(paddc
, user
+ size
, len
- size
) != 0) {
1380 t
= xt_find_table_lock(net
, AF_INET6
, name
);
1381 if (!t
|| IS_ERR(t
)) {
1382 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1388 private = t
->private;
1389 if (private->number
!= num_counters
) {
1391 goto unlock_up_free
;
1395 /* Choose the copy that is on our node */
1396 curcpu
= smp_processor_id();
1397 xt_info_wrlock(curcpu
);
1398 loc_cpu_entry
= private->entries
[curcpu
];
1399 xt_entry_foreach(iter
, loc_cpu_entry
, private->size
) {
1400 ADD_COUNTER(iter
->counters
, paddc
[i
].bcnt
, paddc
[i
].pcnt
);
1403 xt_info_wrunlock(curcpu
);
1415 #ifdef CONFIG_COMPAT
1416 struct compat_ip6t_replace
{
1417 char name
[IP6T_TABLE_MAXNAMELEN
];
1421 u32 hook_entry
[NF_INET_NUMHOOKS
];
1422 u32 underflow
[NF_INET_NUMHOOKS
];
1424 compat_uptr_t counters
; /* struct ip6t_counters * */
1425 struct compat_ip6t_entry entries
[0];
1429 compat_copy_entry_to_user(struct ip6t_entry
*e
, void __user
**dstptr
,
1430 unsigned int *size
, struct xt_counters
*counters
,
1433 struct ip6t_entry_target
*t
;
1434 struct compat_ip6t_entry __user
*ce
;
1435 u_int16_t target_offset
, next_offset
;
1436 compat_uint_t origsize
;
1437 const struct xt_entry_match
*ematch
;
1441 ce
= (struct compat_ip6t_entry __user
*)*dstptr
;
1442 if (copy_to_user(ce
, e
, sizeof(struct ip6t_entry
)) != 0 ||
1443 copy_to_user(&ce
->counters
, &counters
[i
],
1444 sizeof(counters
[i
])) != 0)
1447 *dstptr
+= sizeof(struct compat_ip6t_entry
);
1448 *size
-= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1450 xt_ematch_foreach(ematch
, e
) {
1451 ret
= xt_compat_match_to_user(ematch
, dstptr
, size
);
1455 target_offset
= e
->target_offset
- (origsize
- *size
);
1456 t
= ip6t_get_target(e
);
1457 ret
= xt_compat_target_to_user(t
, dstptr
, size
);
1460 next_offset
= e
->next_offset
- (origsize
- *size
);
1461 if (put_user(target_offset
, &ce
->target_offset
) != 0 ||
1462 put_user(next_offset
, &ce
->next_offset
) != 0)
1468 compat_find_calc_match(struct ip6t_entry_match
*m
,
1470 const struct ip6t_ip6
*ipv6
,
1471 unsigned int hookmask
,
1474 struct xt_match
*match
;
1476 match
= xt_request_find_match(NFPROTO_IPV6
, m
->u
.user
.name
,
1477 m
->u
.user
.revision
);
1478 if (IS_ERR(match
)) {
1479 duprintf("compat_check_calc_match: `%s' not found\n",
1481 return PTR_ERR(match
);
1483 m
->u
.kernel
.match
= match
;
1484 *size
+= xt_compat_match_offset(match
);
1488 static void compat_release_entry(struct compat_ip6t_entry
*e
)
1490 struct ip6t_entry_target
*t
;
1491 struct xt_entry_match
*ematch
;
1493 /* Cleanup all matches */
1494 xt_ematch_foreach(ematch
, e
)
1495 module_put(ematch
->u
.kernel
.match
->me
);
1496 t
= compat_ip6t_get_target(e
);
1497 module_put(t
->u
.kernel
.target
->me
);
1501 check_compat_entry_size_and_hooks(struct compat_ip6t_entry
*e
,
1502 struct xt_table_info
*newinfo
,
1504 const unsigned char *base
,
1505 const unsigned char *limit
,
1506 const unsigned int *hook_entries
,
1507 const unsigned int *underflows
,
1510 struct xt_entry_match
*ematch
;
1511 struct ip6t_entry_target
*t
;
1512 struct xt_target
*target
;
1513 unsigned int entry_offset
;
1517 duprintf("check_compat_entry_size_and_hooks %p\n", e
);
1518 if ((unsigned long)e
% __alignof__(struct compat_ip6t_entry
) != 0 ||
1519 (unsigned char *)e
+ sizeof(struct compat_ip6t_entry
) >= limit
) {
1520 duprintf("Bad offset %p, limit = %p\n", e
, limit
);
1524 if (e
->next_offset
< sizeof(struct compat_ip6t_entry
) +
1525 sizeof(struct compat_xt_entry_target
)) {
1526 duprintf("checking: element %p size %u\n",
1531 /* For purposes of check_entry casting the compat entry is fine */
1532 ret
= check_entry((struct ip6t_entry
*)e
, name
);
1536 off
= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1537 entry_offset
= (void *)e
- (void *)base
;
1539 xt_ematch_foreach(ematch
, e
) {
1540 ret
= compat_find_calc_match(ematch
, name
,
1541 &e
->ipv6
, e
->comefrom
, &off
);
1543 goto release_matches
;
1547 t
= compat_ip6t_get_target(e
);
1548 target
= xt_request_find_target(NFPROTO_IPV6
, t
->u
.user
.name
,
1549 t
->u
.user
.revision
);
1550 if (IS_ERR(target
)) {
1551 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1553 ret
= PTR_ERR(target
);
1554 goto release_matches
;
1556 t
->u
.kernel
.target
= target
;
1558 off
+= xt_compat_target_offset(target
);
1560 ret
= xt_compat_add_offset(AF_INET6
, entry_offset
, off
);
1564 /* Check hooks & underflows */
1565 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
1566 if ((unsigned char *)e
- base
== hook_entries
[h
])
1567 newinfo
->hook_entry
[h
] = hook_entries
[h
];
1568 if ((unsigned char *)e
- base
== underflows
[h
])
1569 newinfo
->underflow
[h
] = underflows
[h
];
1572 /* Clear counters and comefrom */
1573 memset(&e
->counters
, 0, sizeof(e
->counters
));
1578 module_put(t
->u
.kernel
.target
->me
);
1580 xt_ematch_foreach(ematch
, e
) {
1583 module_put(ematch
->u
.kernel
.match
->me
);
1589 compat_copy_entry_from_user(struct compat_ip6t_entry
*e
, void **dstptr
,
1590 unsigned int *size
, const char *name
,
1591 struct xt_table_info
*newinfo
, unsigned char *base
)
1593 struct ip6t_entry_target
*t
;
1594 struct xt_target
*target
;
1595 struct ip6t_entry
*de
;
1596 unsigned int origsize
;
1598 struct xt_entry_match
*ematch
;
1602 de
= (struct ip6t_entry
*)*dstptr
;
1603 memcpy(de
, e
, sizeof(struct ip6t_entry
));
1604 memcpy(&de
->counters
, &e
->counters
, sizeof(e
->counters
));
1606 *dstptr
+= sizeof(struct ip6t_entry
);
1607 *size
+= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1609 xt_ematch_foreach(ematch
, e
) {
1610 ret
= xt_compat_match_from_user(ematch
, dstptr
, size
);
1614 de
->target_offset
= e
->target_offset
- (origsize
- *size
);
1615 t
= compat_ip6t_get_target(e
);
1616 target
= t
->u
.kernel
.target
;
1617 xt_compat_target_from_user(t
, dstptr
, size
);
1619 de
->next_offset
= e
->next_offset
- (origsize
- *size
);
1620 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
1621 if ((unsigned char *)de
- base
< newinfo
->hook_entry
[h
])
1622 newinfo
->hook_entry
[h
] -= origsize
- *size
;
1623 if ((unsigned char *)de
- base
< newinfo
->underflow
[h
])
1624 newinfo
->underflow
[h
] -= origsize
- *size
;
1629 static int compat_check_entry(struct ip6t_entry
*e
, struct net
*net
,
1634 struct xt_mtchk_param mtpar
;
1635 struct xt_entry_match
*ematch
;
1640 mtpar
.entryinfo
= &e
->ipv6
;
1641 mtpar
.hook_mask
= e
->comefrom
;
1642 mtpar
.family
= NFPROTO_IPV6
;
1643 xt_ematch_foreach(ematch
, e
) {
1644 ret
= check_match(ematch
, &mtpar
);
1646 goto cleanup_matches
;
1650 ret
= check_target(e
, net
, name
);
1652 goto cleanup_matches
;
1656 xt_ematch_foreach(ematch
, e
) {
1659 cleanup_match(ematch
, net
);
1665 translate_compat_table(struct net
*net
,
1667 unsigned int valid_hooks
,
1668 struct xt_table_info
**pinfo
,
1670 unsigned int total_size
,
1671 unsigned int number
,
1672 unsigned int *hook_entries
,
1673 unsigned int *underflows
)
1676 struct xt_table_info
*newinfo
, *info
;
1677 void *pos
, *entry0
, *entry1
;
1678 struct compat_ip6t_entry
*iter0
;
1679 struct ip6t_entry
*iter1
;
1686 info
->number
= number
;
1688 /* Init all hooks to impossible value. */
1689 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1690 info
->hook_entry
[i
] = 0xFFFFFFFF;
1691 info
->underflow
[i
] = 0xFFFFFFFF;
1694 duprintf("translate_compat_table: size %u\n", info
->size
);
1696 xt_compat_lock(AF_INET6
);
1697 /* Walk through entries, checking offsets. */
1698 xt_entry_foreach(iter0
, entry0
, total_size
) {
1699 ret
= check_compat_entry_size_and_hooks(iter0
, info
, &size
,
1701 entry0
+ total_size
,
1712 duprintf("translate_compat_table: %u not %u entries\n",
1717 /* Check hooks all assigned */
1718 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1719 /* Only hooks which are valid */
1720 if (!(valid_hooks
& (1 << i
)))
1722 if (info
->hook_entry
[i
] == 0xFFFFFFFF) {
1723 duprintf("Invalid hook entry %u %u\n",
1724 i
, hook_entries
[i
]);
1727 if (info
->underflow
[i
] == 0xFFFFFFFF) {
1728 duprintf("Invalid underflow %u %u\n",
1735 newinfo
= xt_alloc_table_info(size
);
1739 newinfo
->number
= number
;
1740 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1741 newinfo
->hook_entry
[i
] = info
->hook_entry
[i
];
1742 newinfo
->underflow
[i
] = info
->underflow
[i
];
1744 entry1
= newinfo
->entries
[raw_smp_processor_id()];
1747 xt_entry_foreach(iter0
, entry0
, total_size
) {
1748 ret
= compat_copy_entry_from_user(iter0
, &pos
, &size
,
1749 name
, newinfo
, entry1
);
1753 xt_compat_flush_offsets(AF_INET6
);
1754 xt_compat_unlock(AF_INET6
);
1759 if (!mark_source_chains(newinfo
, valid_hooks
, entry1
))
1763 xt_entry_foreach(iter1
, entry1
, newinfo
->size
) {
1764 ret
= compat_check_entry(iter1
, net
, name
);
1771 * The first i matches need cleanup_entry (calls ->destroy)
1772 * because they had called ->check already. The other j-i
1773 * entries need only release.
1777 xt_entry_foreach(iter0
, entry0
, newinfo
->size
) {
1782 compat_release_entry(iter0
);
1784 xt_entry_foreach(iter1
, entry1
, newinfo
->size
) {
1787 cleanup_entry(iter1
, net
);
1789 xt_free_table_info(newinfo
);
1793 /* And one copy for every other CPU */
1794 for_each_possible_cpu(i
)
1795 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry1
)
1796 memcpy(newinfo
->entries
[i
], entry1
, newinfo
->size
);
1800 xt_free_table_info(info
);
1804 xt_free_table_info(newinfo
);
1806 xt_entry_foreach(iter0
, entry0
, total_size
) {
1809 compat_release_entry(iter0
);
1813 xt_compat_flush_offsets(AF_INET6
);
1814 xt_compat_unlock(AF_INET6
);
1819 compat_do_replace(struct net
*net
, void __user
*user
, unsigned int len
)
1822 struct compat_ip6t_replace tmp
;
1823 struct xt_table_info
*newinfo
;
1824 void *loc_cpu_entry
;
1825 struct ip6t_entry
*iter
;
1827 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1830 /* overflow check */
1831 if (tmp
.size
>= INT_MAX
/ num_possible_cpus())
1833 if (tmp
.num_counters
>= INT_MAX
/ sizeof(struct xt_counters
))
1836 newinfo
= xt_alloc_table_info(tmp
.size
);
1840 /* choose the copy that is on our node/cpu */
1841 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
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 (!capable(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
[IP6T_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;
1912 const void *loc_cpu_entry
;
1914 struct ip6t_entry
*iter
;
1916 counters
= alloc_counters(table
);
1917 if (IS_ERR(counters
))
1918 return PTR_ERR(counters
);
1920 /* choose the copy that is on our node/cpu, ...
1921 * This choice is lazy (because current thread is
1922 * allowed to migrate to another cpu)
1924 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
1927 xt_entry_foreach(iter
, loc_cpu_entry
, total_size
) {
1928 ret
= compat_copy_entry_to_user(iter
, &pos
,
1929 &size
, counters
, i
++);
1939 compat_get_entries(struct net
*net
, struct compat_ip6t_get_entries __user
*uptr
,
1943 struct compat_ip6t_get_entries get
;
1946 if (*len
< sizeof(get
)) {
1947 duprintf("compat_get_entries: %u < %zu\n", *len
, sizeof(get
));
1951 if (copy_from_user(&get
, uptr
, sizeof(get
)) != 0)
1954 if (*len
!= sizeof(struct compat_ip6t_get_entries
) + get
.size
) {
1955 duprintf("compat_get_entries: %u != %zu\n",
1956 *len
, sizeof(get
) + get
.size
);
1960 xt_compat_lock(AF_INET6
);
1961 t
= xt_find_table_lock(net
, AF_INET6
, get
.name
);
1962 if (t
&& !IS_ERR(t
)) {
1963 const struct xt_table_info
*private = t
->private;
1964 struct xt_table_info info
;
1965 duprintf("t->private->number = %u\n", private->number
);
1966 ret
= compat_table_info(private, &info
);
1967 if (!ret
&& get
.size
== info
.size
) {
1968 ret
= compat_copy_entries_to_user(private->size
,
1969 t
, uptr
->entrytable
);
1971 duprintf("compat_get_entries: I've got %u not %u!\n",
1972 private->size
, get
.size
);
1975 xt_compat_flush_offsets(AF_INET6
);
1979 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1981 xt_compat_unlock(AF_INET6
);
1985 static int do_ip6t_get_ctl(struct sock
*, int, void __user
*, int *);
1988 compat_do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1992 if (!capable(CAP_NET_ADMIN
))
1996 case IP6T_SO_GET_INFO
:
1997 ret
= get_info(sock_net(sk
), user
, len
, 1);
1999 case IP6T_SO_GET_ENTRIES
:
2000 ret
= compat_get_entries(sock_net(sk
), user
, len
);
2003 ret
= do_ip6t_get_ctl(sk
, cmd
, user
, len
);
2010 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
2014 if (!capable(CAP_NET_ADMIN
))
2018 case IP6T_SO_SET_REPLACE
:
2019 ret
= do_replace(sock_net(sk
), user
, len
);
2022 case IP6T_SO_SET_ADD_COUNTERS
:
2023 ret
= do_add_counters(sock_net(sk
), user
, len
, 0);
2027 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
2035 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
2039 if (!capable(CAP_NET_ADMIN
))
2043 case IP6T_SO_GET_INFO
:
2044 ret
= get_info(sock_net(sk
), user
, len
, 0);
2047 case IP6T_SO_GET_ENTRIES
:
2048 ret
= get_entries(sock_net(sk
), user
, len
);
2051 case IP6T_SO_GET_REVISION_MATCH
:
2052 case IP6T_SO_GET_REVISION_TARGET
: {
2053 struct ip6t_get_revision rev
;
2056 if (*len
!= sizeof(rev
)) {
2060 if (copy_from_user(&rev
, user
, sizeof(rev
)) != 0) {
2065 if (cmd
== IP6T_SO_GET_REVISION_TARGET
)
2070 try_then_request_module(xt_find_revision(AF_INET6
, rev
.name
,
2073 "ip6t_%s", rev
.name
);
2078 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
2085 struct xt_table
*ip6t_register_table(struct net
*net
,
2086 const struct xt_table
*table
,
2087 const struct ip6t_replace
*repl
)
2090 struct xt_table_info
*newinfo
;
2091 struct xt_table_info bootstrap
= {0};
2092 void *loc_cpu_entry
;
2093 struct xt_table
*new_table
;
2095 newinfo
= xt_alloc_table_info(repl
->size
);
2101 /* choose the copy on our node/cpu, but dont care about preemption */
2102 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
2103 memcpy(loc_cpu_entry
, repl
->entries
, repl
->size
);
2105 ret
= translate_table(net
, newinfo
, loc_cpu_entry
, repl
);
2109 new_table
= xt_register_table(net
, table
, &bootstrap
, newinfo
);
2110 if (IS_ERR(new_table
)) {
2111 ret
= PTR_ERR(new_table
);
2117 xt_free_table_info(newinfo
);
2119 return ERR_PTR(ret
);
2122 void ip6t_unregister_table(struct net
*net
, struct xt_table
*table
)
2124 struct xt_table_info
*private;
2125 void *loc_cpu_entry
;
2126 struct module
*table_owner
= table
->me
;
2127 struct ip6t_entry
*iter
;
2129 private = xt_unregister_table(table
);
2131 /* Decrease module usage counts and free resources */
2132 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
2133 xt_entry_foreach(iter
, loc_cpu_entry
, private->size
)
2134 cleanup_entry(iter
, net
);
2135 if (private->number
> private->initial_entries
)
2136 module_put(table_owner
);
2137 xt_free_table_info(private);
2140 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2142 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
2143 u_int8_t type
, u_int8_t code
,
2146 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
2151 icmp6_match(const struct sk_buff
*skb
, struct xt_action_param
*par
)
2153 const struct icmp6hdr
*ic
;
2154 struct icmp6hdr _icmph
;
2155 const struct ip6t_icmp
*icmpinfo
= par
->matchinfo
;
2157 /* Must not be a fragment. */
2158 if (par
->fragoff
!= 0)
2161 ic
= skb_header_pointer(skb
, par
->thoff
, sizeof(_icmph
), &_icmph
);
2163 /* We've been asked to examine this packet, and we
2164 * can't. Hence, no choice but to drop.
2166 duprintf("Dropping evil ICMP tinygram.\n");
2167 par
->hotdrop
= true;
2171 return icmp6_type_code_match(icmpinfo
->type
,
2174 ic
->icmp6_type
, ic
->icmp6_code
,
2175 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
2178 /* Called when user tries to insert an entry of this type. */
2179 static int icmp6_checkentry(const struct xt_mtchk_param
*par
)
2181 const struct ip6t_icmp
*icmpinfo
= par
->matchinfo
;
2183 /* Must specify no unknown invflags */
2184 return (icmpinfo
->invflags
& ~IP6T_ICMP_INV
) ? -EINVAL
: 0;
2187 /* The built-in targets: standard (NULL) and error. */
2188 static struct xt_target ip6t_builtin_tg
[] __read_mostly
= {
2190 .name
= IP6T_STANDARD_TARGET
,
2191 .targetsize
= sizeof(int),
2192 .family
= NFPROTO_IPV6
,
2193 #ifdef CONFIG_COMPAT
2194 .compatsize
= sizeof(compat_int_t
),
2195 .compat_from_user
= compat_standard_from_user
,
2196 .compat_to_user
= compat_standard_to_user
,
2200 .name
= IP6T_ERROR_TARGET
,
2201 .target
= ip6t_error
,
2202 .targetsize
= IP6T_FUNCTION_MAXNAMELEN
,
2203 .family
= NFPROTO_IPV6
,
2207 static struct nf_sockopt_ops ip6t_sockopts
= {
2209 .set_optmin
= IP6T_BASE_CTL
,
2210 .set_optmax
= IP6T_SO_SET_MAX
+1,
2211 .set
= do_ip6t_set_ctl
,
2212 #ifdef CONFIG_COMPAT
2213 .compat_set
= compat_do_ip6t_set_ctl
,
2215 .get_optmin
= IP6T_BASE_CTL
,
2216 .get_optmax
= IP6T_SO_GET_MAX
+1,
2217 .get
= do_ip6t_get_ctl
,
2218 #ifdef CONFIG_COMPAT
2219 .compat_get
= compat_do_ip6t_get_ctl
,
2221 .owner
= THIS_MODULE
,
2224 static struct xt_match ip6t_builtin_mt
[] __read_mostly
= {
2227 .match
= icmp6_match
,
2228 .matchsize
= sizeof(struct ip6t_icmp
),
2229 .checkentry
= icmp6_checkentry
,
2230 .proto
= IPPROTO_ICMPV6
,
2231 .family
= NFPROTO_IPV6
,
2235 static int __net_init
ip6_tables_net_init(struct net
*net
)
2237 return xt_proto_init(net
, NFPROTO_IPV6
);
2240 static void __net_exit
ip6_tables_net_exit(struct net
*net
)
2242 xt_proto_fini(net
, NFPROTO_IPV6
);
2245 static struct pernet_operations ip6_tables_net_ops
= {
2246 .init
= ip6_tables_net_init
,
2247 .exit
= ip6_tables_net_exit
,
2250 static int __init
ip6_tables_init(void)
2254 ret
= register_pernet_subsys(&ip6_tables_net_ops
);
2258 /* Noone else will be downing sem now, so we won't sleep */
2259 ret
= xt_register_targets(ip6t_builtin_tg
, ARRAY_SIZE(ip6t_builtin_tg
));
2262 ret
= xt_register_matches(ip6t_builtin_mt
, ARRAY_SIZE(ip6t_builtin_mt
));
2266 /* Register setsockopt */
2267 ret
= nf_register_sockopt(&ip6t_sockopts
);
2271 pr_info("(C) 2000-2006 Netfilter Core Team\n");
2275 xt_unregister_matches(ip6t_builtin_mt
, ARRAY_SIZE(ip6t_builtin_mt
));
2277 xt_unregister_targets(ip6t_builtin_tg
, ARRAY_SIZE(ip6t_builtin_tg
));
2279 unregister_pernet_subsys(&ip6_tables_net_ops
);
2284 static void __exit
ip6_tables_fini(void)
2286 nf_unregister_sockopt(&ip6t_sockopts
);
2288 xt_unregister_matches(ip6t_builtin_mt
, ARRAY_SIZE(ip6t_builtin_mt
));
2289 xt_unregister_targets(ip6t_builtin_tg
, ARRAY_SIZE(ip6t_builtin_tg
));
2290 unregister_pernet_subsys(&ip6_tables_net_ops
);
2294 * find the offset to specified header or the protocol number of last header
2295 * if target < 0. "last header" is transport protocol header, ESP, or
2298 * If target header is found, its offset is set in *offset and return protocol
2299 * number. Otherwise, return -1.
2301 * If the first fragment doesn't contain the final protocol header or
2302 * NEXTHDR_NONE it is considered invalid.
2304 * Note that non-1st fragment is special case that "the protocol number
2305 * of last header" is "next header" field in Fragment header. In this case,
2306 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2310 int ipv6_find_hdr(const struct sk_buff
*skb
, unsigned int *offset
,
2311 int target
, unsigned short *fragoff
)
2313 unsigned int start
= skb_network_offset(skb
) + sizeof(struct ipv6hdr
);
2314 u8 nexthdr
= ipv6_hdr(skb
)->nexthdr
;
2315 unsigned int len
= skb
->len
- start
;
2320 while (nexthdr
!= target
) {
2321 struct ipv6_opt_hdr _hdr
, *hp
;
2322 unsigned int hdrlen
;
2324 if ((!ipv6_ext_hdr(nexthdr
)) || nexthdr
== NEXTHDR_NONE
) {
2330 hp
= skb_header_pointer(skb
, start
, sizeof(_hdr
), &_hdr
);
2333 if (nexthdr
== NEXTHDR_FRAGMENT
) {
2334 unsigned short _frag_off
;
2336 fp
= skb_header_pointer(skb
,
2337 start
+offsetof(struct frag_hdr
,
2344 _frag_off
= ntohs(*fp
) & ~0x7;
2347 ((!ipv6_ext_hdr(hp
->nexthdr
)) ||
2348 hp
->nexthdr
== NEXTHDR_NONE
)) {
2350 *fragoff
= _frag_off
;
2356 } else if (nexthdr
== NEXTHDR_AUTH
)
2357 hdrlen
= (hp
->hdrlen
+ 2) << 2;
2359 hdrlen
= ipv6_optlen(hp
);
2361 nexthdr
= hp
->nexthdr
;
2370 EXPORT_SYMBOL(ip6t_register_table
);
2371 EXPORT_SYMBOL(ip6t_unregister_table
);
2372 EXPORT_SYMBOL(ip6t_do_table
);
2373 EXPORT_SYMBOL(ip6t_ext_hdr
);
2374 EXPORT_SYMBOL(ipv6_find_hdr
);
2376 module_init(ip6_tables_init
);
2377 module_exit(ip6_tables_fini
);