2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 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
17 #include <linux/config.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
25 #include <linux/icmpv6.h>
28 #include <asm/uaccess.h>
29 #include <asm/semaphore.h>
30 #include <linux/proc_fs.h>
32 #include <linux/netfilter_ipv6/ip6_tables.h>
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
38 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
39 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
41 /*#define DEBUG_IP_FIREWALL*/
42 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
43 /*#define DEBUG_IP_FIREWALL_USER*/
45 #ifdef DEBUG_IP_FIREWALL
46 #define dprintf(format, args...) printk(format , ## args)
48 #define dprintf(format, args...)
51 #ifdef DEBUG_IP_FIREWALL_USER
52 #define duprintf(format, args...) printk(format , ## args)
54 #define duprintf(format, args...)
57 #ifdef CONFIG_NETFILTER_DEBUG
58 #define IP_NF_ASSERT(x) \
61 printk("IP_NF_ASSERT: %s:%s:%u\n", \
62 __FUNCTION__, __FILE__, __LINE__); \
65 #define IP_NF_ASSERT(x)
67 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69 static DECLARE_MUTEX(ip6t_mutex
);
72 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
73 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #include <linux/netfilter_ipv4/listhelp.h>
77 /* All the better to debug you with... */
82 /* Locking is simple: we assume at worst case there will be one packet
83 in user context and one from bottom halves (or soft irq if Alexey's
84 softnet patch was applied).
86 We keep a set of rules for each CPU, so we can avoid write-locking
87 them; doing a readlock_bh() stops packets coming through if we're
90 To be cache friendly on SMP, we arrange them like so:
92 ... cache-align padding ...
95 Hence the start of any table is given by get_table() below. */
97 /* The table itself */
98 struct ip6t_table_info
102 /* Number of entries: FIXME. --RR */
104 /* Initial number of entries. Needed for module usage count */
105 unsigned int initial_entries
;
107 /* Entry points and underflows */
108 unsigned int hook_entry
[NF_IP6_NUMHOOKS
];
109 unsigned int underflow
[NF_IP6_NUMHOOKS
];
111 /* ip6t_entry tables: one per CPU */
112 char entries
[0] ____cacheline_aligned
;
115 static LIST_HEAD(ip6t_target
);
116 static LIST_HEAD(ip6t_match
);
117 static LIST_HEAD(ip6t_tables
);
118 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
121 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
123 #define TABLE_OFFSET(t,p) 0
127 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
128 #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; })
129 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
132 static int ip6_masked_addrcmp(struct in6_addr addr1
, struct in6_addr mask
,
133 struct in6_addr addr2
)
136 for( i
= 0; i
< 16; i
++){
137 if((addr1
.s6_addr
[i
] & mask
.s6_addr
[i
]) !=
138 (addr2
.s6_addr
[i
] & mask
.s6_addr
[i
]))
144 /* Check for an extension */
146 ip6t_ext_hdr(u8 nexthdr
)
148 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
149 (nexthdr
== IPPROTO_ROUTING
) ||
150 (nexthdr
== IPPROTO_FRAGMENT
) ||
151 (nexthdr
== IPPROTO_ESP
) ||
152 (nexthdr
== IPPROTO_AH
) ||
153 (nexthdr
== IPPROTO_NONE
) ||
154 (nexthdr
== IPPROTO_DSTOPTS
) );
157 /* Returns whether matches rule or not. */
159 ip6_packet_match(const struct sk_buff
*skb
,
162 const struct ip6t_ip6
*ip6info
,
163 unsigned int *protoff
,
168 const struct ipv6hdr
*ipv6
= skb
->nh
.ipv6h
;
170 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
172 if (FWINV(ip6_masked_addrcmp(ipv6
->saddr
,ip6info
->smsk
,ip6info
->src
),
174 || FWINV(ip6_masked_addrcmp(ipv6
->daddr
,ip6info
->dmsk
,ip6info
->dst
),
176 dprintf("Source or dest mismatch.\n");
178 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
179 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
180 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
181 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
182 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
183 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
187 /* Look for ifname matches; this should unroll nicely. */
188 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
189 ret
|= (((const unsigned long *)indev
)[i
]
190 ^ ((const unsigned long *)ip6info
->iniface
)[i
])
191 & ((const unsigned long *)ip6info
->iniface_mask
)[i
];
194 if (FWINV(ret
!= 0, IP6T_INV_VIA_IN
)) {
195 dprintf("VIA in mismatch (%s vs %s).%s\n",
196 indev
, ip6info
->iniface
,
197 ip6info
->invflags
&IP6T_INV_VIA_IN
?" (INV)":"");
201 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
202 ret
|= (((const unsigned long *)outdev
)[i
]
203 ^ ((const unsigned long *)ip6info
->outiface
)[i
])
204 & ((const unsigned long *)ip6info
->outiface_mask
)[i
];
207 if (FWINV(ret
!= 0, IP6T_INV_VIA_OUT
)) {
208 dprintf("VIA out mismatch (%s vs %s).%s\n",
209 outdev
, ip6info
->outiface
,
210 ip6info
->invflags
&IP6T_INV_VIA_OUT
?" (INV)":"");
214 /* ... might want to do something with class and flowlabel here ... */
216 /* look for the desired protocol header */
217 if((ip6info
->flags
& IP6T_F_PROTO
)) {
218 u_int8_t currenthdr
= ipv6
->nexthdr
;
219 struct ipv6_opt_hdr _hdr
, *hp
;
220 u_int16_t ptr
; /* Header offset in skb */
221 u_int16_t hdrlen
; /* Header */
222 u_int16_t _fragoff
= 0, *fp
= NULL
;
226 while (ip6t_ext_hdr(currenthdr
)) {
227 /* Is there enough space for the next ext header? */
228 if (skb
->len
- ptr
< IPV6_OPTHDR_LEN
)
231 /* NONE or ESP: there isn't protocol part */
232 /* If we want to count these packets in '-p all',
233 * we will change the return 0 to 1*/
234 if ((currenthdr
== IPPROTO_NONE
) ||
235 (currenthdr
== IPPROTO_ESP
))
238 hp
= skb_header_pointer(skb
, ptr
, sizeof(_hdr
), &_hdr
);
241 /* Size calculation */
242 if (currenthdr
== IPPROTO_FRAGMENT
) {
243 fp
= skb_header_pointer(skb
,
244 ptr
+offsetof(struct frag_hdr
,
251 _fragoff
= ntohs(*fp
) & ~0x7;
253 } else if (currenthdr
== IPPROTO_AH
)
254 hdrlen
= (hp
->hdrlen
+2)<<2;
256 hdrlen
= ipv6_optlen(hp
);
258 currenthdr
= hp
->nexthdr
;
260 /* ptr is too large */
261 if ( ptr
> skb
->len
)
264 if (ip6t_ext_hdr(currenthdr
))
273 /* currenthdr contains the protocol header */
275 dprintf("Packet protocol %hi ?= %s%hi.\n",
277 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
280 if (ip6info
->proto
== currenthdr
) {
281 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
287 /* We need match for the '-p all', too! */
288 if ((ip6info
->proto
!= 0) &&
289 !(ip6info
->invflags
& IP6T_INV_PROTO
))
295 /* should be ip6 safe */
297 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
299 if (ipv6
->flags
& ~IP6T_F_MASK
) {
300 duprintf("Unknown flag bits set: %08X\n",
301 ipv6
->flags
& ~IP6T_F_MASK
);
304 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
305 duprintf("Unknown invflag bits set: %08X\n",
306 ipv6
->invflags
& ~IP6T_INV_MASK
);
313 ip6t_error(struct sk_buff
**pskb
,
314 const struct net_device
*in
,
315 const struct net_device
*out
,
316 unsigned int hooknum
,
317 const void *targinfo
,
321 printk("ip6_tables: error: `%s'\n", (char *)targinfo
);
327 int do_match(struct ip6t_entry_match
*m
,
328 const struct sk_buff
*skb
,
329 const struct net_device
*in
,
330 const struct net_device
*out
,
332 unsigned int protoff
,
335 /* Stop iteration if it doesn't match */
336 if (!m
->u
.kernel
.match
->match(skb
, in
, out
, m
->data
,
337 offset
, protoff
, hotdrop
))
343 static inline struct ip6t_entry
*
344 get_entry(void *base
, unsigned int offset
)
346 return (struct ip6t_entry
*)(base
+ offset
);
349 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
351 ip6t_do_table(struct sk_buff
**pskb
,
353 const struct net_device
*in
,
354 const struct net_device
*out
,
355 struct ip6t_table
*table
,
358 static const char nulldevname
[IFNAMSIZ
];
360 unsigned int protoff
= 0;
362 /* Initializing verdict to NF_DROP keeps gcc happy. */
363 unsigned int verdict
= NF_DROP
;
364 const char *indev
, *outdev
;
366 struct ip6t_entry
*e
, *back
;
369 indev
= in
? in
->name
: nulldevname
;
370 outdev
= out
? out
->name
: nulldevname
;
372 /* We handle fragments by dealing with the first fragment as
373 * if it was a normal packet. All other fragments are treated
374 * normally, except that they will NEVER match rules that ask
375 * things we don't know, ie. tcp syn flag or ports). If the
376 * rule is also a fragment-specific rule, non-fragments won't
379 read_lock_bh(&table
->lock
);
380 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
381 table_base
= (void *)table
->private->entries
382 + TABLE_OFFSET(table
->private, smp_processor_id());
383 e
= get_entry(table_base
, table
->private->hook_entry
[hook
]);
385 #ifdef CONFIG_NETFILTER_DEBUG
386 /* Check noone else using our table */
387 if (((struct ip6t_entry
*)table_base
)->comefrom
!= 0xdead57ac
388 && ((struct ip6t_entry
*)table_base
)->comefrom
!= 0xeeeeeeec) {
389 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
392 &((struct ip6t_entry
*)table_base
)->comefrom
,
393 ((struct ip6t_entry
*)table_base
)->comefrom
);
395 ((struct ip6t_entry
*)table_base
)->comefrom
= 0x57acc001;
398 /* For return from builtin chain */
399 back
= get_entry(table_base
, table
->private->underflow
[hook
]);
404 if (ip6_packet_match(*pskb
, indev
, outdev
, &e
->ipv6
,
405 &protoff
, &offset
)) {
406 struct ip6t_entry_target
*t
;
408 if (IP6T_MATCH_ITERATE(e
, do_match
,
410 offset
, protoff
, &hotdrop
) != 0)
413 ADD_COUNTER(e
->counters
,
414 ntohs((*pskb
)->nh
.ipv6h
->payload_len
)
418 t
= ip6t_get_target(e
);
419 IP_NF_ASSERT(t
->u
.kernel
.target
);
420 /* Standard target? */
421 if (!t
->u
.kernel
.target
->target
) {
424 v
= ((struct ip6t_standard_target
*)t
)->verdict
;
426 /* Pop from stack? */
427 if (v
!= IP6T_RETURN
) {
428 verdict
= (unsigned)(-v
) - 1;
432 back
= get_entry(table_base
,
436 if (table_base
+ v
!= (void *)e
+ e
->next_offset
437 && !(e
->ipv6
.flags
& IP6T_F_GOTO
)) {
438 /* Save old back ptr in next entry */
439 struct ip6t_entry
*next
440 = (void *)e
+ e
->next_offset
;
442 = (void *)back
- table_base
;
443 /* set back pointer to next entry */
447 e
= get_entry(table_base
, v
);
449 /* Targets which reenter must return
451 #ifdef CONFIG_NETFILTER_DEBUG
452 ((struct ip6t_entry
*)table_base
)->comefrom
455 verdict
= t
->u
.kernel
.target
->target(pskb
,
461 #ifdef CONFIG_NETFILTER_DEBUG
462 if (((struct ip6t_entry
*)table_base
)->comefrom
464 && verdict
== IP6T_CONTINUE
) {
465 printk("Target %s reentered!\n",
466 t
->u
.kernel
.target
->name
);
469 ((struct ip6t_entry
*)table_base
)->comefrom
472 if (verdict
== IP6T_CONTINUE
)
473 e
= (void *)e
+ e
->next_offset
;
481 e
= (void *)e
+ e
->next_offset
;
485 #ifdef CONFIG_NETFILTER_DEBUG
486 ((struct ip6t_entry
*)table_base
)->comefrom
= 0xdead57ac;
488 read_unlock_bh(&table
->lock
);
490 #ifdef DEBUG_ALLOW_ALL
499 /* If it succeeds, returns element and locks mutex */
501 find_inlist_lock_noload(struct list_head
*head
,
504 struct semaphore
*mutex
)
509 duprintf("find_inlist: searching for `%s' in %s.\n",
510 name
, head
== &ip6t_target
? "ip6t_target"
511 : head
== &ip6t_match
? "ip6t_match"
512 : head
== &ip6t_tables
? "ip6t_tables" : "UNKNOWN");
515 *error
= down_interruptible(mutex
);
519 ret
= list_named_find(head
, name
);
528 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
531 find_inlist_lock(struct list_head
*head
,
535 struct semaphore
*mutex
)
539 ret
= find_inlist_lock_noload(head
, name
, error
, mutex
);
541 duprintf("find_inlist: loading `%s%s'.\n", prefix
, name
);
542 request_module("%s%s", prefix
, name
);
543 ret
= find_inlist_lock_noload(head
, name
, error
, mutex
);
550 static inline struct ip6t_table
*
551 ip6t_find_table_lock(const char *name
, int *error
, struct semaphore
*mutex
)
553 return find_inlist_lock(&ip6t_tables
, name
, "ip6table_", error
, mutex
);
556 static inline struct ip6t_match
*
557 find_match_lock(const char *name
, int *error
, struct semaphore
*mutex
)
559 return find_inlist_lock(&ip6t_match
, name
, "ip6t_", error
, mutex
);
562 static struct ip6t_target
*
563 ip6t_find_target_lock(const char *name
, int *error
, struct semaphore
*mutex
)
565 return find_inlist_lock(&ip6t_target
, name
, "ip6t_", error
, mutex
);
568 /* All zeroes == unconditional rule. */
570 unconditional(const struct ip6t_ip6
*ipv6
)
574 for (i
= 0; i
< sizeof(*ipv6
); i
++)
575 if (((char *)ipv6
)[i
])
578 return (i
== sizeof(*ipv6
));
581 /* Figures out from what hook each rule can be called: returns 0 if
582 there are loops. Puts hook bitmask in comefrom. */
584 mark_source_chains(struct ip6t_table_info
*newinfo
, unsigned int valid_hooks
)
588 /* No recursion; use packet counter to save back ptrs (reset
589 to 0 as we leave), and comefrom to save source hook bitmask */
590 for (hook
= 0; hook
< NF_IP6_NUMHOOKS
; hook
++) {
591 unsigned int pos
= newinfo
->hook_entry
[hook
];
593 = (struct ip6t_entry
*)(newinfo
->entries
+ pos
);
595 if (!(valid_hooks
& (1 << hook
)))
598 /* Set initial back pointer. */
599 e
->counters
.pcnt
= pos
;
602 struct ip6t_standard_target
*t
603 = (void *)ip6t_get_target(e
);
605 if (e
->comefrom
& (1 << NF_IP6_NUMHOOKS
)) {
606 printk("iptables: loop hook %u pos %u %08X.\n",
607 hook
, pos
, e
->comefrom
);
611 |= ((1 << hook
) | (1 << NF_IP6_NUMHOOKS
));
613 /* Unconditional return/END. */
614 if (e
->target_offset
== sizeof(struct ip6t_entry
)
615 && (strcmp(t
->target
.u
.user
.name
,
616 IP6T_STANDARD_TARGET
) == 0)
618 && unconditional(&e
->ipv6
)) {
619 unsigned int oldpos
, size
;
621 /* Return: backtrack through the last
624 e
->comefrom
^= (1<<NF_IP6_NUMHOOKS
);
625 #ifdef DEBUG_IP_FIREWALL_USER
627 & (1 << NF_IP6_NUMHOOKS
)) {
628 duprintf("Back unset "
635 pos
= e
->counters
.pcnt
;
636 e
->counters
.pcnt
= 0;
638 /* We're at the start. */
642 e
= (struct ip6t_entry
*)
643 (newinfo
->entries
+ pos
);
644 } while (oldpos
== pos
+ e
->next_offset
);
647 size
= e
->next_offset
;
648 e
= (struct ip6t_entry
*)
649 (newinfo
->entries
+ pos
+ size
);
650 e
->counters
.pcnt
= pos
;
653 int newpos
= t
->verdict
;
655 if (strcmp(t
->target
.u
.user
.name
,
656 IP6T_STANDARD_TARGET
) == 0
658 /* This a jump; chase it. */
659 duprintf("Jump rule %u -> %u\n",
662 /* ... this is a fallthru */
663 newpos
= pos
+ e
->next_offset
;
665 e
= (struct ip6t_entry
*)
666 (newinfo
->entries
+ newpos
);
667 e
->counters
.pcnt
= pos
;
672 duprintf("Finished chain %u\n", hook
);
678 cleanup_match(struct ip6t_entry_match
*m
, unsigned int *i
)
680 if (i
&& (*i
)-- == 0)
683 if (m
->u
.kernel
.match
->destroy
)
684 m
->u
.kernel
.match
->destroy(m
->data
,
685 m
->u
.match_size
- sizeof(*m
));
686 module_put(m
->u
.kernel
.match
->me
);
691 standard_check(const struct ip6t_entry_target
*t
,
692 unsigned int max_offset
)
694 struct ip6t_standard_target
*targ
= (void *)t
;
696 /* Check standard info. */
698 != IP6T_ALIGN(sizeof(struct ip6t_standard_target
))) {
699 duprintf("standard_check: target size %u != %u\n",
701 IP6T_ALIGN(sizeof(struct ip6t_standard_target
)));
705 if (targ
->verdict
>= 0
706 && targ
->verdict
> max_offset
- sizeof(struct ip6t_entry
)) {
707 duprintf("ip6t_standard_check: bad verdict (%i)\n",
712 if (targ
->verdict
< -NF_MAX_VERDICT
- 1) {
713 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
721 check_match(struct ip6t_entry_match
*m
,
723 const struct ip6t_ip6
*ipv6
,
724 unsigned int hookmask
,
728 struct ip6t_match
*match
;
730 match
= find_match_lock(m
->u
.user
.name
, &ret
, &ip6t_mutex
);
732 // duprintf("check_match: `%s' not found\n", m->u.name);
735 if (!try_module_get(match
->me
)) {
739 m
->u
.kernel
.match
= match
;
742 if (m
->u
.kernel
.match
->checkentry
743 && !m
->u
.kernel
.match
->checkentry(name
, ipv6
, m
->data
,
744 m
->u
.match_size
- sizeof(*m
),
746 module_put(m
->u
.kernel
.match
->me
);
747 duprintf("ip_tables: check failed for `%s'.\n",
748 m
->u
.kernel
.match
->name
);
756 static struct ip6t_target ip6t_standard_target
;
759 check_entry(struct ip6t_entry
*e
, const char *name
, unsigned int size
,
762 struct ip6t_entry_target
*t
;
763 struct ip6t_target
*target
;
767 if (!ip6_checkentry(&e
->ipv6
)) {
768 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
773 ret
= IP6T_MATCH_ITERATE(e
, check_match
, name
, &e
->ipv6
, e
->comefrom
, &j
);
775 goto cleanup_matches
;
777 t
= ip6t_get_target(e
);
778 target
= ip6t_find_target_lock(t
->u
.user
.name
, &ret
, &ip6t_mutex
);
780 duprintf("check_entry: `%s' not found\n", t
->u
.user
.name
);
781 goto cleanup_matches
;
783 if (!try_module_get(target
->me
)) {
786 goto cleanup_matches
;
788 t
->u
.kernel
.target
= target
;
790 if (!t
->u
.kernel
.target
) {
792 goto cleanup_matches
;
794 if (t
->u
.kernel
.target
== &ip6t_standard_target
) {
795 if (!standard_check(t
, size
)) {
797 goto cleanup_matches
;
799 } else if (t
->u
.kernel
.target
->checkentry
800 && !t
->u
.kernel
.target
->checkentry(name
, e
, t
->data
,
804 module_put(t
->u
.kernel
.target
->me
);
805 duprintf("ip_tables: check failed for `%s'.\n",
806 t
->u
.kernel
.target
->name
);
808 goto cleanup_matches
;
815 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
820 check_entry_size_and_hooks(struct ip6t_entry
*e
,
821 struct ip6t_table_info
*newinfo
,
823 unsigned char *limit
,
824 const unsigned int *hook_entries
,
825 const unsigned int *underflows
,
830 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0
831 || (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
832 duprintf("Bad offset %p\n", e
);
837 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
838 duprintf("checking: element %p size %u\n",
843 /* Check hooks & underflows */
844 for (h
= 0; h
< NF_IP6_NUMHOOKS
; h
++) {
845 if ((unsigned char *)e
- base
== hook_entries
[h
])
846 newinfo
->hook_entry
[h
] = hook_entries
[h
];
847 if ((unsigned char *)e
- base
== underflows
[h
])
848 newinfo
->underflow
[h
] = underflows
[h
];
851 /* FIXME: underflows must be unconditional, standard verdicts
852 < 0 (not IP6T_RETURN). --RR */
854 /* Clear counters and comefrom */
855 e
->counters
= ((struct ip6t_counters
) { 0, 0 });
863 cleanup_entry(struct ip6t_entry
*e
, unsigned int *i
)
865 struct ip6t_entry_target
*t
;
867 if (i
&& (*i
)-- == 0)
870 /* Cleanup all matches */
871 IP6T_MATCH_ITERATE(e
, cleanup_match
, NULL
);
872 t
= ip6t_get_target(e
);
873 if (t
->u
.kernel
.target
->destroy
)
874 t
->u
.kernel
.target
->destroy(t
->data
,
875 t
->u
.target_size
- sizeof(*t
));
876 module_put(t
->u
.kernel
.target
->me
);
880 /* Checks and translates the user-supplied table segment (held in
883 translate_table(const char *name
,
884 unsigned int valid_hooks
,
885 struct ip6t_table_info
*newinfo
,
888 const unsigned int *hook_entries
,
889 const unsigned int *underflows
)
894 newinfo
->size
= size
;
895 newinfo
->number
= number
;
897 /* Init all hooks to impossible value. */
898 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
899 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
900 newinfo
->underflow
[i
] = 0xFFFFFFFF;
903 duprintf("translate_table: size %u\n", newinfo
->size
);
905 /* Walk through entries, checking offsets. */
906 ret
= IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
907 check_entry_size_and_hooks
,
910 newinfo
->entries
+ size
,
911 hook_entries
, underflows
, &i
);
916 duprintf("translate_table: %u not %u entries\n",
921 /* Check hooks all assigned */
922 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
923 /* Only hooks which are valid */
924 if (!(valid_hooks
& (1 << i
)))
926 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
927 duprintf("Invalid hook entry %u %u\n",
931 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
932 duprintf("Invalid underflow %u %u\n",
938 if (!mark_source_chains(newinfo
, valid_hooks
))
941 /* Finally, each sanity check must pass */
943 ret
= IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
944 check_entry
, name
, size
, &i
);
947 IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
952 /* And one copy for every other CPU */
953 for (i
= 1; i
< num_possible_cpus(); i
++) {
954 memcpy(newinfo
->entries
+ SMP_ALIGN(newinfo
->size
)*i
,
956 SMP_ALIGN(newinfo
->size
));
962 static struct ip6t_table_info
*
963 replace_table(struct ip6t_table
*table
,
964 unsigned int num_counters
,
965 struct ip6t_table_info
*newinfo
,
968 struct ip6t_table_info
*oldinfo
;
970 #ifdef CONFIG_NETFILTER_DEBUG
972 struct ip6t_entry
*table_base
;
975 for (i
= 0; i
< num_possible_cpus(); i
++) {
977 (void *)newinfo
->entries
978 + TABLE_OFFSET(newinfo
, i
);
980 table_base
->comefrom
= 0xdead57ac;
985 /* Do the substitution. */
986 write_lock_bh(&table
->lock
);
987 /* Check inside lock: is the old number correct? */
988 if (num_counters
!= table
->private->number
) {
989 duprintf("num_counters != table->private->number (%u/%u)\n",
990 num_counters
, table
->private->number
);
991 write_unlock_bh(&table
->lock
);
995 oldinfo
= table
->private;
996 table
->private = newinfo
;
997 newinfo
->initial_entries
= oldinfo
->initial_entries
;
998 write_unlock_bh(&table
->lock
);
1003 /* Gets counters. */
1005 add_entry_to_counter(const struct ip6t_entry
*e
,
1006 struct ip6t_counters total
[],
1009 ADD_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
1016 get_counters(const struct ip6t_table_info
*t
,
1017 struct ip6t_counters counters
[])
1022 for (cpu
= 0; cpu
< num_possible_cpus(); cpu
++) {
1024 IP6T_ENTRY_ITERATE(t
->entries
+ TABLE_OFFSET(t
, cpu
),
1026 add_entry_to_counter
,
1033 copy_entries_to_user(unsigned int total_size
,
1034 struct ip6t_table
*table
,
1035 void __user
*userptr
)
1037 unsigned int off
, num
, countersize
;
1038 struct ip6t_entry
*e
;
1039 struct ip6t_counters
*counters
;
1042 /* We need atomic snapshot of counters: rest doesn't change
1043 (other than comefrom, which userspace doesn't care
1045 countersize
= sizeof(struct ip6t_counters
) * table
->private->number
;
1046 counters
= vmalloc(countersize
);
1048 if (counters
== NULL
)
1051 /* First, sum counters... */
1052 memset(counters
, 0, countersize
);
1053 write_lock_bh(&table
->lock
);
1054 get_counters(table
->private, counters
);
1055 write_unlock_bh(&table
->lock
);
1057 /* ... then copy entire thing from CPU 0... */
1058 if (copy_to_user(userptr
, table
->private->entries
, total_size
) != 0) {
1063 /* FIXME: use iterator macros --RR */
1064 /* ... then go back and fix counters and names */
1065 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
1067 struct ip6t_entry_match
*m
;
1068 struct ip6t_entry_target
*t
;
1070 e
= (struct ip6t_entry
*)(table
->private->entries
+ off
);
1071 if (copy_to_user(userptr
+ off
1072 + offsetof(struct ip6t_entry
, counters
),
1074 sizeof(counters
[num
])) != 0) {
1079 for (i
= sizeof(struct ip6t_entry
);
1080 i
< e
->target_offset
;
1081 i
+= m
->u
.match_size
) {
1084 if (copy_to_user(userptr
+ off
+ i
1085 + offsetof(struct ip6t_entry_match
,
1087 m
->u
.kernel
.match
->name
,
1088 strlen(m
->u
.kernel
.match
->name
)+1)
1095 t
= ip6t_get_target(e
);
1096 if (copy_to_user(userptr
+ off
+ e
->target_offset
1097 + offsetof(struct ip6t_entry_target
,
1099 t
->u
.kernel
.target
->name
,
1100 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
1112 get_entries(const struct ip6t_get_entries
*entries
,
1113 struct ip6t_get_entries __user
*uptr
)
1116 struct ip6t_table
*t
;
1118 t
= ip6t_find_table_lock(entries
->name
, &ret
, &ip6t_mutex
);
1120 duprintf("t->private->number = %u\n",
1121 t
->private->number
);
1122 if (entries
->size
== t
->private->size
)
1123 ret
= copy_entries_to_user(t
->private->size
,
1124 t
, uptr
->entrytable
);
1126 duprintf("get_entries: I've got %u not %u!\n",
1133 duprintf("get_entries: Can't find %s!\n",
1140 do_replace(void __user
*user
, unsigned int len
)
1143 struct ip6t_replace tmp
;
1144 struct ip6t_table
*t
;
1145 struct ip6t_table_info
*newinfo
, *oldinfo
;
1146 struct ip6t_counters
*counters
;
1148 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1151 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1152 if ((SMP_ALIGN(tmp
.size
) >> PAGE_SHIFT
) + 2 > num_physpages
)
1155 newinfo
= vmalloc(sizeof(struct ip6t_table_info
)
1156 + SMP_ALIGN(tmp
.size
) * num_possible_cpus());
1160 if (copy_from_user(newinfo
->entries
, user
+ sizeof(tmp
),
1166 counters
= vmalloc(tmp
.num_counters
* sizeof(struct ip6t_counters
));
1171 memset(counters
, 0, tmp
.num_counters
* sizeof(struct ip6t_counters
));
1173 ret
= translate_table(tmp
.name
, tmp
.valid_hooks
,
1174 newinfo
, tmp
.size
, tmp
.num_entries
,
1175 tmp
.hook_entry
, tmp
.underflow
);
1177 goto free_newinfo_counters
;
1179 duprintf("ip_tables: Translated table\n");
1181 t
= ip6t_find_table_lock(tmp
.name
, &ret
, &ip6t_mutex
);
1183 goto free_newinfo_counters_untrans
;
1186 if (tmp
.valid_hooks
!= t
->valid_hooks
) {
1187 duprintf("Valid hook crap: %08X vs %08X\n",
1188 tmp
.valid_hooks
, t
->valid_hooks
);
1190 goto free_newinfo_counters_untrans_unlock
;
1193 /* Get a reference in advance, we're not allowed fail later */
1194 if (!try_module_get(t
->me
)) {
1196 goto free_newinfo_counters_untrans_unlock
;
1199 oldinfo
= replace_table(t
, tmp
.num_counters
, newinfo
, &ret
);
1203 /* Update module usage count based on number of rules */
1204 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1205 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1206 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1207 (newinfo
->number
<= oldinfo
->initial_entries
))
1209 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1210 (newinfo
->number
<= oldinfo
->initial_entries
))
1213 /* Get the old counters. */
1214 get_counters(oldinfo
, counters
);
1215 /* Decrease module usage counts and free resource */
1216 IP6T_ENTRY_ITERATE(oldinfo
->entries
, oldinfo
->size
, cleanup_entry
,NULL
);
1218 /* Silent error: too late now. */
1219 if (copy_to_user(tmp
.counters
, counters
,
1220 sizeof(struct ip6t_counters
) * tmp
.num_counters
) != 0)
1228 free_newinfo_counters_untrans_unlock
:
1230 free_newinfo_counters_untrans
:
1231 IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
, cleanup_entry
,NULL
);
1232 free_newinfo_counters
:
1239 /* We're lazy, and add to the first CPU; overflow works its fey magic
1240 * and everything is OK. */
1242 add_counter_to_entry(struct ip6t_entry
*e
,
1243 const struct ip6t_counters addme
[],
1247 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1249 (long unsigned int)e
->counters
.pcnt
,
1250 (long unsigned int)e
->counters
.bcnt
,
1251 (long unsigned int)addme
[*i
].pcnt
,
1252 (long unsigned int)addme
[*i
].bcnt
);
1255 ADD_COUNTER(e
->counters
, addme
[*i
].bcnt
, addme
[*i
].pcnt
);
1262 do_add_counters(void __user
*user
, unsigned int len
)
1265 struct ip6t_counters_info tmp
, *paddc
;
1266 struct ip6t_table
*t
;
1269 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1272 if (len
!= sizeof(tmp
) + tmp
.num_counters
*sizeof(struct ip6t_counters
))
1275 paddc
= vmalloc(len
);
1279 if (copy_from_user(paddc
, user
, len
) != 0) {
1284 t
= ip6t_find_table_lock(tmp
.name
, &ret
, &ip6t_mutex
);
1288 write_lock_bh(&t
->lock
);
1289 if (t
->private->number
!= paddc
->num_counters
) {
1291 goto unlock_up_free
;
1295 IP6T_ENTRY_ITERATE(t
->private->entries
,
1297 add_counter_to_entry
,
1301 write_unlock_bh(&t
->lock
);
1310 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
1314 if (!capable(CAP_NET_ADMIN
))
1318 case IP6T_SO_SET_REPLACE
:
1319 ret
= do_replace(user
, len
);
1322 case IP6T_SO_SET_ADD_COUNTERS
:
1323 ret
= do_add_counters(user
, len
);
1327 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
1335 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1339 if (!capable(CAP_NET_ADMIN
))
1343 case IP6T_SO_GET_INFO
: {
1344 char name
[IP6T_TABLE_MAXNAMELEN
];
1345 struct ip6t_table
*t
;
1347 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1348 duprintf("length %u != %u\n", *len
,
1349 sizeof(struct ip6t_getinfo
));
1354 if (copy_from_user(name
, user
, sizeof(name
)) != 0) {
1358 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1359 t
= ip6t_find_table_lock(name
, &ret
, &ip6t_mutex
);
1361 struct ip6t_getinfo info
;
1363 info
.valid_hooks
= t
->valid_hooks
;
1364 memcpy(info
.hook_entry
, t
->private->hook_entry
,
1365 sizeof(info
.hook_entry
));
1366 memcpy(info
.underflow
, t
->private->underflow
,
1367 sizeof(info
.underflow
));
1368 info
.num_entries
= t
->private->number
;
1369 info
.size
= t
->private->size
;
1370 memcpy(info
.name
, name
, sizeof(info
.name
));
1372 if (copy_to_user(user
, &info
, *len
) != 0)
1382 case IP6T_SO_GET_ENTRIES
: {
1383 struct ip6t_get_entries get
;
1385 if (*len
< sizeof(get
)) {
1386 duprintf("get_entries: %u < %u\n", *len
, sizeof(get
));
1388 } else if (copy_from_user(&get
, user
, sizeof(get
)) != 0) {
1390 } else if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1391 duprintf("get_entries: %u != %u\n", *len
,
1392 sizeof(struct ip6t_get_entries
) + get
.size
);
1395 ret
= get_entries(&get
, user
);
1400 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
1407 /* Registration hooks for targets. */
1409 ip6t_register_target(struct ip6t_target
*target
)
1413 ret
= down_interruptible(&ip6t_mutex
);
1417 if (!list_named_insert(&ip6t_target
, target
)) {
1418 duprintf("ip6t_register_target: `%s' already in list!\n",
1427 ip6t_unregister_target(struct ip6t_target
*target
)
1430 LIST_DELETE(&ip6t_target
, target
);
1435 ip6t_register_match(struct ip6t_match
*match
)
1439 ret
= down_interruptible(&ip6t_mutex
);
1443 if (!list_named_insert(&ip6t_match
, match
)) {
1444 duprintf("ip6t_register_match: `%s' already in list!\n",
1454 ip6t_unregister_match(struct ip6t_match
*match
)
1457 LIST_DELETE(&ip6t_match
, match
);
1461 int ip6t_register_table(struct ip6t_table
*table
,
1462 const struct ip6t_replace
*repl
)
1465 struct ip6t_table_info
*newinfo
;
1466 static struct ip6t_table_info bootstrap
1467 = { 0, 0, 0, { 0 }, { 0 }, { } };
1469 newinfo
= vmalloc(sizeof(struct ip6t_table_info
)
1470 + SMP_ALIGN(repl
->size
) * num_possible_cpus());
1474 memcpy(newinfo
->entries
, repl
->entries
, repl
->size
);
1476 ret
= translate_table(table
->name
, table
->valid_hooks
,
1477 newinfo
, repl
->size
,
1486 ret
= down_interruptible(&ip6t_mutex
);
1492 /* Don't autoload: we'd eat our tail... */
1493 if (list_named_find(&ip6t_tables
, table
->name
)) {
1498 /* Simplifies replace_table code. */
1499 table
->private = &bootstrap
;
1500 if (!replace_table(table
, 0, newinfo
, &ret
))
1503 duprintf("table->private->number = %u\n",
1504 table
->private->number
);
1506 /* save number of initial entries */
1507 table
->private->initial_entries
= table
->private->number
;
1509 rwlock_init(&table
->lock
);
1510 list_prepend(&ip6t_tables
, table
);
1521 void ip6t_unregister_table(struct ip6t_table
*table
)
1524 LIST_DELETE(&ip6t_tables
, table
);
1527 /* Decrease module usage counts and free resources */
1528 IP6T_ENTRY_ITERATE(table
->private->entries
, table
->private->size
,
1529 cleanup_entry
, NULL
);
1530 vfree(table
->private);
1533 /* Returns 1 if the port is matched by the range, 0 otherwise */
1535 port_match(u_int16_t min
, u_int16_t max
, u_int16_t port
, int invert
)
1539 ret
= (port
>= min
&& port
<= max
) ^ invert
;
1544 tcp_find_option(u_int8_t option
,
1545 const struct sk_buff
*skb
,
1546 unsigned int tcpoff
,
1547 unsigned int optlen
,
1551 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1552 u_int8_t _opt
[60 - sizeof(struct tcphdr
)], *op
;
1555 duprintf("tcp_match: finding option\n");
1558 /* If we don't have the whole header, drop packet. */
1559 op
= skb_header_pointer(skb
, tcpoff
+ sizeof(struct tcphdr
), optlen
,
1566 for (i
= 0; i
< optlen
; ) {
1567 if (op
[i
] == option
) return !invert
;
1569 else i
+= op
[i
+1]?:1;
1576 tcp_match(const struct sk_buff
*skb
,
1577 const struct net_device
*in
,
1578 const struct net_device
*out
,
1579 const void *matchinfo
,
1581 unsigned int protoff
,
1584 struct tcphdr _tcph
, *th
;
1585 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1590 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1591 causes this. Its a cracker trying to break in by doing a
1592 flag overwrite to pass the direction checks.
1595 duprintf("Dropping evil TCP offset=1 frag.\n");
1598 /* Must not be a fragment. */
1602 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1604 th
= skb_header_pointer(skb
, protoff
, sizeof(_tcph
), &_tcph
);
1606 /* We've been asked to examine this packet, and we
1607 can't. Hence, no choice but to drop. */
1608 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1613 if (!port_match(tcpinfo
->spts
[0], tcpinfo
->spts
[1],
1615 !!(tcpinfo
->invflags
& IP6T_TCP_INV_SRCPT
)))
1617 if (!port_match(tcpinfo
->dpts
[0], tcpinfo
->dpts
[1],
1619 !!(tcpinfo
->invflags
& IP6T_TCP_INV_DSTPT
)))
1621 if (!FWINVTCP((((unsigned char *)th
)[13] & tcpinfo
->flg_mask
)
1622 == tcpinfo
->flg_cmp
,
1623 IP6T_TCP_INV_FLAGS
))
1625 if (tcpinfo
->option
) {
1626 if (th
->doff
* 4 < sizeof(_tcph
)) {
1630 if (!tcp_find_option(tcpinfo
->option
, skb
, protoff
,
1631 th
->doff
*4 - sizeof(*th
),
1632 tcpinfo
->invflags
& IP6T_TCP_INV_OPTION
,
1639 /* Called when user tries to insert an entry of this type. */
1641 tcp_checkentry(const char *tablename
,
1642 const struct ip6t_ip6
*ipv6
,
1644 unsigned int matchsize
,
1645 unsigned int hook_mask
)
1647 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1649 /* Must specify proto == TCP, and no unknown invflags */
1650 return ipv6
->proto
== IPPROTO_TCP
1651 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1652 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_tcp
))
1653 && !(tcpinfo
->invflags
& ~IP6T_TCP_INV_MASK
);
1657 udp_match(const struct sk_buff
*skb
,
1658 const struct net_device
*in
,
1659 const struct net_device
*out
,
1660 const void *matchinfo
,
1662 unsigned int protoff
,
1665 struct udphdr _udph
, *uh
;
1666 const struct ip6t_udp
*udpinfo
= matchinfo
;
1668 /* Must not be a fragment. */
1672 uh
= skb_header_pointer(skb
, protoff
, sizeof(_udph
), &_udph
);
1674 /* We've been asked to examine this packet, and we
1675 can't. Hence, no choice but to drop. */
1676 duprintf("Dropping evil UDP tinygram.\n");
1681 return port_match(udpinfo
->spts
[0], udpinfo
->spts
[1],
1683 !!(udpinfo
->invflags
& IP6T_UDP_INV_SRCPT
))
1684 && port_match(udpinfo
->dpts
[0], udpinfo
->dpts
[1],
1686 !!(udpinfo
->invflags
& IP6T_UDP_INV_DSTPT
));
1689 /* Called when user tries to insert an entry of this type. */
1691 udp_checkentry(const char *tablename
,
1692 const struct ip6t_ip6
*ipv6
,
1694 unsigned int matchinfosize
,
1695 unsigned int hook_mask
)
1697 const struct ip6t_udp
*udpinfo
= matchinfo
;
1699 /* Must specify proto == UDP, and no unknown invflags */
1700 if (ipv6
->proto
!= IPPROTO_UDP
|| (ipv6
->invflags
& IP6T_INV_PROTO
)) {
1701 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6
->proto
,
1705 if (matchinfosize
!= IP6T_ALIGN(sizeof(struct ip6t_udp
))) {
1706 duprintf("ip6t_udp: matchsize %u != %u\n",
1707 matchinfosize
, IP6T_ALIGN(sizeof(struct ip6t_udp
)));
1710 if (udpinfo
->invflags
& ~IP6T_UDP_INV_MASK
) {
1711 duprintf("ip6t_udp: unknown flags %X\n",
1719 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1721 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
1722 u_int8_t type
, u_int8_t code
,
1725 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
1730 icmp6_match(const struct sk_buff
*skb
,
1731 const struct net_device
*in
,
1732 const struct net_device
*out
,
1733 const void *matchinfo
,
1735 unsigned int protoff
,
1738 struct icmp6hdr _icmp
, *ic
;
1739 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1741 /* Must not be a fragment. */
1745 ic
= skb_header_pointer(skb
, protoff
, sizeof(_icmp
), &_icmp
);
1747 /* We've been asked to examine this packet, and we
1748 can't. Hence, no choice but to drop. */
1749 duprintf("Dropping evil ICMP tinygram.\n");
1754 return icmp6_type_code_match(icmpinfo
->type
,
1757 ic
->icmp6_type
, ic
->icmp6_code
,
1758 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
1761 /* Called when user tries to insert an entry of this type. */
1763 icmp6_checkentry(const char *tablename
,
1764 const struct ip6t_ip6
*ipv6
,
1766 unsigned int matchsize
,
1767 unsigned int hook_mask
)
1769 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1771 /* Must specify proto == ICMP, and no unknown invflags */
1772 return ipv6
->proto
== IPPROTO_ICMPV6
1773 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1774 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_icmp
))
1775 && !(icmpinfo
->invflags
& ~IP6T_ICMP_INV
);
1778 /* The built-in targets: standard (NULL) and error. */
1779 static struct ip6t_target ip6t_standard_target
= {
1780 .name
= IP6T_STANDARD_TARGET
,
1783 static struct ip6t_target ip6t_error_target
= {
1784 .name
= IP6T_ERROR_TARGET
,
1785 .target
= ip6t_error
,
1788 static struct nf_sockopt_ops ip6t_sockopts
= {
1790 .set_optmin
= IP6T_BASE_CTL
,
1791 .set_optmax
= IP6T_SO_SET_MAX
+1,
1792 .set
= do_ip6t_set_ctl
,
1793 .get_optmin
= IP6T_BASE_CTL
,
1794 .get_optmax
= IP6T_SO_GET_MAX
+1,
1795 .get
= do_ip6t_get_ctl
,
1798 static struct ip6t_match tcp_matchstruct
= {
1800 .match
= &tcp_match
,
1801 .checkentry
= &tcp_checkentry
,
1804 static struct ip6t_match udp_matchstruct
= {
1806 .match
= &udp_match
,
1807 .checkentry
= &udp_checkentry
,
1810 static struct ip6t_match icmp6_matchstruct
= {
1812 .match
= &icmp6_match
,
1813 .checkentry
= &icmp6_checkentry
,
1816 #ifdef CONFIG_PROC_FS
1817 static inline int print_name(const char *i
,
1818 off_t start_offset
, char *buffer
, int length
,
1819 off_t
*pos
, unsigned int *count
)
1821 if ((*count
)++ >= start_offset
) {
1822 unsigned int namelen
;
1824 namelen
= sprintf(buffer
+ *pos
, "%s\n",
1825 i
+ sizeof(struct list_head
));
1826 if (*pos
+ namelen
> length
) {
1827 /* Stop iterating */
1835 static inline int print_target(const struct ip6t_target
*t
,
1836 off_t start_offset
, char *buffer
, int length
,
1837 off_t
*pos
, unsigned int *count
)
1839 if (t
== &ip6t_standard_target
|| t
== &ip6t_error_target
)
1841 return print_name((char *)t
, start_offset
, buffer
, length
, pos
, count
);
1844 static int ip6t_get_tables(char *buffer
, char **start
, off_t offset
, int length
)
1847 unsigned int count
= 0;
1849 if (down_interruptible(&ip6t_mutex
) != 0)
1852 LIST_FIND(&ip6t_tables
, print_name
, char *,
1853 offset
, buffer
, length
, &pos
, &count
);
1857 /* `start' hack - see fs/proc/generic.c line ~105 */
1858 *start
=(char *)((unsigned long)count
-offset
);
1862 static int ip6t_get_targets(char *buffer
, char **start
, off_t offset
, int length
)
1865 unsigned int count
= 0;
1867 if (down_interruptible(&ip6t_mutex
) != 0)
1870 LIST_FIND(&ip6t_target
, print_target
, struct ip6t_target
*,
1871 offset
, buffer
, length
, &pos
, &count
);
1875 *start
= (char *)((unsigned long)count
- offset
);
1879 static int ip6t_get_matches(char *buffer
, char **start
, off_t offset
, int length
)
1882 unsigned int count
= 0;
1884 if (down_interruptible(&ip6t_mutex
) != 0)
1887 LIST_FIND(&ip6t_match
, print_name
, char *,
1888 offset
, buffer
, length
, &pos
, &count
);
1892 *start
= (char *)((unsigned long)count
- offset
);
1896 static struct { char *name
; get_info_t
*get_info
; } ip6t_proc_entry
[] =
1897 { { "ip6_tables_names", ip6t_get_tables
},
1898 { "ip6_tables_targets", ip6t_get_targets
},
1899 { "ip6_tables_matches", ip6t_get_matches
},
1901 #endif /*CONFIG_PROC_FS*/
1903 static int __init
init(void)
1907 /* Noone else will be downing sem now, so we won't sleep */
1909 list_append(&ip6t_target
, &ip6t_standard_target
);
1910 list_append(&ip6t_target
, &ip6t_error_target
);
1911 list_append(&ip6t_match
, &tcp_matchstruct
);
1912 list_append(&ip6t_match
, &udp_matchstruct
);
1913 list_append(&ip6t_match
, &icmp6_matchstruct
);
1916 /* Register setsockopt */
1917 ret
= nf_register_sockopt(&ip6t_sockopts
);
1919 duprintf("Unable to register sockopts.\n");
1923 #ifdef CONFIG_PROC_FS
1925 struct proc_dir_entry
*proc
;
1928 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++) {
1929 proc
= proc_net_create(ip6t_proc_entry
[i
].name
, 0,
1930 ip6t_proc_entry
[i
].get_info
);
1933 proc_net_remove(ip6t_proc_entry
[i
].name
);
1934 nf_unregister_sockopt(&ip6t_sockopts
);
1937 proc
->owner
= THIS_MODULE
;
1942 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1946 static void __exit
fini(void)
1948 nf_unregister_sockopt(&ip6t_sockopts
);
1949 #ifdef CONFIG_PROC_FS
1952 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++)
1953 proc_net_remove(ip6t_proc_entry
[i
].name
);
1958 EXPORT_SYMBOL(ip6t_register_table
);
1959 EXPORT_SYMBOL(ip6t_unregister_table
);
1960 EXPORT_SYMBOL(ip6t_do_table
);
1961 EXPORT_SYMBOL(ip6t_register_match
);
1962 EXPORT_SYMBOL(ip6t_unregister_match
);
1963 EXPORT_SYMBOL(ip6t_register_target
);
1964 EXPORT_SYMBOL(ip6t_unregister_target
);
1965 EXPORT_SYMBOL(ip6t_ext_hdr
);