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
17 #include <linux/config.h>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/tcp.h>
25 #include <linux/udp.h>
26 #include <linux/icmpv6.h>
28 #include <asm/uaccess.h>
29 #include <asm/semaphore.h>
30 #include <linux/proc_fs.h>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter_ipv6/ip6_tables.h>
35 MODULE_LICENSE("GPL");
36 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
37 MODULE_DESCRIPTION("IPv6 packet filter");
39 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
40 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
42 /*#define DEBUG_IP_FIREWALL*/
43 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44 /*#define DEBUG_IP_FIREWALL_USER*/
46 #ifdef DEBUG_IP_FIREWALL
47 #define dprintf(format, args...) printk(format , ## args)
49 #define dprintf(format, args...)
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) printk(format , ## args)
55 #define duprintf(format, args...)
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x) \
62 printk("IP_NF_ASSERT: %s:%s:%u\n", \
63 __FUNCTION__, __FILE__, __LINE__); \
66 #define IP_NF_ASSERT(x)
68 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
70 static DECLARE_MUTEX(ip6t_mutex
);
73 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
75 #include <linux/netfilter_ipv4/listhelp.h>
78 /* All the better to debug you with... */
84 We keep a set of rules for each CPU, so we can avoid write-locking
85 them in the softirq when updating the counters and therefore
86 only need to read-lock in the softirq; doing a write_lock_bh() in user
87 context stops packets coming through and allows user context to read
88 the counters or update the rules.
90 Hence the start of any table is given by get_table() below. */
92 /* The table itself */
93 struct ip6t_table_info
97 /* Number of entries: FIXME. --RR */
99 /* Initial number of entries. Needed for module usage count */
100 unsigned int initial_entries
;
102 /* Entry points and underflows */
103 unsigned int hook_entry
[NF_IP6_NUMHOOKS
];
104 unsigned int underflow
[NF_IP6_NUMHOOKS
];
106 /* ip6t_entry tables: one per CPU */
107 void *entries
[NR_CPUS
];
110 static LIST_HEAD(ip6t_target
);
111 static LIST_HEAD(ip6t_match
);
112 static LIST_HEAD(ip6t_tables
);
113 #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
114 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
117 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
118 #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; })
119 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
122 static int ip6_masked_addrcmp(struct in6_addr addr1
, struct in6_addr mask
,
123 struct in6_addr addr2
)
126 for( i
= 0; i
< 16; i
++){
127 if((addr1
.s6_addr
[i
] & mask
.s6_addr
[i
]) !=
128 (addr2
.s6_addr
[i
] & mask
.s6_addr
[i
]))
134 /* Check for an extension */
136 ip6t_ext_hdr(u8 nexthdr
)
138 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
139 (nexthdr
== IPPROTO_ROUTING
) ||
140 (nexthdr
== IPPROTO_FRAGMENT
) ||
141 (nexthdr
== IPPROTO_ESP
) ||
142 (nexthdr
== IPPROTO_AH
) ||
143 (nexthdr
== IPPROTO_NONE
) ||
144 (nexthdr
== IPPROTO_DSTOPTS
) );
147 /* Returns whether matches rule or not. */
149 ip6_packet_match(const struct sk_buff
*skb
,
152 const struct ip6t_ip6
*ip6info
,
153 unsigned int *protoff
,
158 const struct ipv6hdr
*ipv6
= skb
->nh
.ipv6h
;
160 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
162 if (FWINV(ip6_masked_addrcmp(ipv6
->saddr
,ip6info
->smsk
,ip6info
->src
),
164 || FWINV(ip6_masked_addrcmp(ipv6
->daddr
,ip6info
->dmsk
,ip6info
->dst
),
166 dprintf("Source or dest mismatch.\n");
168 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
169 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
170 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
171 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
172 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
173 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
177 /* Look for ifname matches; this should unroll nicely. */
178 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
179 ret
|= (((const unsigned long *)indev
)[i
]
180 ^ ((const unsigned long *)ip6info
->iniface
)[i
])
181 & ((const unsigned long *)ip6info
->iniface_mask
)[i
];
184 if (FWINV(ret
!= 0, IP6T_INV_VIA_IN
)) {
185 dprintf("VIA in mismatch (%s vs %s).%s\n",
186 indev
, ip6info
->iniface
,
187 ip6info
->invflags
&IP6T_INV_VIA_IN
?" (INV)":"");
191 for (i
= 0, ret
= 0; i
< IFNAMSIZ
/sizeof(unsigned long); i
++) {
192 ret
|= (((const unsigned long *)outdev
)[i
]
193 ^ ((const unsigned long *)ip6info
->outiface
)[i
])
194 & ((const unsigned long *)ip6info
->outiface_mask
)[i
];
197 if (FWINV(ret
!= 0, IP6T_INV_VIA_OUT
)) {
198 dprintf("VIA out mismatch (%s vs %s).%s\n",
199 outdev
, ip6info
->outiface
,
200 ip6info
->invflags
&IP6T_INV_VIA_OUT
?" (INV)":"");
204 /* ... might want to do something with class and flowlabel here ... */
206 /* look for the desired protocol header */
207 if((ip6info
->flags
& IP6T_F_PROTO
)) {
208 u_int8_t currenthdr
= ipv6
->nexthdr
;
209 struct ipv6_opt_hdr _hdr
, *hp
;
210 u_int16_t ptr
; /* Header offset in skb */
211 u_int16_t hdrlen
; /* Header */
212 u_int16_t _fragoff
= 0, *fp
= NULL
;
216 while (ip6t_ext_hdr(currenthdr
)) {
217 /* Is there enough space for the next ext header? */
218 if (skb
->len
- ptr
< IPV6_OPTHDR_LEN
)
221 /* NONE or ESP: there isn't protocol part */
222 /* If we want to count these packets in '-p all',
223 * we will change the return 0 to 1*/
224 if ((currenthdr
== IPPROTO_NONE
) ||
225 (currenthdr
== IPPROTO_ESP
))
228 hp
= skb_header_pointer(skb
, ptr
, sizeof(_hdr
), &_hdr
);
231 /* Size calculation */
232 if (currenthdr
== IPPROTO_FRAGMENT
) {
233 fp
= skb_header_pointer(skb
,
234 ptr
+offsetof(struct frag_hdr
,
241 _fragoff
= ntohs(*fp
) & ~0x7;
243 } else if (currenthdr
== IPPROTO_AH
)
244 hdrlen
= (hp
->hdrlen
+2)<<2;
246 hdrlen
= ipv6_optlen(hp
);
248 currenthdr
= hp
->nexthdr
;
250 /* ptr is too large */
251 if ( ptr
> skb
->len
)
254 if (ip6t_ext_hdr(currenthdr
))
263 /* currenthdr contains the protocol header */
265 dprintf("Packet protocol %hi ?= %s%hi.\n",
267 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
270 if (ip6info
->proto
== currenthdr
) {
271 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
277 /* We need match for the '-p all', too! */
278 if ((ip6info
->proto
!= 0) &&
279 !(ip6info
->invflags
& IP6T_INV_PROTO
))
285 /* should be ip6 safe */
287 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
289 if (ipv6
->flags
& ~IP6T_F_MASK
) {
290 duprintf("Unknown flag bits set: %08X\n",
291 ipv6
->flags
& ~IP6T_F_MASK
);
294 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
295 duprintf("Unknown invflag bits set: %08X\n",
296 ipv6
->invflags
& ~IP6T_INV_MASK
);
303 ip6t_error(struct sk_buff
**pskb
,
304 const struct net_device
*in
,
305 const struct net_device
*out
,
306 unsigned int hooknum
,
307 const void *targinfo
,
311 printk("ip6_tables: error: `%s'\n", (char *)targinfo
);
317 int do_match(struct ip6t_entry_match
*m
,
318 const struct sk_buff
*skb
,
319 const struct net_device
*in
,
320 const struct net_device
*out
,
322 unsigned int protoff
,
325 /* Stop iteration if it doesn't match */
326 if (!m
->u
.kernel
.match
->match(skb
, in
, out
, m
->data
,
327 offset
, protoff
, hotdrop
))
333 static inline struct ip6t_entry
*
334 get_entry(void *base
, unsigned int offset
)
336 return (struct ip6t_entry
*)(base
+ offset
);
339 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
341 ip6t_do_table(struct sk_buff
**pskb
,
343 const struct net_device
*in
,
344 const struct net_device
*out
,
345 struct ip6t_table
*table
,
348 static const char nulldevname
[IFNAMSIZ
] __attribute__((aligned(sizeof(long))));
350 unsigned int protoff
= 0;
352 /* Initializing verdict to NF_DROP keeps gcc happy. */
353 unsigned int verdict
= NF_DROP
;
354 const char *indev
, *outdev
;
356 struct ip6t_entry
*e
, *back
;
359 indev
= in
? in
->name
: nulldevname
;
360 outdev
= out
? out
->name
: nulldevname
;
361 /* We handle fragments by dealing with the first fragment as
362 * if it was a normal packet. All other fragments are treated
363 * normally, except that they will NEVER match rules that ask
364 * things we don't know, ie. tcp syn flag or ports). If the
365 * rule is also a fragment-specific rule, non-fragments won't
368 read_lock_bh(&table
->lock
);
369 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
370 table_base
= (void *)table
->private->entries
[smp_processor_id()];
371 e
= get_entry(table_base
, table
->private->hook_entry
[hook
]);
373 #ifdef CONFIG_NETFILTER_DEBUG
374 /* Check noone else using our table */
375 if (((struct ip6t_entry
*)table_base
)->comefrom
!= 0xdead57ac
376 && ((struct ip6t_entry
*)table_base
)->comefrom
!= 0xeeeeeeec) {
377 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
380 &((struct ip6t_entry
*)table_base
)->comefrom
,
381 ((struct ip6t_entry
*)table_base
)->comefrom
);
383 ((struct ip6t_entry
*)table_base
)->comefrom
= 0x57acc001;
386 /* For return from builtin chain */
387 back
= get_entry(table_base
, table
->private->underflow
[hook
]);
392 if (ip6_packet_match(*pskb
, indev
, outdev
, &e
->ipv6
,
393 &protoff
, &offset
)) {
394 struct ip6t_entry_target
*t
;
396 if (IP6T_MATCH_ITERATE(e
, do_match
,
398 offset
, protoff
, &hotdrop
) != 0)
401 ADD_COUNTER(e
->counters
,
402 ntohs((*pskb
)->nh
.ipv6h
->payload_len
)
406 t
= ip6t_get_target(e
);
407 IP_NF_ASSERT(t
->u
.kernel
.target
);
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(pskb
,
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
= 0xdead57ac;
476 read_unlock_bh(&table
->lock
);
478 #ifdef DEBUG_ALLOW_ALL
488 * These are weird, but module loading must not be done with mutex
489 * held (since they will register), and we have to have a single
490 * function to use try_then_request_module().
493 /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
494 static inline struct ip6t_table
*find_table_lock(const char *name
)
496 struct ip6t_table
*t
;
498 if (down_interruptible(&ip6t_mutex
) != 0)
499 return ERR_PTR(-EINTR
);
501 list_for_each_entry(t
, &ip6t_tables
, list
)
502 if (strcmp(t
->name
, name
) == 0 && try_module_get(t
->me
))
508 /* Find match, grabs ref. Returns ERR_PTR() on error. */
509 static inline struct ip6t_match
*find_match(const char *name
, u8 revision
)
511 struct ip6t_match
*m
;
514 if (down_interruptible(&ip6t_mutex
) != 0)
515 return ERR_PTR(-EINTR
);
517 list_for_each_entry(m
, &ip6t_match
, list
) {
518 if (strcmp(m
->name
, name
) == 0) {
519 if (m
->revision
== revision
) {
520 if (try_module_get(m
->me
)) {
525 err
= -EPROTOTYPE
; /* Found something. */
532 /* Find target, grabs ref. Returns ERR_PTR() on error. */
533 static inline struct ip6t_target
*find_target(const char *name
, u8 revision
)
535 struct ip6t_target
*t
;
538 if (down_interruptible(&ip6t_mutex
) != 0)
539 return ERR_PTR(-EINTR
);
541 list_for_each_entry(t
, &ip6t_target
, list
) {
542 if (strcmp(t
->name
, name
) == 0) {
543 if (t
->revision
== revision
) {
544 if (try_module_get(t
->me
)) {
549 err
= -EPROTOTYPE
; /* Found something. */
556 struct ip6t_target
*ip6t_find_target(const char *name
, u8 revision
)
558 struct ip6t_target
*target
;
560 target
= try_then_request_module(find_target(name
, revision
),
562 if (IS_ERR(target
) || !target
)
567 static int match_revfn(const char *name
, u8 revision
, int *bestp
)
569 struct ip6t_match
*m
;
572 list_for_each_entry(m
, &ip6t_match
, list
) {
573 if (strcmp(m
->name
, name
) == 0) {
574 if (m
->revision
> *bestp
)
575 *bestp
= m
->revision
;
576 if (m
->revision
== revision
)
583 static int target_revfn(const char *name
, u8 revision
, int *bestp
)
585 struct ip6t_target
*t
;
588 list_for_each_entry(t
, &ip6t_target
, list
) {
589 if (strcmp(t
->name
, name
) == 0) {
590 if (t
->revision
> *bestp
)
591 *bestp
= t
->revision
;
592 if (t
->revision
== revision
)
599 /* Returns true or fals (if no such extension at all) */
600 static inline int find_revision(const char *name
, u8 revision
,
601 int (*revfn
)(const char *, u8
, int *),
604 int have_rev
, best
= -1;
606 if (down_interruptible(&ip6t_mutex
) != 0) {
610 have_rev
= revfn(name
, revision
, &best
);
613 /* Nothing at all? Return 0 to try loading module. */
621 *err
= -EPROTONOSUPPORT
;
626 /* All zeroes == unconditional rule. */
628 unconditional(const struct ip6t_ip6
*ipv6
)
632 for (i
= 0; i
< sizeof(*ipv6
); i
++)
633 if (((char *)ipv6
)[i
])
636 return (i
== sizeof(*ipv6
));
639 /* Figures out from what hook each rule can be called: returns 0 if
640 there are loops. Puts hook bitmask in comefrom. */
642 mark_source_chains(struct ip6t_table_info
*newinfo
,
643 unsigned int valid_hooks
, void *entry0
)
647 /* No recursion; use packet counter to save back ptrs (reset
648 to 0 as we leave), and comefrom to save source hook bitmask */
649 for (hook
= 0; hook
< NF_IP6_NUMHOOKS
; hook
++) {
650 unsigned int pos
= newinfo
->hook_entry
[hook
];
652 = (struct ip6t_entry
*)(entry0
+ pos
);
654 if (!(valid_hooks
& (1 << hook
)))
657 /* Set initial back pointer. */
658 e
->counters
.pcnt
= pos
;
661 struct ip6t_standard_target
*t
662 = (void *)ip6t_get_target(e
);
664 if (e
->comefrom
& (1 << NF_IP6_NUMHOOKS
)) {
665 printk("iptables: loop hook %u pos %u %08X.\n",
666 hook
, pos
, e
->comefrom
);
670 |= ((1 << hook
) | (1 << NF_IP6_NUMHOOKS
));
672 /* Unconditional return/END. */
673 if (e
->target_offset
== sizeof(struct ip6t_entry
)
674 && (strcmp(t
->target
.u
.user
.name
,
675 IP6T_STANDARD_TARGET
) == 0)
677 && unconditional(&e
->ipv6
)) {
678 unsigned int oldpos
, size
;
680 /* Return: backtrack through the last
683 e
->comefrom
^= (1<<NF_IP6_NUMHOOKS
);
684 #ifdef DEBUG_IP_FIREWALL_USER
686 & (1 << NF_IP6_NUMHOOKS
)) {
687 duprintf("Back unset "
694 pos
= e
->counters
.pcnt
;
695 e
->counters
.pcnt
= 0;
697 /* We're at the start. */
701 e
= (struct ip6t_entry
*)
703 } while (oldpos
== pos
+ e
->next_offset
);
706 size
= e
->next_offset
;
707 e
= (struct ip6t_entry
*)
708 (entry0
+ pos
+ size
);
709 e
->counters
.pcnt
= pos
;
712 int newpos
= t
->verdict
;
714 if (strcmp(t
->target
.u
.user
.name
,
715 IP6T_STANDARD_TARGET
) == 0
717 /* This a jump; chase it. */
718 duprintf("Jump rule %u -> %u\n",
721 /* ... this is a fallthru */
722 newpos
= pos
+ e
->next_offset
;
724 e
= (struct ip6t_entry
*)
726 e
->counters
.pcnt
= pos
;
731 duprintf("Finished chain %u\n", hook
);
737 cleanup_match(struct ip6t_entry_match
*m
, unsigned int *i
)
739 if (i
&& (*i
)-- == 0)
742 if (m
->u
.kernel
.match
->destroy
)
743 m
->u
.kernel
.match
->destroy(m
->data
,
744 m
->u
.match_size
- sizeof(*m
));
745 module_put(m
->u
.kernel
.match
->me
);
750 standard_check(const struct ip6t_entry_target
*t
,
751 unsigned int max_offset
)
753 struct ip6t_standard_target
*targ
= (void *)t
;
755 /* Check standard info. */
757 != IP6T_ALIGN(sizeof(struct ip6t_standard_target
))) {
758 duprintf("standard_check: target size %u != %u\n",
760 IP6T_ALIGN(sizeof(struct ip6t_standard_target
)));
764 if (targ
->verdict
>= 0
765 && targ
->verdict
> max_offset
- sizeof(struct ip6t_entry
)) {
766 duprintf("ip6t_standard_check: bad verdict (%i)\n",
771 if (targ
->verdict
< -NF_MAX_VERDICT
- 1) {
772 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
780 check_match(struct ip6t_entry_match
*m
,
782 const struct ip6t_ip6
*ipv6
,
783 unsigned int hookmask
,
786 struct ip6t_match
*match
;
788 match
= try_then_request_module(find_match(m
->u
.user
.name
,
790 "ip6t_%s", m
->u
.user
.name
);
791 if (IS_ERR(match
) || !match
) {
792 duprintf("check_match: `%s' not found\n", m
->u
.user
.name
);
793 return match
? PTR_ERR(match
) : -ENOENT
;
795 m
->u
.kernel
.match
= match
;
797 if (m
->u
.kernel
.match
->checkentry
798 && !m
->u
.kernel
.match
->checkentry(name
, ipv6
, m
->data
,
799 m
->u
.match_size
- sizeof(*m
),
801 module_put(m
->u
.kernel
.match
->me
);
802 duprintf("ip_tables: check failed for `%s'.\n",
803 m
->u
.kernel
.match
->name
);
811 static struct ip6t_target ip6t_standard_target
;
814 check_entry(struct ip6t_entry
*e
, const char *name
, unsigned int size
,
817 struct ip6t_entry_target
*t
;
818 struct ip6t_target
*target
;
822 if (!ip6_checkentry(&e
->ipv6
)) {
823 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
828 ret
= IP6T_MATCH_ITERATE(e
, check_match
, name
, &e
->ipv6
, e
->comefrom
, &j
);
830 goto cleanup_matches
;
832 t
= ip6t_get_target(e
);
833 target
= try_then_request_module(find_target(t
->u
.user
.name
,
835 "ip6t_%s", t
->u
.user
.name
);
836 if (IS_ERR(target
) || !target
) {
837 duprintf("check_entry: `%s' not found\n", t
->u
.user
.name
);
838 ret
= target
? PTR_ERR(target
) : -ENOENT
;
839 goto cleanup_matches
;
841 t
->u
.kernel
.target
= target
;
843 if (t
->u
.kernel
.target
== &ip6t_standard_target
) {
844 if (!standard_check(t
, size
)) {
846 goto cleanup_matches
;
848 } else if (t
->u
.kernel
.target
->checkentry
849 && !t
->u
.kernel
.target
->checkentry(name
, e
, t
->data
,
853 module_put(t
->u
.kernel
.target
->me
);
854 duprintf("ip_tables: check failed for `%s'.\n",
855 t
->u
.kernel
.target
->name
);
857 goto cleanup_matches
;
864 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
869 check_entry_size_and_hooks(struct ip6t_entry
*e
,
870 struct ip6t_table_info
*newinfo
,
872 unsigned char *limit
,
873 const unsigned int *hook_entries
,
874 const unsigned int *underflows
,
879 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0
880 || (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
881 duprintf("Bad offset %p\n", e
);
886 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
887 duprintf("checking: element %p size %u\n",
892 /* Check hooks & underflows */
893 for (h
= 0; h
< NF_IP6_NUMHOOKS
; h
++) {
894 if ((unsigned char *)e
- base
== hook_entries
[h
])
895 newinfo
->hook_entry
[h
] = hook_entries
[h
];
896 if ((unsigned char *)e
- base
== underflows
[h
])
897 newinfo
->underflow
[h
] = underflows
[h
];
900 /* FIXME: underflows must be unconditional, standard verdicts
901 < 0 (not IP6T_RETURN). --RR */
903 /* Clear counters and comefrom */
904 e
->counters
= ((struct ip6t_counters
) { 0, 0 });
912 cleanup_entry(struct ip6t_entry
*e
, unsigned int *i
)
914 struct ip6t_entry_target
*t
;
916 if (i
&& (*i
)-- == 0)
919 /* Cleanup all matches */
920 IP6T_MATCH_ITERATE(e
, cleanup_match
, NULL
);
921 t
= ip6t_get_target(e
);
922 if (t
->u
.kernel
.target
->destroy
)
923 t
->u
.kernel
.target
->destroy(t
->data
,
924 t
->u
.target_size
- sizeof(*t
));
925 module_put(t
->u
.kernel
.target
->me
);
929 /* Checks and translates the user-supplied table segment (held in
932 translate_table(const char *name
,
933 unsigned int valid_hooks
,
934 struct ip6t_table_info
*newinfo
,
938 const unsigned int *hook_entries
,
939 const unsigned int *underflows
)
944 newinfo
->size
= size
;
945 newinfo
->number
= number
;
947 /* Init all hooks to impossible value. */
948 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
949 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
950 newinfo
->underflow
[i
] = 0xFFFFFFFF;
953 duprintf("translate_table: size %u\n", newinfo
->size
);
955 /* Walk through entries, checking offsets. */
956 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
957 check_entry_size_and_hooks
,
961 hook_entries
, underflows
, &i
);
966 duprintf("translate_table: %u not %u entries\n",
971 /* Check hooks all assigned */
972 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
973 /* Only hooks which are valid */
974 if (!(valid_hooks
& (1 << i
)))
976 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
977 duprintf("Invalid hook entry %u %u\n",
981 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
982 duprintf("Invalid underflow %u %u\n",
988 if (!mark_source_chains(newinfo
, valid_hooks
, entry0
))
991 /* Finally, each sanity check must pass */
993 ret
= IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
994 check_entry
, name
, size
, &i
);
997 IP6T_ENTRY_ITERATE(entry0
, newinfo
->size
,
1002 /* And one copy for every other CPU */
1004 if (newinfo
->entries
[i
] && newinfo
->entries
[i
] != entry0
)
1005 memcpy(newinfo
->entries
[i
], entry0
, newinfo
->size
);
1011 static struct ip6t_table_info
*
1012 replace_table(struct ip6t_table
*table
,
1013 unsigned int num_counters
,
1014 struct ip6t_table_info
*newinfo
,
1017 struct ip6t_table_info
*oldinfo
;
1019 #ifdef CONFIG_NETFILTER_DEBUG
1024 struct ip6t_entry
*table_base
= newinfo
->entries
[cpu
];
1026 table_base
->comefrom
= 0xdead57ac;
1031 /* Do the substitution. */
1032 write_lock_bh(&table
->lock
);
1033 /* Check inside lock: is the old number correct? */
1034 if (num_counters
!= table
->private->number
) {
1035 duprintf("num_counters != table->private->number (%u/%u)\n",
1036 num_counters
, table
->private->number
);
1037 write_unlock_bh(&table
->lock
);
1041 oldinfo
= table
->private;
1042 table
->private = newinfo
;
1043 newinfo
->initial_entries
= oldinfo
->initial_entries
;
1044 write_unlock_bh(&table
->lock
);
1049 /* Gets counters. */
1051 add_entry_to_counter(const struct ip6t_entry
*e
,
1052 struct ip6t_counters total
[],
1055 ADD_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
1062 set_entry_to_counter(const struct ip6t_entry
*e
,
1063 struct ip6t_counters total
[],
1066 SET_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
1073 get_counters(const struct ip6t_table_info
*t
,
1074 struct ip6t_counters counters
[])
1078 unsigned int curcpu
;
1080 /* Instead of clearing (by a previous call to memset())
1081 * the counters and using adds, we set the counters
1082 * with data used by 'current' CPU
1083 * We dont care about preemption here.
1085 curcpu
= raw_smp_processor_id();
1088 IP6T_ENTRY_ITERATE(t
->entries
[curcpu
],
1090 set_entry_to_counter
,
1098 IP6T_ENTRY_ITERATE(t
->entries
[cpu
],
1100 add_entry_to_counter
,
1107 copy_entries_to_user(unsigned int total_size
,
1108 struct ip6t_table
*table
,
1109 void __user
*userptr
)
1111 unsigned int off
, num
, countersize
;
1112 struct ip6t_entry
*e
;
1113 struct ip6t_counters
*counters
;
1115 void *loc_cpu_entry
;
1117 /* We need atomic snapshot of counters: rest doesn't change
1118 (other than comefrom, which userspace doesn't care
1120 countersize
= sizeof(struct ip6t_counters
) * table
->private->number
;
1121 counters
= vmalloc(countersize
);
1123 if (counters
== NULL
)
1126 /* First, sum counters... */
1127 write_lock_bh(&table
->lock
);
1128 get_counters(table
->private, counters
);
1129 write_unlock_bh(&table
->lock
);
1131 /* choose the copy that is on ourc node/cpu */
1132 loc_cpu_entry
= table
->private->entries
[raw_smp_processor_id()];
1133 if (copy_to_user(userptr
, loc_cpu_entry
, total_size
) != 0) {
1138 /* FIXME: use iterator macros --RR */
1139 /* ... then go back and fix counters and names */
1140 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
1142 struct ip6t_entry_match
*m
;
1143 struct ip6t_entry_target
*t
;
1145 e
= (struct ip6t_entry
*)(loc_cpu_entry
+ off
);
1146 if (copy_to_user(userptr
+ off
1147 + offsetof(struct ip6t_entry
, counters
),
1149 sizeof(counters
[num
])) != 0) {
1154 for (i
= sizeof(struct ip6t_entry
);
1155 i
< e
->target_offset
;
1156 i
+= m
->u
.match_size
) {
1159 if (copy_to_user(userptr
+ off
+ i
1160 + offsetof(struct ip6t_entry_match
,
1162 m
->u
.kernel
.match
->name
,
1163 strlen(m
->u
.kernel
.match
->name
)+1)
1170 t
= ip6t_get_target(e
);
1171 if (copy_to_user(userptr
+ off
+ e
->target_offset
1172 + offsetof(struct ip6t_entry_target
,
1174 t
->u
.kernel
.target
->name
,
1175 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
1187 get_entries(const struct ip6t_get_entries
*entries
,
1188 struct ip6t_get_entries __user
*uptr
)
1191 struct ip6t_table
*t
;
1193 t
= find_table_lock(entries
->name
);
1194 if (t
&& !IS_ERR(t
)) {
1195 duprintf("t->private->number = %u\n",
1196 t
->private->number
);
1197 if (entries
->size
== t
->private->size
)
1198 ret
= copy_entries_to_user(t
->private->size
,
1199 t
, uptr
->entrytable
);
1201 duprintf("get_entries: I've got %u not %u!\n",
1209 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1214 static void free_table_info(struct ip6t_table_info
*info
)
1218 if (info
->size
<= PAGE_SIZE
)
1219 kfree(info
->entries
[cpu
]);
1221 vfree(info
->entries
[cpu
]);
1226 static struct ip6t_table_info
*alloc_table_info(unsigned int size
)
1228 struct ip6t_table_info
*newinfo
;
1231 newinfo
= kzalloc(sizeof(struct ip6t_table_info
), GFP_KERNEL
);
1235 newinfo
->size
= size
;
1238 if (size
<= PAGE_SIZE
)
1239 newinfo
->entries
[cpu
] = kmalloc_node(size
,
1243 newinfo
->entries
[cpu
] = vmalloc_node(size
,
1245 if (newinfo
->entries
[cpu
] == NULL
) {
1246 free_table_info(newinfo
);
1255 do_replace(void __user
*user
, unsigned int len
)
1258 struct ip6t_replace tmp
;
1259 struct ip6t_table
*t
;
1260 struct ip6t_table_info
*newinfo
, *oldinfo
;
1261 struct ip6t_counters
*counters
;
1262 void *loc_cpu_entry
, *loc_cpu_old_entry
;
1264 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1267 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1268 if ((SMP_ALIGN(tmp
.size
) >> PAGE_SHIFT
) + 2 > num_physpages
)
1271 newinfo
= alloc_table_info(tmp
.size
);
1275 /* choose the copy that is on our node/cpu */
1276 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1277 if (copy_from_user(loc_cpu_entry
, user
+ sizeof(tmp
),
1283 counters
= vmalloc(tmp
.num_counters
* sizeof(struct ip6t_counters
));
1289 ret
= translate_table(tmp
.name
, tmp
.valid_hooks
,
1290 newinfo
, loc_cpu_entry
, tmp
.size
, tmp
.num_entries
,
1291 tmp
.hook_entry
, tmp
.underflow
);
1293 goto free_newinfo_counters
;
1295 duprintf("ip_tables: Translated table\n");
1297 t
= try_then_request_module(find_table_lock(tmp
.name
),
1298 "ip6table_%s", tmp
.name
);
1299 if (!t
|| IS_ERR(t
)) {
1300 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1301 goto free_newinfo_counters_untrans
;
1305 if (tmp
.valid_hooks
!= t
->valid_hooks
) {
1306 duprintf("Valid hook crap: %08X vs %08X\n",
1307 tmp
.valid_hooks
, t
->valid_hooks
);
1312 oldinfo
= replace_table(t
, tmp
.num_counters
, newinfo
, &ret
);
1316 /* Update module usage count based on number of rules */
1317 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1318 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1319 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1320 (newinfo
->number
<= oldinfo
->initial_entries
))
1322 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1323 (newinfo
->number
<= oldinfo
->initial_entries
))
1326 /* Get the old counters. */
1327 get_counters(oldinfo
, counters
);
1328 /* Decrease module usage counts and free resource */
1329 loc_cpu_old_entry
= oldinfo
->entries
[raw_smp_processor_id()];
1330 IP6T_ENTRY_ITERATE(loc_cpu_old_entry
, oldinfo
->size
, cleanup_entry
,NULL
);
1331 free_table_info(oldinfo
);
1332 if (copy_to_user(tmp
.counters
, counters
,
1333 sizeof(struct ip6t_counters
) * tmp
.num_counters
) != 0)
1342 free_newinfo_counters_untrans
:
1343 IP6T_ENTRY_ITERATE(loc_cpu_entry
, newinfo
->size
, cleanup_entry
,NULL
);
1344 free_newinfo_counters
:
1347 free_table_info(newinfo
);
1351 /* We're lazy, and add to the first CPU; overflow works its fey magic
1352 * and everything is OK. */
1354 add_counter_to_entry(struct ip6t_entry
*e
,
1355 const struct ip6t_counters addme
[],
1359 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1361 (long unsigned int)e
->counters
.pcnt
,
1362 (long unsigned int)e
->counters
.bcnt
,
1363 (long unsigned int)addme
[*i
].pcnt
,
1364 (long unsigned int)addme
[*i
].bcnt
);
1367 ADD_COUNTER(e
->counters
, addme
[*i
].bcnt
, addme
[*i
].pcnt
);
1374 do_add_counters(void __user
*user
, unsigned int len
)
1377 struct ip6t_counters_info tmp
, *paddc
;
1378 struct ip6t_table
*t
;
1380 void *loc_cpu_entry
;
1382 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1385 if (len
!= sizeof(tmp
) + tmp
.num_counters
*sizeof(struct ip6t_counters
))
1388 paddc
= vmalloc(len
);
1392 if (copy_from_user(paddc
, user
, len
) != 0) {
1397 t
= find_table_lock(tmp
.name
);
1398 if (!t
|| IS_ERR(t
)) {
1399 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1403 write_lock_bh(&t
->lock
);
1404 if (t
->private->number
!= paddc
->num_counters
) {
1406 goto unlock_up_free
;
1410 /* Choose the copy that is on our node */
1411 loc_cpu_entry
= t
->private->entries
[smp_processor_id()];
1412 IP6T_ENTRY_ITERATE(loc_cpu_entry
,
1414 add_counter_to_entry
,
1418 write_unlock_bh(&t
->lock
);
1428 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
1432 if (!capable(CAP_NET_ADMIN
))
1436 case IP6T_SO_SET_REPLACE
:
1437 ret
= do_replace(user
, len
);
1440 case IP6T_SO_SET_ADD_COUNTERS
:
1441 ret
= do_add_counters(user
, len
);
1445 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
1453 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1457 if (!capable(CAP_NET_ADMIN
))
1461 case IP6T_SO_GET_INFO
: {
1462 char name
[IP6T_TABLE_MAXNAMELEN
];
1463 struct ip6t_table
*t
;
1465 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1466 duprintf("length %u != %u\n", *len
,
1467 sizeof(struct ip6t_getinfo
));
1472 if (copy_from_user(name
, user
, sizeof(name
)) != 0) {
1476 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1478 t
= try_then_request_module(find_table_lock(name
),
1479 "ip6table_%s", name
);
1480 if (t
&& !IS_ERR(t
)) {
1481 struct ip6t_getinfo info
;
1483 info
.valid_hooks
= t
->valid_hooks
;
1484 memcpy(info
.hook_entry
, t
->private->hook_entry
,
1485 sizeof(info
.hook_entry
));
1486 memcpy(info
.underflow
, t
->private->underflow
,
1487 sizeof(info
.underflow
));
1488 info
.num_entries
= t
->private->number
;
1489 info
.size
= t
->private->size
;
1490 memcpy(info
.name
, name
, sizeof(info
.name
));
1492 if (copy_to_user(user
, &info
, *len
) != 0)
1499 ret
= t
? PTR_ERR(t
) : -ENOENT
;
1503 case IP6T_SO_GET_ENTRIES
: {
1504 struct ip6t_get_entries get
;
1506 if (*len
< sizeof(get
)) {
1507 duprintf("get_entries: %u < %u\n", *len
, sizeof(get
));
1509 } else if (copy_from_user(&get
, user
, sizeof(get
)) != 0) {
1511 } else if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1512 duprintf("get_entries: %u != %u\n", *len
,
1513 sizeof(struct ip6t_get_entries
) + get
.size
);
1516 ret
= get_entries(&get
, user
);
1520 case IP6T_SO_GET_REVISION_MATCH
:
1521 case IP6T_SO_GET_REVISION_TARGET
: {
1522 struct ip6t_get_revision rev
;
1523 int (*revfn
)(const char *, u8
, int *);
1525 if (*len
!= sizeof(rev
)) {
1529 if (copy_from_user(&rev
, user
, sizeof(rev
)) != 0) {
1534 if (cmd
== IP6T_SO_GET_REVISION_TARGET
)
1535 revfn
= target_revfn
;
1537 revfn
= match_revfn
;
1539 try_then_request_module(find_revision(rev
.name
, rev
.revision
,
1541 "ip6t_%s", rev
.name
);
1546 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
1553 /* Registration hooks for targets. */
1555 ip6t_register_target(struct ip6t_target
*target
)
1559 ret
= down_interruptible(&ip6t_mutex
);
1562 list_add(&target
->list
, &ip6t_target
);
1568 ip6t_unregister_target(struct ip6t_target
*target
)
1571 LIST_DELETE(&ip6t_target
, target
);
1576 ip6t_register_match(struct ip6t_match
*match
)
1580 ret
= down_interruptible(&ip6t_mutex
);
1584 list_add(&match
->list
, &ip6t_match
);
1591 ip6t_unregister_match(struct ip6t_match
*match
)
1594 LIST_DELETE(&ip6t_match
, match
);
1598 int ip6t_register_table(struct ip6t_table
*table
,
1599 const struct ip6t_replace
*repl
)
1602 struct ip6t_table_info
*newinfo
;
1603 static struct ip6t_table_info bootstrap
1604 = { 0, 0, 0, { 0 }, { 0 }, { } };
1605 void *loc_cpu_entry
;
1607 newinfo
= alloc_table_info(repl
->size
);
1611 /* choose the copy on our node/cpu */
1612 loc_cpu_entry
= newinfo
->entries
[raw_smp_processor_id()];
1613 memcpy(loc_cpu_entry
, repl
->entries
, repl
->size
);
1615 ret
= translate_table(table
->name
, table
->valid_hooks
,
1616 newinfo
, loc_cpu_entry
, repl
->size
,
1621 free_table_info(newinfo
);
1625 ret
= down_interruptible(&ip6t_mutex
);
1627 free_table_info(newinfo
);
1631 /* Don't autoload: we'd eat our tail... */
1632 if (list_named_find(&ip6t_tables
, table
->name
)) {
1637 /* Simplifies replace_table code. */
1638 table
->private = &bootstrap
;
1639 if (!replace_table(table
, 0, newinfo
, &ret
))
1642 duprintf("table->private->number = %u\n",
1643 table
->private->number
);
1645 /* save number of initial entries */
1646 table
->private->initial_entries
= table
->private->number
;
1648 rwlock_init(&table
->lock
);
1649 list_prepend(&ip6t_tables
, table
);
1656 free_table_info(newinfo
);
1660 void ip6t_unregister_table(struct ip6t_table
*table
)
1662 void *loc_cpu_entry
;
1665 LIST_DELETE(&ip6t_tables
, table
);
1668 /* Decrease module usage counts and free resources */
1669 loc_cpu_entry
= table
->private->entries
[raw_smp_processor_id()];
1670 IP6T_ENTRY_ITERATE(loc_cpu_entry
, table
->private->size
,
1671 cleanup_entry
, NULL
);
1672 free_table_info(table
->private);
1675 /* Returns 1 if the port is matched by the range, 0 otherwise */
1677 port_match(u_int16_t min
, u_int16_t max
, u_int16_t port
, int invert
)
1681 ret
= (port
>= min
&& port
<= max
) ^ invert
;
1686 tcp_find_option(u_int8_t option
,
1687 const struct sk_buff
*skb
,
1688 unsigned int tcpoff
,
1689 unsigned int optlen
,
1693 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1694 u_int8_t _opt
[60 - sizeof(struct tcphdr
)], *op
;
1697 duprintf("tcp_match: finding option\n");
1700 /* If we don't have the whole header, drop packet. */
1701 op
= skb_header_pointer(skb
, tcpoff
+ sizeof(struct tcphdr
), optlen
,
1708 for (i
= 0; i
< optlen
; ) {
1709 if (op
[i
] == option
) return !invert
;
1711 else i
+= op
[i
+1]?:1;
1718 tcp_match(const struct sk_buff
*skb
,
1719 const struct net_device
*in
,
1720 const struct net_device
*out
,
1721 const void *matchinfo
,
1723 unsigned int protoff
,
1726 struct tcphdr _tcph
, *th
;
1727 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1732 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1733 causes this. Its a cracker trying to break in by doing a
1734 flag overwrite to pass the direction checks.
1737 duprintf("Dropping evil TCP offset=1 frag.\n");
1740 /* Must not be a fragment. */
1744 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1746 th
= skb_header_pointer(skb
, protoff
, sizeof(_tcph
), &_tcph
);
1748 /* We've been asked to examine this packet, and we
1749 can't. Hence, no choice but to drop. */
1750 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1755 if (!port_match(tcpinfo
->spts
[0], tcpinfo
->spts
[1],
1757 !!(tcpinfo
->invflags
& IP6T_TCP_INV_SRCPT
)))
1759 if (!port_match(tcpinfo
->dpts
[0], tcpinfo
->dpts
[1],
1761 !!(tcpinfo
->invflags
& IP6T_TCP_INV_DSTPT
)))
1763 if (!FWINVTCP((((unsigned char *)th
)[13] & tcpinfo
->flg_mask
)
1764 == tcpinfo
->flg_cmp
,
1765 IP6T_TCP_INV_FLAGS
))
1767 if (tcpinfo
->option
) {
1768 if (th
->doff
* 4 < sizeof(_tcph
)) {
1772 if (!tcp_find_option(tcpinfo
->option
, skb
, protoff
,
1773 th
->doff
*4 - sizeof(*th
),
1774 tcpinfo
->invflags
& IP6T_TCP_INV_OPTION
,
1781 /* Called when user tries to insert an entry of this type. */
1783 tcp_checkentry(const char *tablename
,
1784 const struct ip6t_ip6
*ipv6
,
1786 unsigned int matchsize
,
1787 unsigned int hook_mask
)
1789 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1791 /* Must specify proto == TCP, and no unknown invflags */
1792 return ipv6
->proto
== IPPROTO_TCP
1793 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1794 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_tcp
))
1795 && !(tcpinfo
->invflags
& ~IP6T_TCP_INV_MASK
);
1799 udp_match(const struct sk_buff
*skb
,
1800 const struct net_device
*in
,
1801 const struct net_device
*out
,
1802 const void *matchinfo
,
1804 unsigned int protoff
,
1807 struct udphdr _udph
, *uh
;
1808 const struct ip6t_udp
*udpinfo
= matchinfo
;
1810 /* Must not be a fragment. */
1814 uh
= skb_header_pointer(skb
, protoff
, sizeof(_udph
), &_udph
);
1816 /* We've been asked to examine this packet, and we
1817 can't. Hence, no choice but to drop. */
1818 duprintf("Dropping evil UDP tinygram.\n");
1823 return port_match(udpinfo
->spts
[0], udpinfo
->spts
[1],
1825 !!(udpinfo
->invflags
& IP6T_UDP_INV_SRCPT
))
1826 && port_match(udpinfo
->dpts
[0], udpinfo
->dpts
[1],
1828 !!(udpinfo
->invflags
& IP6T_UDP_INV_DSTPT
));
1831 /* Called when user tries to insert an entry of this type. */
1833 udp_checkentry(const char *tablename
,
1834 const struct ip6t_ip6
*ipv6
,
1836 unsigned int matchinfosize
,
1837 unsigned int hook_mask
)
1839 const struct ip6t_udp
*udpinfo
= matchinfo
;
1841 /* Must specify proto == UDP, and no unknown invflags */
1842 if (ipv6
->proto
!= IPPROTO_UDP
|| (ipv6
->invflags
& IP6T_INV_PROTO
)) {
1843 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6
->proto
,
1847 if (matchinfosize
!= IP6T_ALIGN(sizeof(struct ip6t_udp
))) {
1848 duprintf("ip6t_udp: matchsize %u != %u\n",
1849 matchinfosize
, IP6T_ALIGN(sizeof(struct ip6t_udp
)));
1852 if (udpinfo
->invflags
& ~IP6T_UDP_INV_MASK
) {
1853 duprintf("ip6t_udp: unknown flags %X\n",
1861 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1863 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
1864 u_int8_t type
, u_int8_t code
,
1867 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
1872 icmp6_match(const struct sk_buff
*skb
,
1873 const struct net_device
*in
,
1874 const struct net_device
*out
,
1875 const void *matchinfo
,
1877 unsigned int protoff
,
1880 struct icmp6hdr _icmp
, *ic
;
1881 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1883 /* Must not be a fragment. */
1887 ic
= skb_header_pointer(skb
, protoff
, sizeof(_icmp
), &_icmp
);
1889 /* We've been asked to examine this packet, and we
1890 can't. Hence, no choice but to drop. */
1891 duprintf("Dropping evil ICMP tinygram.\n");
1896 return icmp6_type_code_match(icmpinfo
->type
,
1899 ic
->icmp6_type
, ic
->icmp6_code
,
1900 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
1903 /* Called when user tries to insert an entry of this type. */
1905 icmp6_checkentry(const char *tablename
,
1906 const struct ip6t_ip6
*ipv6
,
1908 unsigned int matchsize
,
1909 unsigned int hook_mask
)
1911 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1913 /* Must specify proto == ICMP, and no unknown invflags */
1914 return ipv6
->proto
== IPPROTO_ICMPV6
1915 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1916 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_icmp
))
1917 && !(icmpinfo
->invflags
& ~IP6T_ICMP_INV
);
1920 /* The built-in targets: standard (NULL) and error. */
1921 static struct ip6t_target ip6t_standard_target
= {
1922 .name
= IP6T_STANDARD_TARGET
,
1925 static struct ip6t_target ip6t_error_target
= {
1926 .name
= IP6T_ERROR_TARGET
,
1927 .target
= ip6t_error
,
1930 static struct nf_sockopt_ops ip6t_sockopts
= {
1932 .set_optmin
= IP6T_BASE_CTL
,
1933 .set_optmax
= IP6T_SO_SET_MAX
+1,
1934 .set
= do_ip6t_set_ctl
,
1935 .get_optmin
= IP6T_BASE_CTL
,
1936 .get_optmax
= IP6T_SO_GET_MAX
+1,
1937 .get
= do_ip6t_get_ctl
,
1940 static struct ip6t_match tcp_matchstruct
= {
1942 .match
= &tcp_match
,
1943 .checkentry
= &tcp_checkentry
,
1946 static struct ip6t_match udp_matchstruct
= {
1948 .match
= &udp_match
,
1949 .checkentry
= &udp_checkentry
,
1952 static struct ip6t_match icmp6_matchstruct
= {
1954 .match
= &icmp6_match
,
1955 .checkentry
= &icmp6_checkentry
,
1958 #ifdef CONFIG_PROC_FS
1959 static inline int print_name(const char *i
,
1960 off_t start_offset
, char *buffer
, int length
,
1961 off_t
*pos
, unsigned int *count
)
1963 if ((*count
)++ >= start_offset
) {
1964 unsigned int namelen
;
1966 namelen
= sprintf(buffer
+ *pos
, "%s\n",
1967 i
+ sizeof(struct list_head
));
1968 if (*pos
+ namelen
> length
) {
1969 /* Stop iterating */
1977 static inline int print_target(const struct ip6t_target
*t
,
1978 off_t start_offset
, char *buffer
, int length
,
1979 off_t
*pos
, unsigned int *count
)
1981 if (t
== &ip6t_standard_target
|| t
== &ip6t_error_target
)
1983 return print_name((char *)t
, start_offset
, buffer
, length
, pos
, count
);
1986 static int ip6t_get_tables(char *buffer
, char **start
, off_t offset
, int length
)
1989 unsigned int count
= 0;
1991 if (down_interruptible(&ip6t_mutex
) != 0)
1994 LIST_FIND(&ip6t_tables
, print_name
, char *,
1995 offset
, buffer
, length
, &pos
, &count
);
1999 /* `start' hack - see fs/proc/generic.c line ~105 */
2000 *start
=(char *)((unsigned long)count
-offset
);
2004 static int ip6t_get_targets(char *buffer
, char **start
, off_t offset
, int length
)
2007 unsigned int count
= 0;
2009 if (down_interruptible(&ip6t_mutex
) != 0)
2012 LIST_FIND(&ip6t_target
, print_target
, struct ip6t_target
*,
2013 offset
, buffer
, length
, &pos
, &count
);
2017 *start
= (char *)((unsigned long)count
- offset
);
2021 static int ip6t_get_matches(char *buffer
, char **start
, off_t offset
, int length
)
2024 unsigned int count
= 0;
2026 if (down_interruptible(&ip6t_mutex
) != 0)
2029 LIST_FIND(&ip6t_match
, print_name
, char *,
2030 offset
, buffer
, length
, &pos
, &count
);
2034 *start
= (char *)((unsigned long)count
- offset
);
2038 static const struct { char *name
; get_info_t
*get_info
; } ip6t_proc_entry
[] =
2039 { { "ip6_tables_names", ip6t_get_tables
},
2040 { "ip6_tables_targets", ip6t_get_targets
},
2041 { "ip6_tables_matches", ip6t_get_matches
},
2043 #endif /*CONFIG_PROC_FS*/
2045 static int __init
init(void)
2049 /* Noone else will be downing sem now, so we won't sleep */
2051 list_append(&ip6t_target
, &ip6t_standard_target
);
2052 list_append(&ip6t_target
, &ip6t_error_target
);
2053 list_append(&ip6t_match
, &tcp_matchstruct
);
2054 list_append(&ip6t_match
, &udp_matchstruct
);
2055 list_append(&ip6t_match
, &icmp6_matchstruct
);
2058 /* Register setsockopt */
2059 ret
= nf_register_sockopt(&ip6t_sockopts
);
2061 duprintf("Unable to register sockopts.\n");
2065 #ifdef CONFIG_PROC_FS
2067 struct proc_dir_entry
*proc
;
2070 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++) {
2071 proc
= proc_net_create(ip6t_proc_entry
[i
].name
, 0,
2072 ip6t_proc_entry
[i
].get_info
);
2075 proc_net_remove(ip6t_proc_entry
[i
].name
);
2076 nf_unregister_sockopt(&ip6t_sockopts
);
2079 proc
->owner
= THIS_MODULE
;
2084 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2088 static void __exit
fini(void)
2090 nf_unregister_sockopt(&ip6t_sockopts
);
2091 #ifdef CONFIG_PROC_FS
2094 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++)
2095 proc_net_remove(ip6t_proc_entry
[i
].name
);
2101 * find specified header up to transport protocol header.
2102 * If found target header, the offset to the header is set to *offset
2103 * and return 0. otherwise, return -1.
2105 * Notes: - non-1st Fragment Header isn't skipped.
2106 * - ESP header isn't skipped.
2107 * - The target header may be trancated.
2109 int ipv6_find_hdr(const struct sk_buff
*skb
, unsigned int *offset
, u8 target
)
2111 unsigned int start
= (u8
*)(skb
->nh
.ipv6h
+ 1) - skb
->data
;
2112 u8 nexthdr
= skb
->nh
.ipv6h
->nexthdr
;
2113 unsigned int len
= skb
->len
- start
;
2115 while (nexthdr
!= target
) {
2116 struct ipv6_opt_hdr _hdr
, *hp
;
2117 unsigned int hdrlen
;
2119 if ((!ipv6_ext_hdr(nexthdr
)) || nexthdr
== NEXTHDR_NONE
)
2121 hp
= skb_header_pointer(skb
, start
, sizeof(_hdr
), &_hdr
);
2124 if (nexthdr
== NEXTHDR_FRAGMENT
) {
2125 unsigned short _frag_off
, *fp
;
2126 fp
= skb_header_pointer(skb
,
2127 start
+offsetof(struct frag_hdr
,
2134 if (ntohs(*fp
) & ~0x7)
2137 } else if (nexthdr
== NEXTHDR_AUTH
)
2138 hdrlen
= (hp
->hdrlen
+ 2) << 2;
2140 hdrlen
= ipv6_optlen(hp
);
2142 nexthdr
= hp
->nexthdr
;
2151 EXPORT_SYMBOL(ip6t_register_table
);
2152 EXPORT_SYMBOL(ip6t_unregister_table
);
2153 EXPORT_SYMBOL(ip6t_do_table
);
2154 EXPORT_SYMBOL(ip6t_register_match
);
2155 EXPORT_SYMBOL(ip6t_unregister_match
);
2156 EXPORT_SYMBOL(ip6t_register_target
);
2157 EXPORT_SYMBOL(ip6t_unregister_target
);
2158 EXPORT_SYMBOL(ip6t_ext_hdr
);
2159 EXPORT_SYMBOL(ipv6_find_hdr
);