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>
32 MODULE_LICENSE("GPL");
33 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
34 MODULE_DESCRIPTION("IPv6 packet filter");
36 /*#define DEBUG_IP_FIREWALL*/
37 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
38 /*#define DEBUG_IP_FIREWALL_USER*/
40 #ifdef DEBUG_IP_FIREWALL
41 #define dprintf(format, args...) printk(format , ## args)
43 #define dprintf(format, args...)
46 #ifdef DEBUG_IP_FIREWALL_USER
47 #define duprintf(format, args...) printk(format , ## args)
49 #define duprintf(format, args...)
52 #ifdef CONFIG_NETFILTER_DEBUG
53 #define IP_NF_ASSERT(x) \
56 printk("IP_NF_ASSERT: %s:%s:%u\n", \
57 __FUNCTION__, __FILE__, __LINE__); \
60 #define IP_NF_ASSERT(x)
64 /* All the better to debug you with... */
70 We keep a set of rules for each CPU, so we can avoid write-locking
71 them in the softirq when updating the counters and therefore
72 only need to read-lock in the softirq; doing a write_lock_bh() in user
73 context stops packets coming through and allows user context to read
74 the counters or update the rules.
76 Hence the start of any table is given by get_table() below. */
78 /* Check for an extension */
80 ip6t_ext_hdr(u8 nexthdr
)
82 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
83 (nexthdr
== IPPROTO_ROUTING
) ||
84 (nexthdr
== IPPROTO_FRAGMENT
) ||
85 (nexthdr
== IPPROTO_ESP
) ||
86 (nexthdr
== IPPROTO_AH
) ||
87 (nexthdr
== IPPROTO_NONE
) ||
88 (nexthdr
== IPPROTO_DSTOPTS
) );
91 /* Returns whether matches rule or not. */
93 ip6_packet_match(const struct sk_buff
*skb
,
96 const struct ip6t_ip6
*ip6info
,
97 unsigned int *protoff
,
98 int *fragoff
, bool *hotdrop
)
102 const struct ipv6hdr
*ipv6
= ipv6_hdr(skb
);
104 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
106 if (FWINV(ipv6_masked_addr_cmp(&ipv6
->saddr
, &ip6info
->smsk
,
107 &ip6info
->src
), IP6T_INV_SRCIP
)
108 || FWINV(ipv6_masked_addr_cmp(&ipv6
->daddr
, &ip6info
->dmsk
,
109 &ip6info
->dst
), IP6T_INV_DSTIP
)) {
110 dprintf("Source or dest mismatch.\n");
112 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
113 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
114 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
115 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
116 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
117 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
121 /* Look for ifname matches; this should unroll nicely. */
122 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
123 ret
|= (((const unsigned long *)indev
)[i
]
124 ^ ((const unsigned long *)ip6info
->iniface
)[i
])
125 & ((const unsigned long *)ip6info
->iniface_mask
)[i
];
128 if (FWINV(ret
!= 0, IP6T_INV_VIA_IN
)) {
129 dprintf("VIA in mismatch (%s vs %s).%s\n",
130 indev
, ip6info
->iniface
,
131 ip6info
->invflags
&IP6T_INV_VIA_IN
?" (INV)":"");
135 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
136 ret
|= (((const unsigned long *)outdev
)[i
]
137 ^ ((const unsigned long *)ip6info
->outiface
)[i
])
138 & ((const unsigned long *)ip6info
->outiface_mask
)[i
];
141 if (FWINV(ret
!= 0, IP6T_INV_VIA_OUT
)) {
142 dprintf("VIA out mismatch (%s vs %s).%s\n",
143 outdev
, ip6info
->outiface
,
144 ip6info
->invflags
&IP6T_INV_VIA_OUT
?" (INV)":"");
148 /* ... might want to do something with class and flowlabel here ... */
150 /* look for the desired protocol header */
151 if((ip6info
->flags
& IP6T_F_PROTO
)) {
153 unsigned short _frag_off
;
155 protohdr
= ipv6_find_hdr(skb
, protoff
, -1, &_frag_off
);
161 *fragoff
= _frag_off
;
163 dprintf("Packet protocol %hi ?= %s%hi.\n",
165 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
168 if (ip6info
->proto
== protohdr
) {
169 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
175 /* We need match for the '-p all', too! */
176 if ((ip6info
->proto
!= 0) &&
177 !(ip6info
->invflags
& IP6T_INV_PROTO
))
183 /* should be ip6 safe */
185 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
187 if (ipv6
->flags
& ~IP6T_F_MASK
) {
188 duprintf("Unknown flag bits set: %08X\n",
189 ipv6
->flags
& ~IP6T_F_MASK
);
192 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
193 duprintf("Unknown invflag bits set: %08X\n",
194 ipv6
->invflags
& ~IP6T_INV_MASK
);
201 ip6t_error(struct sk_buff
*skb
,
202 const struct net_device
*in
,
203 const struct net_device
*out
,
204 unsigned int hooknum
,
205 const struct xt_target
*target
,
206 const void *targinfo
)
209 printk("ip6_tables: error: `%s'\n", (char *)targinfo
);
215 bool do_match(struct ip6t_entry_match
*m
,
216 const struct sk_buff
*skb
,
217 const struct net_device
*in
,
218 const struct net_device
*out
,
220 unsigned int protoff
,
223 /* Stop iteration if it doesn't match */
224 if (!m
->u
.kernel
.match
->match(skb
, in
, out
, m
->u
.kernel
.match
, m
->data
,
225 offset
, protoff
, hotdrop
))
231 static inline struct ip6t_entry
*
232 get_entry(void *base
, unsigned int offset
)
234 return (struct ip6t_entry
*)(base
+ offset
);
237 /* All zeroes == unconditional rule. */
239 unconditional(const struct ip6t_ip6
*ipv6
)
243 for (i
= 0; i
< sizeof(*ipv6
); i
++)
244 if (((char *)ipv6
)[i
])
247 return (i
== sizeof(*ipv6
));
250 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
251 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
252 /* This cries for unification! */
253 static const char *hooknames
[] = {
254 [NF_INET_PRE_ROUTING
] = "PREROUTING",
255 [NF_INET_LOCAL_IN
] = "INPUT",
256 [NF_INET_FORWARD
] = "FORWARD",
257 [NF_INET_LOCAL_OUT
] = "OUTPUT",
258 [NF_INET_POST_ROUTING
] = "POSTROUTING",
261 enum nf_ip_trace_comments
{
262 NF_IP6_TRACE_COMMENT_RULE
,
263 NF_IP6_TRACE_COMMENT_RETURN
,
264 NF_IP6_TRACE_COMMENT_POLICY
,
267 static const char *comments
[] = {
268 [NF_IP6_TRACE_COMMENT_RULE
] = "rule",
269 [NF_IP6_TRACE_COMMENT_RETURN
] = "return",
270 [NF_IP6_TRACE_COMMENT_POLICY
] = "policy",
273 static struct nf_loginfo trace_loginfo
= {
274 .type
= NF_LOG_TYPE_LOG
,
278 .logflags
= NF_LOG_MASK
,
284 get_chainname_rulenum(struct ip6t_entry
*s
, struct ip6t_entry
*e
,
285 char *hookname
, char **chainname
,
286 char **comment
, unsigned int *rulenum
)
288 struct ip6t_standard_target
*t
= (void *)ip6t_get_target(s
);
290 if (strcmp(t
->target
.u
.kernel
.target
->name
, IP6T_ERROR_TARGET
) == 0) {
291 /* Head of user chain: ERROR target with chainname */
292 *chainname
= t
->target
.data
;
297 if (s
->target_offset
== sizeof(struct ip6t_entry
)
298 && strcmp(t
->target
.u
.kernel
.target
->name
,
299 IP6T_STANDARD_TARGET
) == 0
301 && unconditional(&s
->ipv6
)) {
302 /* Tail of chains: STANDARD target (return/policy) */
303 *comment
= *chainname
== hookname
304 ? (char *)comments
[NF_IP6_TRACE_COMMENT_POLICY
]
305 : (char *)comments
[NF_IP6_TRACE_COMMENT_RETURN
];
314 static void trace_packet(struct sk_buff
*skb
,
316 const struct net_device
*in
,
317 const struct net_device
*out
,
319 struct xt_table_info
*private,
320 struct ip6t_entry
*e
)
323 struct ip6t_entry
*root
;
324 char *hookname
, *chainname
, *comment
;
325 unsigned int rulenum
= 0;
327 table_base
= (void *)private->entries
[smp_processor_id()];
328 root
= get_entry(table_base
, private->hook_entry
[hook
]);
330 hookname
= chainname
= (char *)hooknames
[hook
];
331 comment
= (char *)comments
[NF_IP6_TRACE_COMMENT_RULE
];
333 IP6T_ENTRY_ITERATE(root
,
334 private->size
- private->hook_entry
[hook
],
335 get_chainname_rulenum
,
336 e
, hookname
, &chainname
, &comment
, &rulenum
);
338 nf_log_packet(AF_INET6
, hook
, skb
, in
, out
, &trace_loginfo
,
339 "TRACE: %s:%s:%s:%u ",
340 tablename
, chainname
, comment
, rulenum
);
344 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
346 ip6t_do_table(struct sk_buff
*skb
,
348 const struct net_device
*in
,
349 const struct net_device
*out
,
350 struct xt_table
*table
)
352 static const char nulldevname
[IFNAMSIZ
] __attribute__((aligned(sizeof(long))));
354 unsigned int protoff
= 0;
355 bool hotdrop
= false;
356 /* Initializing verdict to NF_DROP keeps gcc happy. */
357 unsigned int verdict
= NF_DROP
;
358 const char *indev
, *outdev
;
360 struct ip6t_entry
*e
, *back
;
361 struct xt_table_info
*private;
364 indev
= in
? in
->name
: nulldevname
;
365 outdev
= out
? out
->name
: nulldevname
;
366 /* We handle fragments by dealing with the first fragment as
367 * if it was a normal packet. All other fragments are treated
368 * normally, except that they will NEVER match rules that ask
369 * things we don't know, ie. tcp syn flag or ports). If the
370 * rule is also a fragment-specific rule, non-fragments won't
373 read_lock_bh(&table
->lock
);
374 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
375 private = table
->private;
376 table_base
= (void *)private->entries
[smp_processor_id()];
377 e
= get_entry(table_base
, private->hook_entry
[hook
]);
379 /* For return from builtin chain */
380 back
= get_entry(table_base
, private->underflow
[hook
]);
385 if (ip6_packet_match(skb
, indev
, outdev
, &e
->ipv6
,
386 &protoff
, &offset
, &hotdrop
)) {
387 struct ip6t_entry_target
*t
;
389 if (IP6T_MATCH_ITERATE(e
, do_match
,
391 offset
, protoff
, &hotdrop
) != 0)
394 ADD_COUNTER(e
->counters
,
395 ntohs(ipv6_hdr(skb
)->payload_len
) +
396 sizeof(struct ipv6hdr
), 1);
398 t
= ip6t_get_target(e
);
399 IP_NF_ASSERT(t
->u
.kernel
.target
);
401 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
402 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
403 /* The packet is traced: log it */
404 if (unlikely(skb
->nf_trace
))
405 trace_packet(skb
, hook
, in
, out
,
406 table
->name
, private, e
);
408 /* Standard target? */
409 if (!t
->u
.kernel
.target
->target
) {
412 v
= ((struct ip6t_standard_target
*)t
)->verdict
;
414 /* Pop from stack? */
415 if (v
!= IP6T_RETURN
) {
416 verdict
= (unsigned)(-v
) - 1;
420 back
= get_entry(table_base
,
424 if (table_base
+ v
!= (void *)e
+ e
->next_offset
425 && !(e
->ipv6
.flags
& IP6T_F_GOTO
)) {
426 /* Save old back ptr in next entry */
427 struct ip6t_entry
*next
428 = (void *)e
+ e
->next_offset
;
430 = (void *)back
- table_base
;
431 /* set back pointer to next entry */
435 e
= get_entry(table_base
, v
);
437 /* Targets which reenter must return
439 #ifdef CONFIG_NETFILTER_DEBUG
440 ((struct ip6t_entry
*)table_base
)->comefrom
443 verdict
= t
->u
.kernel
.target
->target(skb
,
449 #ifdef CONFIG_NETFILTER_DEBUG
450 if (((struct ip6t_entry
*)table_base
)->comefrom
452 && verdict
== IP6T_CONTINUE
) {
453 printk("Target %s reentered!\n",
454 t
->u
.kernel
.target
->name
);
457 ((struct ip6t_entry
*)table_base
)->comefrom
460 if (verdict
== IP6T_CONTINUE
)
461 e
= (void *)e
+ e
->next_offset
;
469 e
= (void *)e
+ e
->next_offset
;
473 #ifdef CONFIG_NETFILTER_DEBUG
474 ((struct ip6t_entry
*)table_base
)->comefrom
= NETFILTER_LINK_POISON
;
476 read_unlock_bh(&table
->lock
);
478 #ifdef DEBUG_ALLOW_ALL
487 /* Figures out from what hook each rule can be called: returns 0 if
488 there are loops. Puts hook bitmask in comefrom. */
490 mark_source_chains(struct xt_table_info
*newinfo
,
491 unsigned int valid_hooks
, void *entry0
)
495 /* No recursion; use packet counter to save back ptrs (reset
496 to 0 as we leave), and comefrom to save source hook bitmask */
497 for (hook
= 0; hook
< NF_INET_NUMHOOKS
; hook
++) {
498 unsigned int pos
= newinfo
->hook_entry
[hook
];
499 struct ip6t_entry
*e
= (struct ip6t_entry
*)(entry0
+ pos
);
501 if (!(valid_hooks
& (1 << hook
)))
504 /* Set initial back pointer. */
505 e
->counters
.pcnt
= pos
;
508 struct ip6t_standard_target
*t
509 = (void *)ip6t_get_target(e
);
510 int visited
= e
->comefrom
& (1 << hook
);
512 if (e
->comefrom
& (1 << NF_INET_NUMHOOKS
)) {
513 printk("iptables: loop hook %u pos %u %08X.\n",
514 hook
, pos
, e
->comefrom
);
517 e
->comefrom
|= ((1 << hook
) | (1 << NF_INET_NUMHOOKS
));
519 /* Unconditional return/END. */
520 if ((e
->target_offset
== sizeof(struct ip6t_entry
)
521 && (strcmp(t
->target
.u
.user
.name
,
522 IP6T_STANDARD_TARGET
) == 0)
524 && unconditional(&e
->ipv6
)) || visited
) {
525 unsigned int oldpos
, size
;
527 if (t
->verdict
< -NF_MAX_VERDICT
- 1) {
528 duprintf("mark_source_chains: bad "
529 "negative verdict (%i)\n",
534 /* Return: backtrack through the last
537 e
->comefrom
^= (1<<NF_INET_NUMHOOKS
);
538 #ifdef DEBUG_IP_FIREWALL_USER
540 & (1 << NF_INET_NUMHOOKS
)) {
541 duprintf("Back unset "
548 pos
= e
->counters
.pcnt
;
549 e
->counters
.pcnt
= 0;
551 /* We're at the start. */
555 e
= (struct ip6t_entry
*)
557 } while (oldpos
== pos
+ e
->next_offset
);
560 size
= e
->next_offset
;
561 e
= (struct ip6t_entry
*)
562 (entry0
+ pos
+ size
);
563 e
->counters
.pcnt
= pos
;
566 int newpos
= t
->verdict
;
568 if (strcmp(t
->target
.u
.user
.name
,
569 IP6T_STANDARD_TARGET
) == 0
571 if (newpos
> newinfo
->size
-
572 sizeof(struct ip6t_entry
)) {
573 duprintf("mark_source_chains: "
574 "bad verdict (%i)\n",
578 /* This a jump; chase it. */
579 duprintf("Jump rule %u -> %u\n",
582 /* ... this is a fallthru */
583 newpos
= pos
+ e
->next_offset
;
585 e
= (struct ip6t_entry
*)
587 e
->counters
.pcnt
= pos
;
592 duprintf("Finished chain %u\n", hook
);
598 cleanup_match(struct ip6t_entry_match
*m
, unsigned int *i
)
600 if (i
&& (*i
)-- == 0)
603 if (m
->u
.kernel
.match
->destroy
)
604 m
->u
.kernel
.match
->destroy(m
->u
.kernel
.match
, m
->data
);
605 module_put(m
->u
.kernel
.match
->me
);
610 check_entry(struct ip6t_entry
*e
, const char *name
)
612 struct ip6t_entry_target
*t
;
614 if (!ip6_checkentry(&e
->ipv6
)) {
615 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
619 if (e
->target_offset
+ sizeof(struct ip6t_entry_target
) >
623 t
= ip6t_get_target(e
);
624 if (e
->target_offset
+ t
->u
.target_size
> e
->next_offset
)
630 static inline int check_match(struct ip6t_entry_match
*m
, const char *name
,
631 const struct ip6t_ip6
*ipv6
,
632 unsigned int hookmask
, unsigned int *i
)
634 struct xt_match
*match
;
637 match
= m
->u
.kernel
.match
;
638 ret
= xt_check_match(match
, AF_INET6
, m
->u
.match_size
- sizeof(*m
),
639 name
, hookmask
, ipv6
->proto
,
640 ipv6
->invflags
& IP6T_INV_PROTO
);
641 if (!ret
&& m
->u
.kernel
.match
->checkentry
642 && !m
->u
.kernel
.match
->checkentry(name
, ipv6
, match
, m
->data
,
644 duprintf("ip_tables: check failed for `%s'.\n",
645 m
->u
.kernel
.match
->name
);
654 find_check_match(struct ip6t_entry_match
*m
,
656 const struct ip6t_ip6
*ipv6
,
657 unsigned int hookmask
,
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
, name
, ipv6
, hookmask
, i
);
678 module_put(m
->u
.kernel
.match
->me
);
682 static inline int check_target(struct ip6t_entry
*e
, const char *name
)
684 struct ip6t_entry_target
*t
;
685 struct xt_target
*target
;
688 t
= ip6t_get_target(e
);
689 target
= t
->u
.kernel
.target
;
690 ret
= xt_check_target(target
, AF_INET6
, t
->u
.target_size
- sizeof(*t
),
691 name
, e
->comefrom
, e
->ipv6
.proto
,
692 e
->ipv6
.invflags
& IP6T_INV_PROTO
);
693 if (!ret
&& t
->u
.kernel
.target
->checkentry
694 && !t
->u
.kernel
.target
->checkentry(name
, e
, target
, t
->data
,
696 duprintf("ip_tables: check failed for `%s'.\n",
697 t
->u
.kernel
.target
->name
);
704 find_check_entry(struct ip6t_entry
*e
, const char *name
, unsigned int size
,
707 struct ip6t_entry_target
*t
;
708 struct xt_target
*target
;
712 ret
= check_entry(e
, name
);
717 ret
= IP6T_MATCH_ITERATE(e
, find_check_match
, name
, &e
->ipv6
,
720 goto cleanup_matches
;
722 t
= ip6t_get_target(e
);
723 target
= try_then_request_module(xt_find_target(AF_INET6
,
726 "ip6t_%s", t
->u
.user
.name
);
727 if (IS_ERR(target
) || !target
) {
728 duprintf("find_check_entry: `%s' not found\n", t
->u
.user
.name
);
729 ret
= target
? PTR_ERR(target
) : -ENOENT
;
730 goto cleanup_matches
;
732 t
->u
.kernel
.target
= target
;
734 ret
= check_target(e
, name
);
741 module_put(t
->u
.kernel
.target
->me
);
743 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
748 check_entry_size_and_hooks(struct ip6t_entry
*e
,
749 struct xt_table_info
*newinfo
,
751 unsigned char *limit
,
752 const unsigned int *hook_entries
,
753 const unsigned int *underflows
,
758 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0
759 || (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
760 duprintf("Bad offset %p\n", e
);
765 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
766 duprintf("checking: element %p size %u\n",
771 /* Check hooks & underflows */
772 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
773 if ((unsigned char *)e
- base
== hook_entries
[h
])
774 newinfo
->hook_entry
[h
] = hook_entries
[h
];
775 if ((unsigned char *)e
- base
== underflows
[h
])
776 newinfo
->underflow
[h
] = underflows
[h
];
779 /* FIXME: underflows must be unconditional, standard verdicts
780 < 0 (not IP6T_RETURN). --RR */
782 /* Clear counters and comefrom */
783 e
->counters
= ((struct xt_counters
) { 0, 0 });
791 cleanup_entry(struct ip6t_entry
*e
, unsigned int *i
)
793 struct ip6t_entry_target
*t
;
795 if (i
&& (*i
)-- == 0)
798 /* Cleanup all matches */
799 IP6T_MATCH_ITERATE(e
, cleanup_match
, NULL
);
800 t
= ip6t_get_target(e
);
801 if (t
->u
.kernel
.target
->destroy
)
802 t
->u
.kernel
.target
->destroy(t
->u
.kernel
.target
, t
->data
);
803 module_put(t
->u
.kernel
.target
->me
);
807 /* Checks and translates the user-supplied table segment (held in
810 translate_table(const char *name
,
811 unsigned int valid_hooks
,
812 struct xt_table_info
*newinfo
,
816 const unsigned int *hook_entries
,
817 const unsigned int *underflows
)
822 newinfo
->size
= size
;
823 newinfo
->number
= number
;
825 /* Init all hooks to impossible value. */
826 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
827 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
828 newinfo
->underflow
[i
] = 0xFFFFFFFF;
831 duprintf("translate_table: size %u\n", newinfo
->size
);
833 /* Walk through entries, checking offsets. */
834 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
835 check_entry_size_and_hooks
,
839 hook_entries
, underflows
, &i
);
844 duprintf("translate_table: %u not %u entries\n",
849 /* Check hooks all assigned */
850 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
851 /* Only hooks which are valid */
852 if (!(valid_hooks
& (1 << i
)))
854 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
855 duprintf("Invalid hook entry %u %u\n",
859 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
860 duprintf("Invalid underflow %u %u\n",
866 if (!mark_source_chains(newinfo
, valid_hooks
, entry0
))
869 /* Finally, each sanity check must pass */
871 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
872 find_check_entry
, name
, size
, &i
);
875 IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
880 /* And one copy for every other CPU */
881 for_each_possible_cpu(i
) {
882 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry0
)
883 memcpy(newinfo
->entries
[i
], entry0
, newinfo
->size
);
891 add_entry_to_counter(const struct ip6t_entry
*e
,
892 struct xt_counters total
[],
895 ADD_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
902 set_entry_to_counter(const struct ip6t_entry
*e
,
903 struct ip6t_counters total
[],
906 SET_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
913 get_counters(const struct xt_table_info
*t
,
914 struct xt_counters counters
[])
920 /* Instead of clearing (by a previous call to memset())
921 * the counters and using adds, we set the counters
922 * with data used by 'current' CPU
923 * We dont care about preemption here.
925 curcpu
= raw_smp_processor_id();
928 IP6T_ENTRY_ITERATE(t
->entries
[curcpu
],
930 set_entry_to_counter
,
934 for_each_possible_cpu(cpu
) {
938 IP6T_ENTRY_ITERATE(t
->entries
[cpu
],
940 add_entry_to_counter
,
946 static inline struct xt_counters
*alloc_counters(struct xt_table
*table
)
948 unsigned int countersize
;
949 struct xt_counters
*counters
;
950 struct xt_table_info
*private = table
->private;
952 /* We need atomic snapshot of counters: rest doesn't change
953 (other than comefrom, which userspace doesn't care
955 countersize
= sizeof(struct xt_counters
) * private->number
;
956 counters
= vmalloc_node(countersize
, numa_node_id());
958 if (counters
== NULL
)
959 return ERR_PTR(-ENOMEM
);
961 /* First, sum counters... */
962 write_lock_bh(&table
->lock
);
963 get_counters(private, counters
);
964 write_unlock_bh(&table
->lock
);
970 copy_entries_to_user(unsigned int total_size
,
971 struct xt_table
*table
,
972 void __user
*userptr
)
974 unsigned int off
, num
;
975 struct ip6t_entry
*e
;
976 struct xt_counters
*counters
;
977 struct xt_table_info
*private = table
->private;
981 counters
= alloc_counters(table
);
982 if (IS_ERR(counters
))
983 return PTR_ERR(counters
);
985 /* choose the copy that is on our node/cpu, ...
986 * This choice is lazy (because current thread is
987 * allowed to migrate to another cpu)
989 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
990 if (copy_to_user(userptr
, loc_cpu_entry
, total_size
) != 0) {
995 /* FIXME: use iterator macros --RR */
996 /* ... then go back and fix counters and names */
997 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
999 struct ip6t_entry_match
*m
;
1000 struct ip6t_entry_target
*t
;
1002 e
= (struct ip6t_entry
*)(loc_cpu_entry
+ off
);
1003 if (copy_to_user(userptr
+ off
1004 + offsetof(struct ip6t_entry
, counters
),
1006 sizeof(counters
[num
])) != 0) {
1011 for (i
= sizeof(struct ip6t_entry
);
1012 i
< e
->target_offset
;
1013 i
+= m
->u
.match_size
) {
1016 if (copy_to_user(userptr
+ off
+ i
1017 + offsetof(struct ip6t_entry_match
,
1019 m
->u
.kernel
.match
->name
,
1020 strlen(m
->u
.kernel
.match
->name
)+1)
1027 t
= ip6t_get_target(e
);
1028 if (copy_to_user(userptr
+ off
+ e
->target_offset
1029 + offsetof(struct ip6t_entry_target
,
1031 t
->u
.kernel
.target
->name
,
1032 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
1043 #ifdef CONFIG_COMPAT
1044 static void compat_standard_from_user(void *dst
, void *src
)
1046 int v
= *(compat_int_t
*)src
;
1049 v
+= xt_compat_calc_jump(AF_INET6
, v
);
1050 memcpy(dst
, &v
, sizeof(v
));
1053 static int compat_standard_to_user(void __user
*dst
, void *src
)
1055 compat_int_t cv
= *(int *)src
;
1058 cv
-= xt_compat_calc_jump(AF_INET6
, cv
);
1059 return copy_to_user(dst
, &cv
, sizeof(cv
)) ? -EFAULT
: 0;
1063 compat_calc_match(struct ip6t_entry_match
*m
, int *size
)
1065 *size
+= xt_compat_match_offset(m
->u
.kernel
.match
);
1069 static int compat_calc_entry(struct ip6t_entry
*e
,
1070 const struct xt_table_info
*info
,
1071 void *base
, struct xt_table_info
*newinfo
)
1073 struct ip6t_entry_target
*t
;
1074 unsigned int entry_offset
;
1077 off
= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1078 entry_offset
= (void *)e
- base
;
1079 IP6T_MATCH_ITERATE(e
, compat_calc_match
, &off
);
1080 t
= ip6t_get_target(e
);
1081 off
+= xt_compat_target_offset(t
->u
.kernel
.target
);
1082 newinfo
->size
-= off
;
1083 ret
= xt_compat_add_offset(AF_INET6
, entry_offset
, off
);
1087 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1088 if (info
->hook_entry
[i
] &&
1089 (e
< (struct ip6t_entry
*)(base
+ info
->hook_entry
[i
])))
1090 newinfo
->hook_entry
[i
] -= off
;
1091 if (info
->underflow
[i
] &&
1092 (e
< (struct ip6t_entry
*)(base
+ info
->underflow
[i
])))
1093 newinfo
->underflow
[i
] -= off
;
1098 static int compat_table_info(const struct xt_table_info
*info
,
1099 struct xt_table_info
*newinfo
)
1101 void *loc_cpu_entry
;
1103 if (!newinfo
|| !info
)
1106 /* we dont care about newinfo->entries[] */
1107 memcpy(newinfo
, info
, offsetof(struct xt_table_info
, entries
));
1108 newinfo
->initial_entries
= 0;
1109 loc_cpu_entry
= info
->entries
[raw_smp_processor_id()];
1110 return IP6T_ENTRY_ITERATE(loc_cpu_entry
, info
->size
,
1111 compat_calc_entry
, info
, loc_cpu_entry
,
1116 static int get_info(void __user
*user
, int *len
, int compat
)
1118 char name
[IP6T_TABLE_MAXNAMELEN
];
1122 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1123 duprintf("length %u != %zu\n", *len
,
1124 sizeof(struct ip6t_getinfo
));
1128 if (copy_from_user(name
, user
, sizeof(name
)) != 0)
1131 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1132 #ifdef CONFIG_COMPAT
1134 xt_compat_lock(AF_INET6
);
1136 t
= try_then_request_module(xt_find_table_lock(AF_INET6
, name
),
1137 "ip6table_%s", name
);
1138 if (t
&& !IS_ERR(t
)) {
1139 struct ip6t_getinfo info
;
1140 struct xt_table_info
*private = t
->private;
1142 #ifdef CONFIG_COMPAT
1144 struct xt_table_info tmp
;
1145 ret
= compat_table_info(private, &tmp
);
1146 xt_compat_flush_offsets(AF_INET6
);
1150 info
.valid_hooks
= t
->valid_hooks
;
1151 memcpy(info
.hook_entry
, private->hook_entry
,
1152 sizeof(info
.hook_entry
));
1153 memcpy(info
.underflow
, private->underflow
,
1154 sizeof(info
.underflow
));
1155 info
.num_entries
= private->number
;
1156 info
.size
= private->size
;
1157 strcpy(info
.name
, name
);
1159 if (copy_to_user(user
, &info
, *len
) != 0)
1167 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1168 #ifdef CONFIG_COMPAT
1170 xt_compat_unlock(AF_INET6
);
1176 get_entries(struct ip6t_get_entries __user
*uptr
, int *len
)
1179 struct ip6t_get_entries get
;
1182 if (*len
< sizeof(get
)) {
1183 duprintf("get_entries: %u < %zu\n", *len
, sizeof(get
));
1186 if (copy_from_user(&get
, uptr
, sizeof(get
)) != 0)
1188 if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1189 duprintf("get_entries: %u != %zu\n",
1190 *len
, sizeof(get
) + get
.size
);
1194 t
= xt_find_table_lock(AF_INET6
, get
.name
);
1195 if (t
&& !IS_ERR(t
)) {
1196 struct xt_table_info
*private = t
->private;
1197 duprintf("t->private->number = %u\n", private->number
);
1198 if (get
.size
== private->size
)
1199 ret
= copy_entries_to_user(private->size
,
1200 t
, uptr
->entrytable
);
1202 duprintf("get_entries: I've got %u not %u!\n",
1203 private->size
, get
.size
);
1209 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1215 __do_replace(const char *name
, unsigned int valid_hooks
,
1216 struct xt_table_info
*newinfo
, unsigned int num_counters
,
1217 void __user
*counters_ptr
)
1221 struct xt_table_info
*oldinfo
;
1222 struct xt_counters
*counters
;
1223 void *loc_cpu_old_entry
;
1226 counters
= vmalloc_node(num_counters
* sizeof(struct xt_counters
),
1233 t
= try_then_request_module(xt_find_table_lock(AF_INET6
, name
),
1234 "ip6table_%s", name
);
1235 if (!t
|| IS_ERR(t
)) {
1236 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1237 goto free_newinfo_counters_untrans
;
1241 if (valid_hooks
!= t
->valid_hooks
) {
1242 duprintf("Valid hook crap: %08X vs %08X\n",
1243 valid_hooks
, t
->valid_hooks
);
1248 oldinfo
= xt_replace_table(t
, num_counters
, newinfo
, &ret
);
1252 /* Update module usage count based on number of rules */
1253 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1254 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1255 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1256 (newinfo
->number
<= oldinfo
->initial_entries
))
1258 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1259 (newinfo
->number
<= oldinfo
->initial_entries
))
1262 /* Get the old counters. */
1263 get_counters(oldinfo
, counters
);
1264 /* Decrease module usage counts and free resource */
1265 loc_cpu_old_entry
= oldinfo
->entries
[raw_smp_processor_id()];
1266 IP6T_ENTRY_ITERATE(loc_cpu_old_entry
, oldinfo
->size
, cleanup_entry
,
1268 xt_free_table_info(oldinfo
);
1269 if (copy_to_user(counters_ptr
, counters
,
1270 sizeof(struct xt_counters
) * num_counters
) != 0)
1279 free_newinfo_counters_untrans
:
1286 do_replace(void __user
*user
, unsigned int len
)
1289 struct ip6t_replace tmp
;
1290 struct xt_table_info
*newinfo
;
1291 void *loc_cpu_entry
;
1293 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1296 /* overflow check */
1297 if (tmp
.num_counters
>= INT_MAX
/ sizeof(struct xt_counters
))
1300 newinfo
= xt_alloc_table_info(tmp
.size
);
1304 /* choose the copy that is on our node/cpu */
1305 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1306 if (copy_from_user(loc_cpu_entry
, user
+ sizeof(tmp
),
1312 ret
= translate_table(tmp
.name
, tmp
.valid_hooks
,
1313 newinfo
, loc_cpu_entry
, tmp
.size
, tmp
.num_entries
,
1314 tmp
.hook_entry
, tmp
.underflow
);
1318 duprintf("ip_tables: Translated table\n");
1320 ret
= __do_replace(tmp
.name
, tmp
.valid_hooks
, newinfo
,
1321 tmp
.num_counters
, tmp
.counters
);
1323 goto free_newinfo_untrans
;
1326 free_newinfo_untrans
:
1327 IP6T_ENTRY_ITERATE(loc_cpu_entry
, newinfo
->size
, cleanup_entry
, NULL
);
1329 xt_free_table_info(newinfo
);
1333 /* We're lazy, and add to the first CPU; overflow works its fey magic
1334 * and everything is OK. */
1336 add_counter_to_entry(struct ip6t_entry
*e
,
1337 const struct xt_counters addme
[],
1341 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1343 (long unsigned int)e
->counters
.pcnt
,
1344 (long unsigned int)e
->counters
.bcnt
,
1345 (long unsigned int)addme
[*i
].pcnt
,
1346 (long unsigned int)addme
[*i
].bcnt
);
1349 ADD_COUNTER(e
->counters
, addme
[*i
].bcnt
, addme
[*i
].pcnt
);
1356 do_add_counters(void __user
*user
, unsigned int len
, int compat
)
1359 struct xt_counters_info tmp
;
1360 struct xt_counters
*paddc
;
1361 unsigned int num_counters
;
1366 struct xt_table_info
*private;
1368 void *loc_cpu_entry
;
1369 #ifdef CONFIG_COMPAT
1370 struct compat_xt_counters_info compat_tmp
;
1374 size
= sizeof(struct compat_xt_counters_info
);
1379 size
= sizeof(struct xt_counters_info
);
1382 if (copy_from_user(ptmp
, user
, size
) != 0)
1385 #ifdef CONFIG_COMPAT
1387 num_counters
= compat_tmp
.num_counters
;
1388 name
= compat_tmp
.name
;
1392 num_counters
= tmp
.num_counters
;
1396 if (len
!= size
+ num_counters
* sizeof(struct xt_counters
))
1399 paddc
= vmalloc_node(len
- size
, numa_node_id());
1403 if (copy_from_user(paddc
, user
+ size
, len
- size
) != 0) {
1408 t
= xt_find_table_lock(AF_INET6
, name
);
1409 if (!t
|| IS_ERR(t
)) {
1410 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1414 write_lock_bh(&t
->lock
);
1415 private = t
->private;
1416 if (private->number
!= num_counters
) {
1418 goto unlock_up_free
;
1422 /* Choose the copy that is on our node */
1423 loc_cpu_entry
= private->entries
[smp_processor_id()];
1424 IP6T_ENTRY_ITERATE(loc_cpu_entry
,
1426 add_counter_to_entry
,
1430 write_unlock_bh(&t
->lock
);
1439 #ifdef CONFIG_COMPAT
1440 struct compat_ip6t_replace
{
1441 char name
[IP6T_TABLE_MAXNAMELEN
];
1445 u32 hook_entry
[NF_INET_NUMHOOKS
];
1446 u32 underflow
[NF_INET_NUMHOOKS
];
1448 compat_uptr_t counters
; /* struct ip6t_counters * */
1449 struct compat_ip6t_entry entries
[0];
1453 compat_copy_entry_to_user(struct ip6t_entry
*e
, void __user
**dstptr
,
1454 compat_uint_t
*size
, struct xt_counters
*counters
,
1457 struct ip6t_entry_target
*t
;
1458 struct compat_ip6t_entry __user
*ce
;
1459 u_int16_t target_offset
, next_offset
;
1460 compat_uint_t origsize
;
1465 ce
= (struct compat_ip6t_entry __user
*)*dstptr
;
1466 if (copy_to_user(ce
, e
, sizeof(struct ip6t_entry
)))
1469 if (copy_to_user(&ce
->counters
, &counters
[*i
], sizeof(counters
[*i
])))
1472 *dstptr
+= sizeof(struct compat_ip6t_entry
);
1473 *size
-= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1475 ret
= IP6T_MATCH_ITERATE(e
, xt_compat_match_to_user
, dstptr
, size
);
1476 target_offset
= e
->target_offset
- (origsize
- *size
);
1479 t
= ip6t_get_target(e
);
1480 ret
= xt_compat_target_to_user(t
, dstptr
, size
);
1484 next_offset
= e
->next_offset
- (origsize
- *size
);
1485 if (put_user(target_offset
, &ce
->target_offset
))
1487 if (put_user(next_offset
, &ce
->next_offset
))
1497 compat_find_calc_match(struct ip6t_entry_match
*m
,
1499 const struct ip6t_ip6
*ipv6
,
1500 unsigned int hookmask
,
1503 struct xt_match
*match
;
1505 match
= try_then_request_module(xt_find_match(AF_INET6
, m
->u
.user
.name
,
1506 m
->u
.user
.revision
),
1507 "ip6t_%s", m
->u
.user
.name
);
1508 if (IS_ERR(match
) || !match
) {
1509 duprintf("compat_check_calc_match: `%s' not found\n",
1511 return match
? PTR_ERR(match
) : -ENOENT
;
1513 m
->u
.kernel
.match
= match
;
1514 *size
+= xt_compat_match_offset(match
);
1521 compat_release_match(struct ip6t_entry_match
*m
, unsigned int *i
)
1523 if (i
&& (*i
)-- == 0)
1526 module_put(m
->u
.kernel
.match
->me
);
1531 compat_release_entry(struct compat_ip6t_entry
*e
, unsigned int *i
)
1533 struct ip6t_entry_target
*t
;
1535 if (i
&& (*i
)-- == 0)
1538 /* Cleanup all matches */
1539 COMPAT_IP6T_MATCH_ITERATE(e
, compat_release_match
, NULL
);
1540 t
= compat_ip6t_get_target(e
);
1541 module_put(t
->u
.kernel
.target
->me
);
1546 check_compat_entry_size_and_hooks(struct compat_ip6t_entry
*e
,
1547 struct xt_table_info
*newinfo
,
1549 unsigned char *base
,
1550 unsigned char *limit
,
1551 unsigned int *hook_entries
,
1552 unsigned int *underflows
,
1556 struct ip6t_entry_target
*t
;
1557 struct xt_target
*target
;
1558 unsigned int entry_offset
;
1561 duprintf("check_compat_entry_size_and_hooks %p\n", e
);
1562 if ((unsigned long)e
% __alignof__(struct compat_ip6t_entry
) != 0
1563 || (unsigned char *)e
+ sizeof(struct compat_ip6t_entry
) >= limit
) {
1564 duprintf("Bad offset %p, limit = %p\n", e
, limit
);
1568 if (e
->next_offset
< sizeof(struct compat_ip6t_entry
) +
1569 sizeof(struct compat_xt_entry_target
)) {
1570 duprintf("checking: element %p size %u\n",
1575 /* For purposes of check_entry casting the compat entry is fine */
1576 ret
= check_entry((struct ip6t_entry
*)e
, name
);
1580 off
= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1581 entry_offset
= (void *)e
- (void *)base
;
1583 ret
= COMPAT_IP6T_MATCH_ITERATE(e
, compat_find_calc_match
, name
,
1584 &e
->ipv6
, e
->comefrom
, &off
, &j
);
1586 goto release_matches
;
1588 t
= compat_ip6t_get_target(e
);
1589 target
= try_then_request_module(xt_find_target(AF_INET6
,
1591 t
->u
.user
.revision
),
1592 "ip6t_%s", t
->u
.user
.name
);
1593 if (IS_ERR(target
) || !target
) {
1594 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1596 ret
= target
? PTR_ERR(target
) : -ENOENT
;
1597 goto release_matches
;
1599 t
->u
.kernel
.target
= target
;
1601 off
+= xt_compat_target_offset(target
);
1603 ret
= xt_compat_add_offset(AF_INET6
, entry_offset
, off
);
1607 /* Check hooks & underflows */
1608 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
1609 if ((unsigned char *)e
- base
== hook_entries
[h
])
1610 newinfo
->hook_entry
[h
] = hook_entries
[h
];
1611 if ((unsigned char *)e
- base
== underflows
[h
])
1612 newinfo
->underflow
[h
] = underflows
[h
];
1615 /* Clear counters and comefrom */
1616 memset(&e
->counters
, 0, sizeof(e
->counters
));
1623 module_put(t
->u
.kernel
.target
->me
);
1625 IP6T_MATCH_ITERATE(e
, compat_release_match
, &j
);
1630 compat_copy_entry_from_user(struct compat_ip6t_entry
*e
, void **dstptr
,
1631 unsigned int *size
, const char *name
,
1632 struct xt_table_info
*newinfo
, unsigned char *base
)
1634 struct ip6t_entry_target
*t
;
1635 struct xt_target
*target
;
1636 struct ip6t_entry
*de
;
1637 unsigned int origsize
;
1642 de
= (struct ip6t_entry
*)*dstptr
;
1643 memcpy(de
, e
, sizeof(struct ip6t_entry
));
1644 memcpy(&de
->counters
, &e
->counters
, sizeof(e
->counters
));
1646 *dstptr
+= sizeof(struct ip6t_entry
);
1647 *size
+= sizeof(struct ip6t_entry
) - sizeof(struct compat_ip6t_entry
);
1649 ret
= COMPAT_IP6T_MATCH_ITERATE(e
, xt_compat_match_from_user
,
1653 de
->target_offset
= e
->target_offset
- (origsize
- *size
);
1654 t
= compat_ip6t_get_target(e
);
1655 target
= t
->u
.kernel
.target
;
1656 xt_compat_target_from_user(t
, dstptr
, size
);
1658 de
->next_offset
= e
->next_offset
- (origsize
- *size
);
1659 for (h
= 0; h
< NF_INET_NUMHOOKS
; h
++) {
1660 if ((unsigned char *)de
- base
< newinfo
->hook_entry
[h
])
1661 newinfo
->hook_entry
[h
] -= origsize
- *size
;
1662 if ((unsigned char *)de
- base
< newinfo
->underflow
[h
])
1663 newinfo
->underflow
[h
] -= origsize
- *size
;
1668 static inline int compat_check_entry(struct ip6t_entry
*e
, const char *name
,
1674 ret
= IP6T_MATCH_ITERATE(e
, check_match
, name
, &e
->ipv6
,
1677 goto cleanup_matches
;
1679 ret
= check_target(e
, name
);
1681 goto cleanup_matches
;
1687 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
1692 translate_compat_table(const char *name
,
1693 unsigned int valid_hooks
,
1694 struct xt_table_info
**pinfo
,
1696 unsigned int total_size
,
1697 unsigned int number
,
1698 unsigned int *hook_entries
,
1699 unsigned int *underflows
)
1702 struct xt_table_info
*newinfo
, *info
;
1703 void *pos
, *entry0
, *entry1
;
1710 info
->number
= number
;
1712 /* Init all hooks to impossible value. */
1713 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1714 info
->hook_entry
[i
] = 0xFFFFFFFF;
1715 info
->underflow
[i
] = 0xFFFFFFFF;
1718 duprintf("translate_compat_table: size %u\n", info
->size
);
1720 xt_compat_lock(AF_INET6
);
1721 /* Walk through entries, checking offsets. */
1722 ret
= COMPAT_IP6T_ENTRY_ITERATE(entry0
, total_size
,
1723 check_compat_entry_size_and_hooks
,
1724 info
, &size
, entry0
,
1725 entry0
+ total_size
,
1726 hook_entries
, underflows
, &j
, name
);
1732 duprintf("translate_compat_table: %u not %u entries\n",
1737 /* Check hooks all assigned */
1738 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1739 /* Only hooks which are valid */
1740 if (!(valid_hooks
& (1 << i
)))
1742 if (info
->hook_entry
[i
] == 0xFFFFFFFF) {
1743 duprintf("Invalid hook entry %u %u\n",
1744 i
, hook_entries
[i
]);
1747 if (info
->underflow
[i
] == 0xFFFFFFFF) {
1748 duprintf("Invalid underflow %u %u\n",
1755 newinfo
= xt_alloc_table_info(size
);
1759 newinfo
->number
= number
;
1760 for (i
= 0; i
< NF_INET_NUMHOOKS
; i
++) {
1761 newinfo
->hook_entry
[i
] = info
->hook_entry
[i
];
1762 newinfo
->underflow
[i
] = info
->underflow
[i
];
1764 entry1
= newinfo
->entries
[raw_smp_processor_id()];
1767 ret
= COMPAT_IP6T_ENTRY_ITERATE(entry0
, total_size
,
1768 compat_copy_entry_from_user
,
1769 &pos
, &size
, name
, newinfo
, entry1
);
1770 xt_compat_flush_offsets(AF_INET6
);
1771 xt_compat_unlock(AF_INET6
);
1776 if (!mark_source_chains(newinfo
, valid_hooks
, entry1
))
1780 ret
= IP6T_ENTRY_ITERATE(entry1
, newinfo
->size
, compat_check_entry
,
1784 COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0
, newinfo
->size
, i
,
1785 compat_release_entry
, &j
);
1786 IP6T_ENTRY_ITERATE(entry1
, newinfo
->size
, cleanup_entry
, &i
);
1787 xt_free_table_info(newinfo
);
1791 /* And one copy for every other CPU */
1792 for_each_possible_cpu(i
)
1793 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry1
)
1794 memcpy(newinfo
->entries
[i
], entry1
, newinfo
->size
);
1798 xt_free_table_info(info
);
1802 xt_free_table_info(newinfo
);
1804 COMPAT_IP6T_ENTRY_ITERATE(entry0
, total_size
, compat_release_entry
, &j
);
1807 xt_compat_flush_offsets(AF_INET6
);
1808 xt_compat_unlock(AF_INET6
);
1813 compat_do_replace(void __user
*user
, unsigned int len
)
1816 struct compat_ip6t_replace tmp
;
1817 struct xt_table_info
*newinfo
;
1818 void *loc_cpu_entry
;
1820 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1823 /* overflow check */
1824 if (tmp
.size
>= INT_MAX
/ num_possible_cpus())
1826 if (tmp
.num_counters
>= INT_MAX
/ sizeof(struct xt_counters
))
1829 newinfo
= xt_alloc_table_info(tmp
.size
);
1833 /* choose the copy that is on our node/cpu */
1834 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1835 if (copy_from_user(loc_cpu_entry
, user
+ sizeof(tmp
),
1841 ret
= translate_compat_table(tmp
.name
, tmp
.valid_hooks
,
1842 &newinfo
, &loc_cpu_entry
, tmp
.size
,
1843 tmp
.num_entries
, tmp
.hook_entry
,
1848 duprintf("compat_do_replace: Translated table\n");
1850 ret
= __do_replace(tmp
.name
, tmp
.valid_hooks
, newinfo
,
1851 tmp
.num_counters
, compat_ptr(tmp
.counters
));
1853 goto free_newinfo_untrans
;
1856 free_newinfo_untrans
:
1857 IP6T_ENTRY_ITERATE(loc_cpu_entry
, newinfo
->size
, cleanup_entry
, NULL
);
1859 xt_free_table_info(newinfo
);
1864 compat_do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
,
1869 if (!capable(CAP_NET_ADMIN
))
1873 case IP6T_SO_SET_REPLACE
:
1874 ret
= compat_do_replace(user
, len
);
1877 case IP6T_SO_SET_ADD_COUNTERS
:
1878 ret
= do_add_counters(user
, len
, 1);
1882 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
1889 struct compat_ip6t_get_entries
{
1890 char name
[IP6T_TABLE_MAXNAMELEN
];
1892 struct compat_ip6t_entry entrytable
[0];
1896 compat_copy_entries_to_user(unsigned int total_size
, struct xt_table
*table
,
1897 void __user
*userptr
)
1899 struct xt_counters
*counters
;
1900 struct xt_table_info
*private = table
->private;
1904 void *loc_cpu_entry
;
1907 counters
= alloc_counters(table
);
1908 if (IS_ERR(counters
))
1909 return PTR_ERR(counters
);
1911 /* choose the copy that is on our node/cpu, ...
1912 * This choice is lazy (because current thread is
1913 * allowed to migrate to another cpu)
1915 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
1918 ret
= IP6T_ENTRY_ITERATE(loc_cpu_entry
, total_size
,
1919 compat_copy_entry_to_user
,
1920 &pos
, &size
, counters
, &i
);
1927 compat_get_entries(struct compat_ip6t_get_entries __user
*uptr
, int *len
)
1930 struct compat_ip6t_get_entries get
;
1933 if (*len
< sizeof(get
)) {
1934 duprintf("compat_get_entries: %u < %zu\n", *len
, sizeof(get
));
1938 if (copy_from_user(&get
, uptr
, sizeof(get
)) != 0)
1941 if (*len
!= sizeof(struct compat_ip6t_get_entries
) + get
.size
) {
1942 duprintf("compat_get_entries: %u != %zu\n",
1943 *len
, sizeof(get
) + get
.size
);
1947 xt_compat_lock(AF_INET6
);
1948 t
= xt_find_table_lock(AF_INET6
, get
.name
);
1949 if (t
&& !IS_ERR(t
)) {
1950 struct xt_table_info
*private = t
->private;
1951 struct xt_table_info info
;
1952 duprintf("t->private->number = %u\n", private->number
);
1953 ret
= compat_table_info(private, &info
);
1954 if (!ret
&& get
.size
== info
.size
) {
1955 ret
= compat_copy_entries_to_user(private->size
,
1956 t
, uptr
->entrytable
);
1958 duprintf("compat_get_entries: I've got %u not %u!\n",
1959 private->size
, get
.size
);
1962 xt_compat_flush_offsets(AF_INET6
);
1966 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1968 xt_compat_unlock(AF_INET6
);
1972 static int do_ip6t_get_ctl(struct sock
*, int, void __user
*, int *);
1975 compat_do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1979 if (!capable(CAP_NET_ADMIN
))
1983 case IP6T_SO_GET_INFO
:
1984 ret
= get_info(user
, len
, 1);
1986 case IP6T_SO_GET_ENTRIES
:
1987 ret
= compat_get_entries(user
, len
);
1990 ret
= do_ip6t_get_ctl(sk
, cmd
, user
, len
);
1997 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
2001 if (!capable(CAP_NET_ADMIN
))
2005 case IP6T_SO_SET_REPLACE
:
2006 ret
= do_replace(user
, len
);
2009 case IP6T_SO_SET_ADD_COUNTERS
:
2010 ret
= do_add_counters(user
, len
, 0);
2014 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
2022 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
2026 if (!capable(CAP_NET_ADMIN
))
2030 case IP6T_SO_GET_INFO
:
2031 ret
= get_info(user
, len
, 0);
2034 case IP6T_SO_GET_ENTRIES
:
2035 ret
= get_entries(user
, len
);
2038 case IP6T_SO_GET_REVISION_MATCH
:
2039 case IP6T_SO_GET_REVISION_TARGET
: {
2040 struct ip6t_get_revision rev
;
2043 if (*len
!= sizeof(rev
)) {
2047 if (copy_from_user(&rev
, user
, sizeof(rev
)) != 0) {
2052 if (cmd
== IP6T_SO_GET_REVISION_TARGET
)
2057 try_then_request_module(xt_find_revision(AF_INET6
, rev
.name
,
2060 "ip6t_%s", rev
.name
);
2065 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
2072 int ip6t_register_table(struct xt_table
*table
, const struct ip6t_replace
*repl
)
2075 struct xt_table_info
*newinfo
;
2076 struct xt_table_info bootstrap
2077 = { 0, 0, 0, { 0 }, { 0 }, { } };
2078 void *loc_cpu_entry
;
2080 newinfo
= xt_alloc_table_info(repl
->size
);
2084 /* choose the copy on our node/cpu, but dont care about preemption */
2085 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
2086 memcpy(loc_cpu_entry
, repl
->entries
, repl
->size
);
2088 ret
= translate_table(table
->name
, table
->valid_hooks
,
2089 newinfo
, loc_cpu_entry
, repl
->size
,
2094 xt_free_table_info(newinfo
);
2098 ret
= xt_register_table(table
, &bootstrap
, newinfo
);
2100 xt_free_table_info(newinfo
);
2107 void ip6t_unregister_table(struct xt_table
*table
)
2109 struct xt_table_info
*private;
2110 void *loc_cpu_entry
;
2112 private = xt_unregister_table(table
);
2114 /* Decrease module usage counts and free resources */
2115 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
2116 IP6T_ENTRY_ITERATE(loc_cpu_entry
, private->size
, cleanup_entry
, NULL
);
2117 xt_free_table_info(private);
2120 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2122 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
2123 u_int8_t type
, u_int8_t code
,
2126 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
2131 icmp6_match(const struct sk_buff
*skb
,
2132 const struct net_device
*in
,
2133 const struct net_device
*out
,
2134 const struct xt_match
*match
,
2135 const void *matchinfo
,
2137 unsigned int protoff
,
2140 struct icmp6hdr _icmph
, *ic
;
2141 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
2143 /* Must not be a fragment. */
2147 ic
= skb_header_pointer(skb
, protoff
, sizeof(_icmph
), &_icmph
);
2149 /* We've been asked to examine this packet, and we
2150 * can't. Hence, no choice but to drop.
2152 duprintf("Dropping evil ICMP tinygram.\n");
2157 return icmp6_type_code_match(icmpinfo
->type
,
2160 ic
->icmp6_type
, ic
->icmp6_code
,
2161 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
2164 /* Called when user tries to insert an entry of this type. */
2166 icmp6_checkentry(const char *tablename
,
2168 const struct xt_match
*match
,
2170 unsigned int hook_mask
)
2172 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
2174 /* Must specify no unknown invflags */
2175 return !(icmpinfo
->invflags
& ~IP6T_ICMP_INV
);
2178 /* The built-in targets: standard (NULL) and error. */
2179 static struct xt_target ip6t_standard_target __read_mostly
= {
2180 .name
= IP6T_STANDARD_TARGET
,
2181 .targetsize
= sizeof(int),
2183 #ifdef CONFIG_COMPAT
2184 .compatsize
= sizeof(compat_int_t
),
2185 .compat_from_user
= compat_standard_from_user
,
2186 .compat_to_user
= compat_standard_to_user
,
2190 static struct xt_target ip6t_error_target __read_mostly
= {
2191 .name
= IP6T_ERROR_TARGET
,
2192 .target
= ip6t_error
,
2193 .targetsize
= IP6T_FUNCTION_MAXNAMELEN
,
2197 static struct nf_sockopt_ops ip6t_sockopts
= {
2199 .set_optmin
= IP6T_BASE_CTL
,
2200 .set_optmax
= IP6T_SO_SET_MAX
+1,
2201 .set
= do_ip6t_set_ctl
,
2202 #ifdef CONFIG_COMPAT
2203 .compat_set
= compat_do_ip6t_set_ctl
,
2205 .get_optmin
= IP6T_BASE_CTL
,
2206 .get_optmax
= IP6T_SO_GET_MAX
+1,
2207 .get
= do_ip6t_get_ctl
,
2208 #ifdef CONFIG_COMPAT
2209 .compat_get
= compat_do_ip6t_get_ctl
,
2211 .owner
= THIS_MODULE
,
2214 static struct xt_match icmp6_matchstruct __read_mostly
= {
2216 .match
= icmp6_match
,
2217 .matchsize
= sizeof(struct ip6t_icmp
),
2218 .checkentry
= icmp6_checkentry
,
2219 .proto
= IPPROTO_ICMPV6
,
2223 static int __init
ip6_tables_init(void)
2227 ret
= xt_proto_init(AF_INET6
);
2231 /* Noone else will be downing sem now, so we won't sleep */
2232 ret
= xt_register_target(&ip6t_standard_target
);
2235 ret
= xt_register_target(&ip6t_error_target
);
2238 ret
= xt_register_match(&icmp6_matchstruct
);
2242 /* Register setsockopt */
2243 ret
= nf_register_sockopt(&ip6t_sockopts
);
2247 printk(KERN_INFO
"ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
2251 xt_unregister_match(&icmp6_matchstruct
);
2253 xt_unregister_target(&ip6t_error_target
);
2255 xt_unregister_target(&ip6t_standard_target
);
2257 xt_proto_fini(AF_INET6
);
2262 static void __exit
ip6_tables_fini(void)
2264 nf_unregister_sockopt(&ip6t_sockopts
);
2266 xt_unregister_match(&icmp6_matchstruct
);
2267 xt_unregister_target(&ip6t_error_target
);
2268 xt_unregister_target(&ip6t_standard_target
);
2269 xt_proto_fini(AF_INET6
);
2273 * find the offset to specified header or the protocol number of last header
2274 * if target < 0. "last header" is transport protocol header, ESP, or
2277 * If target header is found, its offset is set in *offset and return protocol
2278 * number. Otherwise, return -1.
2280 * If the first fragment doesn't contain the final protocol header or
2281 * NEXTHDR_NONE it is considered invalid.
2283 * Note that non-1st fragment is special case that "the protocol number
2284 * of last header" is "next header" field in Fragment header. In this case,
2285 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2289 int ipv6_find_hdr(const struct sk_buff
*skb
, unsigned int *offset
,
2290 int target
, unsigned short *fragoff
)
2292 unsigned int start
= skb_network_offset(skb
) + sizeof(struct ipv6hdr
);
2293 u8 nexthdr
= ipv6_hdr(skb
)->nexthdr
;
2294 unsigned int len
= skb
->len
- start
;
2299 while (nexthdr
!= target
) {
2300 struct ipv6_opt_hdr _hdr
, *hp
;
2301 unsigned int hdrlen
;
2303 if ((!ipv6_ext_hdr(nexthdr
)) || nexthdr
== NEXTHDR_NONE
) {
2309 hp
= skb_header_pointer(skb
, start
, sizeof(_hdr
), &_hdr
);
2312 if (nexthdr
== NEXTHDR_FRAGMENT
) {
2313 unsigned short _frag_off
;
2315 fp
= skb_header_pointer(skb
,
2316 start
+offsetof(struct frag_hdr
,
2323 _frag_off
= ntohs(*fp
) & ~0x7;
2326 ((!ipv6_ext_hdr(hp
->nexthdr
)) ||
2327 hp
->nexthdr
== NEXTHDR_NONE
)) {
2329 *fragoff
= _frag_off
;
2335 } else if (nexthdr
== NEXTHDR_AUTH
)
2336 hdrlen
= (hp
->hdrlen
+ 2) << 2;
2338 hdrlen
= ipv6_optlen(hp
);
2340 nexthdr
= hp
->nexthdr
;
2349 EXPORT_SYMBOL(ip6t_register_table
);
2350 EXPORT_SYMBOL(ip6t_unregister_table
);
2351 EXPORT_SYMBOL(ip6t_do_table
);
2352 EXPORT_SYMBOL(ip6t_ext_hdr
);
2353 EXPORT_SYMBOL(ipv6_find_hdr
);
2355 module_init(ip6_tables_init
);
2356 module_exit(ip6_tables_fini
);