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 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
16 * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
17 * - Unification of {ip,ip6}_tables into x_tables
18 * - Removed tcp and udp code, since it's not ipv6 specific
21 #include <linux/capability.h>
23 #include <linux/skbuff.h>
24 #include <linux/kmod.h>
25 #include <linux/vmalloc.h>
26 #include <linux/netdevice.h>
27 #include <linux/module.h>
28 #include <linux/poison.h>
29 #include <linux/icmpv6.h>
31 #include <asm/uaccess.h>
32 #include <linux/mutex.h>
33 #include <linux/proc_fs.h>
34 #include <linux/cpumask.h>
36 #include <linux/netfilter_ipv6/ip6_tables.h>
37 #include <linux/netfilter/x_tables.h>
39 MODULE_LICENSE("GPL");
40 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
41 MODULE_DESCRIPTION("IPv6 packet filter");
43 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
44 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
46 /*#define DEBUG_IP_FIREWALL*/
47 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
48 /*#define DEBUG_IP_FIREWALL_USER*/
50 #ifdef DEBUG_IP_FIREWALL
51 #define dprintf(format, args...) printk(format , ## args)
53 #define dprintf(format, args...)
56 #ifdef DEBUG_IP_FIREWALL_USER
57 #define duprintf(format, args...) printk(format , ## args)
59 #define duprintf(format, args...)
62 #ifdef CONFIG_NETFILTER_DEBUG
63 #define IP_NF_ASSERT(x) \
66 printk("IP_NF_ASSERT: %s:%s:%u\n", \
67 __FUNCTION__, __FILE__, __LINE__); \
70 #define IP_NF_ASSERT(x)
74 /* All the better to debug you with... */
80 We keep a set of rules for each CPU, so we can avoid write-locking
81 them in the softirq when updating the counters and therefore
82 only need to read-lock in the softirq; doing a write_lock_bh() in user
83 context stops packets coming through and allows user context to read
84 the counters or update the rules.
86 Hence the start of any table is given by get_table() below. */
89 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
90 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
91 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
94 /* Check for an extension */
96 ip6t_ext_hdr(u8 nexthdr
)
98 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
99 (nexthdr
== IPPROTO_ROUTING
) ||
100 (nexthdr
== IPPROTO_FRAGMENT
) ||
101 (nexthdr
== IPPROTO_ESP
) ||
102 (nexthdr
== IPPROTO_AH
) ||
103 (nexthdr
== IPPROTO_NONE
) ||
104 (nexthdr
== IPPROTO_DSTOPTS
) );
107 /* Returns whether matches rule or not. */
109 ip6_packet_match(const struct sk_buff
*skb
,
112 const struct ip6t_ip6
*ip6info
,
113 unsigned int *protoff
,
118 const struct ipv6hdr
*ipv6
= skb
->nh
.ipv6h
;
120 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
122 if (FWINV(ipv6_masked_addr_cmp(&ipv6
->saddr
, &ip6info
->smsk
,
123 &ip6info
->src
), IP6T_INV_SRCIP
)
124 || FWINV(ipv6_masked_addr_cmp(&ipv6
->daddr
, &ip6info
->dmsk
,
125 &ip6info
->dst
), IP6T_INV_DSTIP
)) {
126 dprintf("Source or dest mismatch.\n");
128 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
129 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
130 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
131 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
132 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
133 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
137 /* Look for ifname matches; this should unroll nicely. */
138 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
139 ret
|= (((const unsigned long *)indev
)[i
]
140 ^ ((const unsigned long *)ip6info
->iniface
)[i
])
141 & ((const unsigned long *)ip6info
->iniface_mask
)[i
];
144 if (FWINV(ret
!= 0, IP6T_INV_VIA_IN
)) {
145 dprintf("VIA in mismatch (%s vs %s).%s\n",
146 indev
, ip6info
->iniface
,
147 ip6info
->invflags
&IP6T_INV_VIA_IN
?" (INV)":"");
151 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
152 ret
|= (((const unsigned long *)outdev
)[i
]
153 ^ ((const unsigned long *)ip6info
->outiface
)[i
])
154 & ((const unsigned long *)ip6info
->outiface_mask
)[i
];
157 if (FWINV(ret
!= 0, IP6T_INV_VIA_OUT
)) {
158 dprintf("VIA out mismatch (%s vs %s).%s\n",
159 outdev
, ip6info
->outiface
,
160 ip6info
->invflags
&IP6T_INV_VIA_OUT
?" (INV)":"");
164 /* ... might want to do something with class and flowlabel here ... */
166 /* look for the desired protocol header */
167 if((ip6info
->flags
& IP6T_F_PROTO
)) {
169 unsigned short _frag_off
;
171 protohdr
= ipv6_find_hdr(skb
, protoff
, -1, &_frag_off
);
175 *fragoff
= _frag_off
;
177 dprintf("Packet protocol %hi ?= %s%hi.\n",
179 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
182 if (ip6info
->proto
== protohdr
) {
183 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
189 /* We need match for the '-p all', too! */
190 if ((ip6info
->proto
!= 0) &&
191 !(ip6info
->invflags
& IP6T_INV_PROTO
))
197 /* should be ip6 safe */
199 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
201 if (ipv6
->flags
& ~IP6T_F_MASK
) {
202 duprintf("Unknown flag bits set: %08X\n",
203 ipv6
->flags
& ~IP6T_F_MASK
);
206 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
207 duprintf("Unknown invflag bits set: %08X\n",
208 ipv6
->invflags
& ~IP6T_INV_MASK
);
215 ip6t_error(struct sk_buff
**pskb
,
216 const struct net_device
*in
,
217 const struct net_device
*out
,
218 unsigned int hooknum
,
219 const struct xt_target
*target
,
220 const void *targinfo
)
223 printk("ip6_tables: error: `%s'\n", (char *)targinfo
);
229 int do_match(struct ip6t_entry_match
*m
,
230 const struct sk_buff
*skb
,
231 const struct net_device
*in
,
232 const struct net_device
*out
,
234 unsigned int protoff
,
237 /* Stop iteration if it doesn't match */
238 if (!m
->u
.kernel
.match
->match(skb
, in
, out
, m
->u
.kernel
.match
, m
->data
,
239 offset
, protoff
, hotdrop
))
245 static inline struct ip6t_entry
*
246 get_entry(void *base
, unsigned int offset
)
248 return (struct ip6t_entry
*)(base
+ offset
);
251 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
253 ip6t_do_table(struct sk_buff
**pskb
,
255 const struct net_device
*in
,
256 const struct net_device
*out
,
257 struct xt_table
*table
)
259 static const char nulldevname
[IFNAMSIZ
] __attribute__((aligned(sizeof(long))));
261 unsigned int protoff
= 0;
263 /* Initializing verdict to NF_DROP keeps gcc happy. */
264 unsigned int verdict
= NF_DROP
;
265 const char *indev
, *outdev
;
267 struct ip6t_entry
*e
, *back
;
268 struct xt_table_info
*private;
271 indev
= in
? in
->name
: nulldevname
;
272 outdev
= out
? out
->name
: nulldevname
;
273 /* We handle fragments by dealing with the first fragment as
274 * if it was a normal packet. All other fragments are treated
275 * normally, except that they will NEVER match rules that ask
276 * things we don't know, ie. tcp syn flag or ports). If the
277 * rule is also a fragment-specific rule, non-fragments won't
280 read_lock_bh(&table
->lock
);
281 private = table
->private;
282 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
283 table_base
= (void *)private->entries
[smp_processor_id()];
284 e
= get_entry(table_base
, private->hook_entry
[hook
]);
286 /* For return from builtin chain */
287 back
= get_entry(table_base
, private->underflow
[hook
]);
292 if (ip6_packet_match(*pskb
, indev
, outdev
, &e
->ipv6
,
293 &protoff
, &offset
)) {
294 struct ip6t_entry_target
*t
;
296 if (IP6T_MATCH_ITERATE(e
, do_match
,
298 offset
, protoff
, &hotdrop
) != 0)
301 ADD_COUNTER(e
->counters
,
302 ntohs((*pskb
)->nh
.ipv6h
->payload_len
)
306 t
= ip6t_get_target(e
);
307 IP_NF_ASSERT(t
->u
.kernel
.target
);
308 /* Standard target? */
309 if (!t
->u
.kernel
.target
->target
) {
312 v
= ((struct ip6t_standard_target
*)t
)->verdict
;
314 /* Pop from stack? */
315 if (v
!= IP6T_RETURN
) {
316 verdict
= (unsigned)(-v
) - 1;
320 back
= get_entry(table_base
,
324 if (table_base
+ v
!= (void *)e
+ e
->next_offset
325 && !(e
->ipv6
.flags
& IP6T_F_GOTO
)) {
326 /* Save old back ptr in next entry */
327 struct ip6t_entry
*next
328 = (void *)e
+ e
->next_offset
;
330 = (void *)back
- table_base
;
331 /* set back pointer to next entry */
335 e
= get_entry(table_base
, v
);
337 /* Targets which reenter must return
339 #ifdef CONFIG_NETFILTER_DEBUG
340 ((struct ip6t_entry
*)table_base
)->comefrom
343 verdict
= t
->u
.kernel
.target
->target(pskb
,
349 #ifdef CONFIG_NETFILTER_DEBUG
350 if (((struct ip6t_entry
*)table_base
)->comefrom
352 && verdict
== IP6T_CONTINUE
) {
353 printk("Target %s reentered!\n",
354 t
->u
.kernel
.target
->name
);
357 ((struct ip6t_entry
*)table_base
)->comefrom
360 if (verdict
== IP6T_CONTINUE
)
361 e
= (void *)e
+ e
->next_offset
;
369 e
= (void *)e
+ e
->next_offset
;
373 #ifdef CONFIG_NETFILTER_DEBUG
374 ((struct ip6t_entry
*)table_base
)->comefrom
= NETFILTER_LINK_POISON
;
376 read_unlock_bh(&table
->lock
);
378 #ifdef DEBUG_ALLOW_ALL
387 /* All zeroes == unconditional rule. */
389 unconditional(const struct ip6t_ip6
*ipv6
)
393 for (i
= 0; i
< sizeof(*ipv6
); i
++)
394 if (((char *)ipv6
)[i
])
397 return (i
== sizeof(*ipv6
));
400 /* Figures out from what hook each rule can be called: returns 0 if
401 there are loops. Puts hook bitmask in comefrom. */
403 mark_source_chains(struct xt_table_info
*newinfo
,
404 unsigned int valid_hooks
, void *entry0
)
408 /* No recursion; use packet counter to save back ptrs (reset
409 to 0 as we leave), and comefrom to save source hook bitmask */
410 for (hook
= 0; hook
< NF_IP6_NUMHOOKS
; hook
++) {
411 unsigned int pos
= newinfo
->hook_entry
[hook
];
413 = (struct ip6t_entry
*)(entry0
+ pos
);
415 if (!(valid_hooks
& (1 << hook
)))
418 /* Set initial back pointer. */
419 e
->counters
.pcnt
= pos
;
422 struct ip6t_standard_target
*t
423 = (void *)ip6t_get_target(e
);
425 if (e
->comefrom
& (1 << NF_IP6_NUMHOOKS
)) {
426 printk("iptables: loop hook %u pos %u %08X.\n",
427 hook
, pos
, e
->comefrom
);
431 |= ((1 << hook
) | (1 << NF_IP6_NUMHOOKS
));
433 /* Unconditional return/END. */
434 if (e
->target_offset
== sizeof(struct ip6t_entry
)
435 && (strcmp(t
->target
.u
.user
.name
,
436 IP6T_STANDARD_TARGET
) == 0)
438 && unconditional(&e
->ipv6
)) {
439 unsigned int oldpos
, size
;
441 /* Return: backtrack through the last
444 e
->comefrom
^= (1<<NF_IP6_NUMHOOKS
);
445 #ifdef DEBUG_IP_FIREWALL_USER
447 & (1 << NF_IP6_NUMHOOKS
)) {
448 duprintf("Back unset "
455 pos
= e
->counters
.pcnt
;
456 e
->counters
.pcnt
= 0;
458 /* We're at the start. */
462 e
= (struct ip6t_entry
*)
464 } while (oldpos
== pos
+ e
->next_offset
);
467 size
= e
->next_offset
;
468 e
= (struct ip6t_entry
*)
469 (entry0
+ pos
+ size
);
470 e
->counters
.pcnt
= pos
;
473 int newpos
= t
->verdict
;
475 if (strcmp(t
->target
.u
.user
.name
,
476 IP6T_STANDARD_TARGET
) == 0
478 /* This a jump; chase it. */
479 duprintf("Jump rule %u -> %u\n",
482 /* ... this is a fallthru */
483 newpos
= pos
+ e
->next_offset
;
485 e
= (struct ip6t_entry
*)
487 e
->counters
.pcnt
= pos
;
492 duprintf("Finished chain %u\n", hook
);
498 cleanup_match(struct ip6t_entry_match
*m
, unsigned int *i
)
500 if (i
&& (*i
)-- == 0)
503 if (m
->u
.kernel
.match
->destroy
)
504 m
->u
.kernel
.match
->destroy(m
->u
.kernel
.match
, m
->data
);
505 module_put(m
->u
.kernel
.match
->me
);
510 standard_check(const struct ip6t_entry_target
*t
,
511 unsigned int max_offset
)
513 struct ip6t_standard_target
*targ
= (void *)t
;
515 /* Check standard info. */
516 if (targ
->verdict
>= 0
517 && targ
->verdict
> max_offset
- sizeof(struct ip6t_entry
)) {
518 duprintf("ip6t_standard_check: bad verdict (%i)\n",
522 if (targ
->verdict
< -NF_MAX_VERDICT
- 1) {
523 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
531 check_match(struct ip6t_entry_match
*m
,
533 const struct ip6t_ip6
*ipv6
,
534 unsigned int hookmask
,
537 struct ip6t_match
*match
;
540 match
= try_then_request_module(xt_find_match(AF_INET6
, m
->u
.user
.name
,
542 "ip6t_%s", m
->u
.user
.name
);
543 if (IS_ERR(match
) || !match
) {
544 duprintf("check_match: `%s' not found\n", m
->u
.user
.name
);
545 return match
? PTR_ERR(match
) : -ENOENT
;
547 m
->u
.kernel
.match
= match
;
549 ret
= xt_check_match(match
, AF_INET6
, m
->u
.match_size
- sizeof(*m
),
550 name
, hookmask
, ipv6
->proto
,
551 ipv6
->invflags
& IP6T_INV_PROTO
);
555 if (m
->u
.kernel
.match
->checkentry
556 && !m
->u
.kernel
.match
->checkentry(name
, ipv6
, match
, m
->data
,
558 duprintf("ip_tables: check failed for `%s'.\n",
559 m
->u
.kernel
.match
->name
);
567 module_put(m
->u
.kernel
.match
->me
);
571 static struct ip6t_target ip6t_standard_target
;
574 check_entry(struct ip6t_entry
*e
, const char *name
, unsigned int size
,
577 struct ip6t_entry_target
*t
;
578 struct ip6t_target
*target
;
582 if (!ip6_checkentry(&e
->ipv6
)) {
583 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
588 ret
= IP6T_MATCH_ITERATE(e
, check_match
, name
, &e
->ipv6
, e
->comefrom
, &j
);
590 goto cleanup_matches
;
592 t
= ip6t_get_target(e
);
593 target
= try_then_request_module(xt_find_target(AF_INET6
,
596 "ip6t_%s", t
->u
.user
.name
);
597 if (IS_ERR(target
) || !target
) {
598 duprintf("check_entry: `%s' not found\n", t
->u
.user
.name
);
599 ret
= target
? PTR_ERR(target
) : -ENOENT
;
600 goto cleanup_matches
;
602 t
->u
.kernel
.target
= target
;
604 ret
= xt_check_target(target
, AF_INET6
, t
->u
.target_size
- sizeof(*t
),
605 name
, e
->comefrom
, e
->ipv6
.proto
,
606 e
->ipv6
.invflags
& IP6T_INV_PROTO
);
610 if (t
->u
.kernel
.target
== &ip6t_standard_target
) {
611 if (!standard_check(t
, size
)) {
615 } else if (t
->u
.kernel
.target
->checkentry
616 && !t
->u
.kernel
.target
->checkentry(name
, e
, target
, t
->data
,
618 duprintf("ip_tables: check failed for `%s'.\n",
619 t
->u
.kernel
.target
->name
);
627 module_put(t
->u
.kernel
.target
->me
);
629 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
634 check_entry_size_and_hooks(struct ip6t_entry
*e
,
635 struct xt_table_info
*newinfo
,
637 unsigned char *limit
,
638 const unsigned int *hook_entries
,
639 const unsigned int *underflows
,
644 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0
645 || (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
646 duprintf("Bad offset %p\n", e
);
651 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
652 duprintf("checking: element %p size %u\n",
657 /* Check hooks & underflows */
658 for (h
= 0; h
< NF_IP6_NUMHOOKS
; h
++) {
659 if ((unsigned char *)e
- base
== hook_entries
[h
])
660 newinfo
->hook_entry
[h
] = hook_entries
[h
];
661 if ((unsigned char *)e
- base
== underflows
[h
])
662 newinfo
->underflow
[h
] = underflows
[h
];
665 /* FIXME: underflows must be unconditional, standard verdicts
666 < 0 (not IP6T_RETURN). --RR */
668 /* Clear counters and comefrom */
669 e
->counters
= ((struct xt_counters
) { 0, 0 });
677 cleanup_entry(struct ip6t_entry
*e
, unsigned int *i
)
679 struct ip6t_entry_target
*t
;
681 if (i
&& (*i
)-- == 0)
684 /* Cleanup all matches */
685 IP6T_MATCH_ITERATE(e
, cleanup_match
, NULL
);
686 t
= ip6t_get_target(e
);
687 if (t
->u
.kernel
.target
->destroy
)
688 t
->u
.kernel
.target
->destroy(t
->u
.kernel
.target
, t
->data
);
689 module_put(t
->u
.kernel
.target
->me
);
693 /* Checks and translates the user-supplied table segment (held in
696 translate_table(const char *name
,
697 unsigned int valid_hooks
,
698 struct xt_table_info
*newinfo
,
702 const unsigned int *hook_entries
,
703 const unsigned int *underflows
)
708 newinfo
->size
= size
;
709 newinfo
->number
= number
;
711 /* Init all hooks to impossible value. */
712 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
713 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
714 newinfo
->underflow
[i
] = 0xFFFFFFFF;
717 duprintf("translate_table: size %u\n", newinfo
->size
);
719 /* Walk through entries, checking offsets. */
720 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
721 check_entry_size_and_hooks
,
725 hook_entries
, underflows
, &i
);
730 duprintf("translate_table: %u not %u entries\n",
735 /* Check hooks all assigned */
736 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
737 /* Only hooks which are valid */
738 if (!(valid_hooks
& (1 << i
)))
740 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
741 duprintf("Invalid hook entry %u %u\n",
745 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
746 duprintf("Invalid underflow %u %u\n",
752 if (!mark_source_chains(newinfo
, valid_hooks
, entry0
))
755 /* Finally, each sanity check must pass */
757 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
758 check_entry
, name
, size
, &i
);
761 IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
766 /* And one copy for every other CPU */
767 for_each_possible_cpu(i
) {
768 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry0
)
769 memcpy(newinfo
->entries
[i
], entry0
, newinfo
->size
);
777 add_entry_to_counter(const struct ip6t_entry
*e
,
778 struct xt_counters total
[],
781 ADD_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
788 set_entry_to_counter(const struct ip6t_entry
*e
,
789 struct ip6t_counters total
[],
792 SET_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
799 get_counters(const struct xt_table_info
*t
,
800 struct xt_counters counters
[])
806 /* Instead of clearing (by a previous call to memset())
807 * the counters and using adds, we set the counters
808 * with data used by 'current' CPU
809 * We dont care about preemption here.
811 curcpu
= raw_smp_processor_id();
814 IP6T_ENTRY_ITERATE(t
->entries
[curcpu
],
816 set_entry_to_counter
,
820 for_each_possible_cpu(cpu
) {
824 IP6T_ENTRY_ITERATE(t
->entries
[cpu
],
826 add_entry_to_counter
,
833 copy_entries_to_user(unsigned int total_size
,
834 struct xt_table
*table
,
835 void __user
*userptr
)
837 unsigned int off
, num
, countersize
;
838 struct ip6t_entry
*e
;
839 struct xt_counters
*counters
;
840 struct xt_table_info
*private = table
->private;
844 /* We need atomic snapshot of counters: rest doesn't change
845 (other than comefrom, which userspace doesn't care
847 countersize
= sizeof(struct xt_counters
) * private->number
;
848 counters
= vmalloc(countersize
);
850 if (counters
== NULL
)
853 /* First, sum counters... */
854 write_lock_bh(&table
->lock
);
855 get_counters(private, counters
);
856 write_unlock_bh(&table
->lock
);
858 /* choose the copy that is on ourc node/cpu */
859 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
860 if (copy_to_user(userptr
, loc_cpu_entry
, total_size
) != 0) {
865 /* FIXME: use iterator macros --RR */
866 /* ... then go back and fix counters and names */
867 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
869 struct ip6t_entry_match
*m
;
870 struct ip6t_entry_target
*t
;
872 e
= (struct ip6t_entry
*)(loc_cpu_entry
+ off
);
873 if (copy_to_user(userptr
+ off
874 + offsetof(struct ip6t_entry
, counters
),
876 sizeof(counters
[num
])) != 0) {
881 for (i
= sizeof(struct ip6t_entry
);
882 i
< e
->target_offset
;
883 i
+= m
->u
.match_size
) {
886 if (copy_to_user(userptr
+ off
+ i
887 + offsetof(struct ip6t_entry_match
,
889 m
->u
.kernel
.match
->name
,
890 strlen(m
->u
.kernel
.match
->name
)+1)
897 t
= ip6t_get_target(e
);
898 if (copy_to_user(userptr
+ off
+ e
->target_offset
899 + offsetof(struct ip6t_entry_target
,
901 t
->u
.kernel
.target
->name
,
902 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
914 get_entries(const struct ip6t_get_entries
*entries
,
915 struct ip6t_get_entries __user
*uptr
)
920 t
= xt_find_table_lock(AF_INET6
, entries
->name
);
921 if (t
&& !IS_ERR(t
)) {
922 struct xt_table_info
*private = t
->private;
923 duprintf("t->private->number = %u\n", private->number
);
924 if (entries
->size
== private->size
)
925 ret
= copy_entries_to_user(private->size
,
926 t
, uptr
->entrytable
);
928 duprintf("get_entries: I've got %u not %u!\n",
929 private->size
, entries
->size
);
935 ret
= t
? PTR_ERR(t
) : -ENOENT
;
941 do_replace(void __user
*user
, unsigned int len
)
944 struct ip6t_replace tmp
;
946 struct xt_table_info
*newinfo
, *oldinfo
;
947 struct xt_counters
*counters
;
948 void *loc_cpu_entry
, *loc_cpu_old_entry
;
950 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
954 if (tmp
.size
>= (INT_MAX
- sizeof(struct xt_table_info
)) / NR_CPUS
-
957 if (tmp
.num_counters
>= INT_MAX
/ sizeof(struct xt_counters
))
960 newinfo
= xt_alloc_table_info(tmp
.size
);
964 /* choose the copy that is on our node/cpu */
965 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
966 if (copy_from_user(loc_cpu_entry
, user
+ sizeof(tmp
),
972 counters
= vmalloc(tmp
.num_counters
* sizeof(struct xt_counters
));
978 ret
= translate_table(tmp
.name
, tmp
.valid_hooks
,
979 newinfo
, loc_cpu_entry
, tmp
.size
, tmp
.num_entries
,
980 tmp
.hook_entry
, tmp
.underflow
);
982 goto free_newinfo_counters
;
984 duprintf("ip_tables: Translated table\n");
986 t
= try_then_request_module(xt_find_table_lock(AF_INET6
, tmp
.name
),
987 "ip6table_%s", tmp
.name
);
988 if (!t
|| IS_ERR(t
)) {
989 ret
= t
? PTR_ERR(t
) : -ENOENT
;
990 goto free_newinfo_counters_untrans
;
994 if (tmp
.valid_hooks
!= t
->valid_hooks
) {
995 duprintf("Valid hook crap: %08X vs %08X\n",
996 tmp
.valid_hooks
, t
->valid_hooks
);
1001 oldinfo
= xt_replace_table(t
, tmp
.num_counters
, newinfo
, &ret
);
1005 /* Update module usage count based on number of rules */
1006 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1007 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1008 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1009 (newinfo
->number
<= oldinfo
->initial_entries
))
1011 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1012 (newinfo
->number
<= oldinfo
->initial_entries
))
1015 /* Get the old counters. */
1016 get_counters(oldinfo
, counters
);
1017 /* Decrease module usage counts and free resource */
1018 loc_cpu_old_entry
= oldinfo
->entries
[raw_smp_processor_id()];
1019 IP6T_ENTRY_ITERATE(loc_cpu_old_entry
, oldinfo
->size
, cleanup_entry
,NULL
);
1020 xt_free_table_info(oldinfo
);
1021 if (copy_to_user(tmp
.counters
, counters
,
1022 sizeof(struct xt_counters
) * tmp
.num_counters
) != 0)
1031 free_newinfo_counters_untrans
:
1032 IP6T_ENTRY_ITERATE(loc_cpu_entry
, newinfo
->size
, cleanup_entry
,NULL
);
1033 free_newinfo_counters
:
1036 xt_free_table_info(newinfo
);
1040 /* We're lazy, and add to the first CPU; overflow works its fey magic
1041 * and everything is OK. */
1043 add_counter_to_entry(struct ip6t_entry
*e
,
1044 const struct xt_counters addme
[],
1048 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1050 (long unsigned int)e
->counters
.pcnt
,
1051 (long unsigned int)e
->counters
.bcnt
,
1052 (long unsigned int)addme
[*i
].pcnt
,
1053 (long unsigned int)addme
[*i
].bcnt
);
1056 ADD_COUNTER(e
->counters
, addme
[*i
].bcnt
, addme
[*i
].pcnt
);
1063 do_add_counters(void __user
*user
, unsigned int len
)
1066 struct xt_counters_info tmp
, *paddc
;
1067 struct xt_table_info
*private;
1070 void *loc_cpu_entry
;
1072 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1075 if (len
!= sizeof(tmp
) + tmp
.num_counters
*sizeof(struct xt_counters
))
1078 paddc
= vmalloc(len
);
1082 if (copy_from_user(paddc
, user
, len
) != 0) {
1087 t
= xt_find_table_lock(AF_INET6
, tmp
.name
);
1088 if (!t
|| IS_ERR(t
)) {
1089 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1093 write_lock_bh(&t
->lock
);
1094 private = t
->private;
1095 if (private->number
!= tmp
.num_counters
) {
1097 goto unlock_up_free
;
1101 /* Choose the copy that is on our node */
1102 loc_cpu_entry
= private->entries
[smp_processor_id()];
1103 IP6T_ENTRY_ITERATE(loc_cpu_entry
,
1105 add_counter_to_entry
,
1109 write_unlock_bh(&t
->lock
);
1119 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
1123 if (!capable(CAP_NET_ADMIN
))
1127 case IP6T_SO_SET_REPLACE
:
1128 ret
= do_replace(user
, len
);
1131 case IP6T_SO_SET_ADD_COUNTERS
:
1132 ret
= do_add_counters(user
, len
);
1136 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
1144 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1148 if (!capable(CAP_NET_ADMIN
))
1152 case IP6T_SO_GET_INFO
: {
1153 char name
[IP6T_TABLE_MAXNAMELEN
];
1156 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1157 duprintf("length %u != %u\n", *len
,
1158 sizeof(struct ip6t_getinfo
));
1163 if (copy_from_user(name
, user
, sizeof(name
)) != 0) {
1167 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1169 t
= try_then_request_module(xt_find_table_lock(AF_INET6
, name
),
1170 "ip6table_%s", name
);
1171 if (t
&& !IS_ERR(t
)) {
1172 struct ip6t_getinfo info
;
1173 struct xt_table_info
*private = t
->private;
1175 info
.valid_hooks
= t
->valid_hooks
;
1176 memcpy(info
.hook_entry
, private->hook_entry
,
1177 sizeof(info
.hook_entry
));
1178 memcpy(info
.underflow
, private->underflow
,
1179 sizeof(info
.underflow
));
1180 info
.num_entries
= private->number
;
1181 info
.size
= private->size
;
1182 memcpy(info
.name
, name
, sizeof(info
.name
));
1184 if (copy_to_user(user
, &info
, *len
) != 0)
1191 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1195 case IP6T_SO_GET_ENTRIES
: {
1196 struct ip6t_get_entries get
;
1198 if (*len
< sizeof(get
)) {
1199 duprintf("get_entries: %u < %u\n", *len
, sizeof(get
));
1201 } else if (copy_from_user(&get
, user
, sizeof(get
)) != 0) {
1203 } else if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1204 duprintf("get_entries: %u != %u\n", *len
,
1205 sizeof(struct ip6t_get_entries
) + get
.size
);
1208 ret
= get_entries(&get
, user
);
1212 case IP6T_SO_GET_REVISION_MATCH
:
1213 case IP6T_SO_GET_REVISION_TARGET
: {
1214 struct ip6t_get_revision rev
;
1217 if (*len
!= sizeof(rev
)) {
1221 if (copy_from_user(&rev
, user
, sizeof(rev
)) != 0) {
1226 if (cmd
== IP6T_SO_GET_REVISION_TARGET
)
1231 try_then_request_module(xt_find_revision(AF_INET6
, rev
.name
,
1234 "ip6t_%s", rev
.name
);
1239 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
1246 int ip6t_register_table(struct xt_table
*table
,
1247 const struct ip6t_replace
*repl
)
1250 struct xt_table_info
*newinfo
;
1251 static struct xt_table_info bootstrap
1252 = { 0, 0, 0, { 0 }, { 0 }, { } };
1253 void *loc_cpu_entry
;
1255 newinfo
= xt_alloc_table_info(repl
->size
);
1259 /* choose the copy on our node/cpu */
1260 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1261 memcpy(loc_cpu_entry
, repl
->entries
, repl
->size
);
1263 ret
= translate_table(table
->name
, table
->valid_hooks
,
1264 newinfo
, loc_cpu_entry
, repl
->size
,
1269 xt_free_table_info(newinfo
);
1273 ret
= xt_register_table(table
, &bootstrap
, newinfo
);
1275 xt_free_table_info(newinfo
);
1282 void ip6t_unregister_table(struct xt_table
*table
)
1284 struct xt_table_info
*private;
1285 void *loc_cpu_entry
;
1287 private = xt_unregister_table(table
);
1289 /* Decrease module usage counts and free resources */
1290 loc_cpu_entry
= private->entries
[raw_smp_processor_id()];
1291 IP6T_ENTRY_ITERATE(loc_cpu_entry
, private->size
, cleanup_entry
, NULL
);
1292 xt_free_table_info(private);
1295 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1297 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
1298 u_int8_t type
, u_int8_t code
,
1301 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
1306 icmp6_match(const struct sk_buff
*skb
,
1307 const struct net_device
*in
,
1308 const struct net_device
*out
,
1309 const struct xt_match
*match
,
1310 const void *matchinfo
,
1312 unsigned int protoff
,
1315 struct icmp6hdr _icmp
, *ic
;
1316 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1318 /* Must not be a fragment. */
1322 ic
= skb_header_pointer(skb
, protoff
, sizeof(_icmp
), &_icmp
);
1324 /* We've been asked to examine this packet, and we
1325 can't. Hence, no choice but to drop. */
1326 duprintf("Dropping evil ICMP tinygram.\n");
1331 return icmp6_type_code_match(icmpinfo
->type
,
1334 ic
->icmp6_type
, ic
->icmp6_code
,
1335 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
1338 /* Called when user tries to insert an entry of this type. */
1340 icmp6_checkentry(const char *tablename
,
1342 const struct xt_match
*match
,
1344 unsigned int hook_mask
)
1346 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1348 /* Must specify no unknown invflags */
1349 return !(icmpinfo
->invflags
& ~IP6T_ICMP_INV
);
1352 /* The built-in targets: standard (NULL) and error. */
1353 static struct ip6t_target ip6t_standard_target
= {
1354 .name
= IP6T_STANDARD_TARGET
,
1355 .targetsize
= sizeof(int),
1359 static struct ip6t_target ip6t_error_target
= {
1360 .name
= IP6T_ERROR_TARGET
,
1361 .target
= ip6t_error
,
1362 .targetsize
= IP6T_FUNCTION_MAXNAMELEN
,
1366 static struct nf_sockopt_ops ip6t_sockopts
= {
1368 .set_optmin
= IP6T_BASE_CTL
,
1369 .set_optmax
= IP6T_SO_SET_MAX
+1,
1370 .set
= do_ip6t_set_ctl
,
1371 .get_optmin
= IP6T_BASE_CTL
,
1372 .get_optmax
= IP6T_SO_GET_MAX
+1,
1373 .get
= do_ip6t_get_ctl
,
1376 static struct ip6t_match icmp6_matchstruct
= {
1378 .match
= &icmp6_match
,
1379 .matchsize
= sizeof(struct ip6t_icmp
),
1380 .checkentry
= icmp6_checkentry
,
1381 .proto
= IPPROTO_ICMPV6
,
1385 static int __init
ip6_tables_init(void)
1389 ret
= xt_proto_init(AF_INET6
);
1393 /* Noone else will be downing sem now, so we won't sleep */
1394 ret
= xt_register_target(&ip6t_standard_target
);
1397 ret
= xt_register_target(&ip6t_error_target
);
1400 ret
= xt_register_match(&icmp6_matchstruct
);
1404 /* Register setsockopt */
1405 ret
= nf_register_sockopt(&ip6t_sockopts
);
1409 printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
1413 xt_unregister_match(&icmp6_matchstruct
);
1415 xt_unregister_target(&ip6t_error_target
);
1417 xt_unregister_target(&ip6t_standard_target
);
1419 xt_proto_fini(AF_INET6
);
1424 static void __exit
ip6_tables_fini(void)
1426 nf_unregister_sockopt(&ip6t_sockopts
);
1427 xt_unregister_match(&icmp6_matchstruct
);
1428 xt_unregister_target(&ip6t_error_target
);
1429 xt_unregister_target(&ip6t_standard_target
);
1430 xt_proto_fini(AF_INET6
);
1434 * find the offset to specified header or the protocol number of last header
1435 * if target < 0. "last header" is transport protocol header, ESP, or
1438 * If target header is found, its offset is set in *offset and return protocol
1439 * number. Otherwise, return -1.
1441 * Note that non-1st fragment is special case that "the protocol number
1442 * of last header" is "next header" field in Fragment header. In this case,
1443 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
1447 int ipv6_find_hdr(const struct sk_buff
*skb
, unsigned int *offset
,
1448 int target
, unsigned short *fragoff
)
1450 unsigned int start
= (u8
*)(skb
->nh
.ipv6h
+ 1) - skb
->data
;
1451 u8 nexthdr
= skb
->nh
.ipv6h
->nexthdr
;
1452 unsigned int len
= skb
->len
- start
;
1457 while (nexthdr
!= target
) {
1458 struct ipv6_opt_hdr _hdr
, *hp
;
1459 unsigned int hdrlen
;
1461 if ((!ipv6_ext_hdr(nexthdr
)) || nexthdr
== NEXTHDR_NONE
) {
1467 hp
= skb_header_pointer(skb
, start
, sizeof(_hdr
), &_hdr
);
1470 if (nexthdr
== NEXTHDR_FRAGMENT
) {
1471 unsigned short _frag_off
, *fp
;
1472 fp
= skb_header_pointer(skb
,
1473 start
+offsetof(struct frag_hdr
,
1480 _frag_off
= ntohs(*fp
) & ~0x7;
1483 ((!ipv6_ext_hdr(hp
->nexthdr
)) ||
1484 nexthdr
== NEXTHDR_NONE
)) {
1486 *fragoff
= _frag_off
;
1492 } else if (nexthdr
== NEXTHDR_AUTH
)
1493 hdrlen
= (hp
->hdrlen
+ 2) << 2;
1495 hdrlen
= ipv6_optlen(hp
);
1497 nexthdr
= hp
->nexthdr
;
1506 EXPORT_SYMBOL(ip6t_register_table
);
1507 EXPORT_SYMBOL(ip6t_unregister_table
);
1508 EXPORT_SYMBOL(ip6t_do_table
);
1509 EXPORT_SYMBOL(ip6t_ext_hdr
);
1510 EXPORT_SYMBOL(ipv6_find_hdr
);
1512 module_init(ip6_tables_init
);
1513 module_exit(ip6_tables_fini
);