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/lockhelp.h>
75 #include <linux/netfilter_ipv4/listhelp.h>
78 /* All the better to debug you with... */
83 /* Locking is simple: we assume at worst case there will be one packet
84 in user context and one from bottom halves (or soft irq if Alexey's
85 softnet patch was applied).
87 We keep a set of rules for each CPU, so we can avoid write-locking
88 them; doing a readlock_bh() stops packets coming through if we're
91 To be cache friendly on SMP, we arrange them like so:
93 ... cache-align padding ...
96 Hence the start of any table is given by get_table() below. */
98 /* The table itself */
99 struct ip6t_table_info
103 /* Number of entries: FIXME. --RR */
105 /* Initial number of entries. Needed for module usage count */
106 unsigned int initial_entries
;
108 /* Entry points and underflows */
109 unsigned int hook_entry
[NF_IP6_NUMHOOKS
];
110 unsigned int underflow
[NF_IP6_NUMHOOKS
];
112 /* ip6t_entry tables: one per CPU */
113 char entries
[0] ____cacheline_aligned
;
116 static LIST_HEAD(ip6t_target
);
117 static LIST_HEAD(ip6t_match
);
118 static LIST_HEAD(ip6t_tables
);
119 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
122 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
124 #define TABLE_OFFSET(t,p) 0
128 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
129 #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; })
130 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
133 static int ip6_masked_addrcmp(struct in6_addr addr1
, struct in6_addr mask
,
134 struct in6_addr addr2
)
137 for( i
= 0; i
< 16; i
++){
138 if((addr1
.s6_addr
[i
] & mask
.s6_addr
[i
]) !=
139 (addr2
.s6_addr
[i
] & mask
.s6_addr
[i
]))
145 /* Check for an extension */
147 ip6t_ext_hdr(u8 nexthdr
)
149 return ( (nexthdr
== IPPROTO_HOPOPTS
) ||
150 (nexthdr
== IPPROTO_ROUTING
) ||
151 (nexthdr
== IPPROTO_FRAGMENT
) ||
152 (nexthdr
== IPPROTO_ESP
) ||
153 (nexthdr
== IPPROTO_AH
) ||
154 (nexthdr
== IPPROTO_NONE
) ||
155 (nexthdr
== IPPROTO_DSTOPTS
) );
158 /* Returns whether matches rule or not. */
160 ip6_packet_match(const struct sk_buff
*skb
,
161 const struct ipv6hdr
*ipv6
,
164 const struct ip6t_ip6
*ip6info
,
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
*hdrptr
;
220 u_int16_t ptr
; /* Header offset in skb */
221 u_int16_t hdrlen
; /* Header */
225 while (ip6t_ext_hdr(currenthdr
)) {
226 /* Is there enough space for the next ext header? */
227 if (skb
->len
- ptr
< IPV6_OPTHDR_LEN
)
230 /* NONE or ESP: there isn't protocol part */
231 /* If we want to count these packets in '-p all',
232 * we will change the return 0 to 1*/
233 if ((currenthdr
== IPPROTO_NONE
) ||
234 (currenthdr
== IPPROTO_ESP
))
237 hdrptr
= (struct ipv6_opt_hdr
*)(skb
->data
+ ptr
);
239 /* Size calculation */
240 if (currenthdr
== IPPROTO_FRAGMENT
) {
242 } else if (currenthdr
== IPPROTO_AH
)
243 hdrlen
= (hdrptr
->hdrlen
+2)<<2;
245 hdrlen
= ipv6_optlen(hdrptr
);
247 currenthdr
= hdrptr
->nexthdr
;
249 /* ptr is too large */
250 if ( ptr
> skb
->len
)
254 /* currenthdr contains the protocol header */
256 dprintf("Packet protocol %hi ?= %s%hi.\n",
258 ip6info
->invflags
& IP6T_INV_PROTO
? "!":"",
261 if (ip6info
->proto
== currenthdr
) {
262 if(ip6info
->invflags
& IP6T_INV_PROTO
) {
268 /* We need match for the '-p all', too! */
269 if ((ip6info
->proto
!= 0) &&
270 !(ip6info
->invflags
& IP6T_INV_PROTO
))
276 /* should be ip6 safe */
278 ip6_checkentry(const struct ip6t_ip6
*ipv6
)
280 if (ipv6
->flags
& ~IP6T_F_MASK
) {
281 duprintf("Unknown flag bits set: %08X\n",
282 ipv6
->flags
& ~IP6T_F_MASK
);
285 if (ipv6
->invflags
& ~IP6T_INV_MASK
) {
286 duprintf("Unknown invflag bits set: %08X\n",
287 ipv6
->invflags
& ~IP6T_INV_MASK
);
294 ip6t_error(struct sk_buff
**pskb
,
295 unsigned int hooknum
,
296 const struct net_device
*in
,
297 const struct net_device
*out
,
298 const void *targinfo
,
302 printk("ip6_tables: error: `%s'\n", (char *)targinfo
);
308 int do_match(struct ip6t_entry_match
*m
,
309 const struct sk_buff
*skb
,
310 const struct net_device
*in
,
311 const struct net_device
*out
,
317 /* Stop iteration if it doesn't match */
318 if (!m
->u
.kernel
.match
->match(skb
, in
, out
, m
->data
,
319 offset
, hdr
, datalen
, hotdrop
))
325 static inline struct ip6t_entry
*
326 get_entry(void *base
, unsigned int offset
)
328 return (struct ip6t_entry
*)(base
+ offset
);
331 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
333 ip6t_do_table(struct sk_buff
**pskb
,
335 const struct net_device
*in
,
336 const struct net_device
*out
,
337 struct ip6t_table
*table
,
340 static const char nulldevname
[IFNAMSIZ
];
341 u_int16_t offset
= 0;
342 struct ipv6hdr
*ipv6
;
346 /* Initializing verdict to NF_DROP keeps gcc happy. */
347 unsigned int verdict
= NF_DROP
;
348 const char *indev
, *outdev
;
350 struct ip6t_entry
*e
, *back
;
352 /* FIXME: Push down to extensions --RR */
353 if (skb_is_nonlinear(*pskb
) && skb_linearize(*pskb
, GFP_ATOMIC
) != 0)
357 ipv6
= (*pskb
)->nh
.ipv6h
;
358 protohdr
= (u_int32_t
*)((char *)ipv6
+ IPV6_HDR_LEN
);
359 datalen
= (*pskb
)->len
- IPV6_HDR_LEN
;
360 indev
= in
? in
->name
: nulldevname
;
361 outdev
= out
? out
->name
: nulldevname
;
363 /* We handle fragments by dealing with the first fragment as
364 * if it was a normal packet. All other fragments are treated
365 * normally, except that they will NEVER match rules that ask
366 * things we don't know, ie. tcp syn flag or ports). If the
367 * rule is also a fragment-specific rule, non-fragments won't
370 read_lock_bh(&table
->lock
);
371 IP_NF_ASSERT(table
->valid_hooks
& (1 << hook
));
372 table_base
= (void *)table
->private->entries
373 + TABLE_OFFSET(table
->private, smp_processor_id());
374 e
= get_entry(table_base
, table
->private->hook_entry
[hook
]);
376 #ifdef CONFIG_NETFILTER_DEBUG
377 /* Check noone else using our table */
378 if (((struct ip6t_entry
*)table_base
)->comefrom
!= 0xdead57ac
379 && ((struct ip6t_entry
*)table_base
)->comefrom
!= 0xeeeeeeec) {
380 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
383 &((struct ip6t_entry
*)table_base
)->comefrom
,
384 ((struct ip6t_entry
*)table_base
)->comefrom
);
386 ((struct ip6t_entry
*)table_base
)->comefrom
= 0x57acc001;
389 /* For return from builtin chain */
390 back
= get_entry(table_base
, table
->private->underflow
[hook
]);
395 (*pskb
)->nfcache
|= e
->nfcache
;
396 if (ip6_packet_match(*pskb
, ipv6
, indev
, outdev
,
398 struct ip6t_entry_target
*t
;
400 if (IP6T_MATCH_ITERATE(e
, do_match
,
403 datalen
, &hotdrop
) != 0)
406 ADD_COUNTER(e
->counters
, ntohs(ipv6
->payload_len
) + IPV6_HDR_LEN
, 1);
408 t
= ip6t_get_target(e
);
409 IP_NF_ASSERT(t
->u
.kernel
.target
);
410 /* Standard target? */
411 if (!t
->u
.kernel
.target
->target
) {
414 v
= ((struct ip6t_standard_target
*)t
)->verdict
;
416 /* Pop from stack? */
417 if (v
!= IP6T_RETURN
) {
418 verdict
= (unsigned)(-v
) - 1;
422 back
= get_entry(table_base
,
427 != (void *)e
+ e
->next_offset
) {
428 /* Save old back ptr in next entry */
429 struct ip6t_entry
*next
430 = (void *)e
+ e
->next_offset
;
432 = (void *)back
- table_base
;
433 /* set back pointer to next entry */
437 e
= get_entry(table_base
, v
);
439 /* Targets which reenter must return
441 #ifdef CONFIG_NETFILTER_DEBUG
442 ((struct ip6t_entry
*)table_base
)->comefrom
445 verdict
= t
->u
.kernel
.target
->target(pskb
,
451 #ifdef CONFIG_NETFILTER_DEBUG
452 if (((struct ip6t_entry
*)table_base
)->comefrom
454 && verdict
== IP6T_CONTINUE
) {
455 printk("Target %s reentered!\n",
456 t
->u
.kernel
.target
->name
);
459 ((struct ip6t_entry
*)table_base
)->comefrom
462 /* Target might have changed stuff. */
463 ipv6
= (*pskb
)->nh
.ipv6h
;
464 protohdr
= (u_int32_t
*)((void *)ipv6
+ IPV6_HDR_LEN
);
465 datalen
= (*pskb
)->len
- IPV6_HDR_LEN
;
467 if (verdict
== IP6T_CONTINUE
)
468 e
= (void *)e
+ e
->next_offset
;
476 e
= (void *)e
+ e
->next_offset
;
480 #ifdef CONFIG_NETFILTER_DEBUG
481 ((struct ip6t_entry
*)table_base
)->comefrom
= 0xdead57ac;
483 read_unlock_bh(&table
->lock
);
485 #ifdef DEBUG_ALLOW_ALL
494 /* If it succeeds, returns element and locks mutex */
496 find_inlist_lock_noload(struct list_head
*head
,
499 struct semaphore
*mutex
)
504 duprintf("find_inlist: searching for `%s' in %s.\n",
505 name
, head
== &ip6t_target
? "ip6t_target"
506 : head
== &ip6t_match
? "ip6t_match"
507 : head
== &ip6t_tables
? "ip6t_tables" : "UNKNOWN");
510 *error
= down_interruptible(mutex
);
514 ret
= list_named_find(head
, name
);
523 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
526 find_inlist_lock(struct list_head
*head
,
530 struct semaphore
*mutex
)
534 ret
= find_inlist_lock_noload(head
, name
, error
, mutex
);
536 duprintf("find_inlist: loading `%s%s'.\n", prefix
, name
);
537 request_module("%s%s", prefix
, name
);
538 ret
= find_inlist_lock_noload(head
, name
, error
, mutex
);
545 static inline struct ip6t_table
*
546 ip6t_find_table_lock(const char *name
, int *error
, struct semaphore
*mutex
)
548 return find_inlist_lock(&ip6t_tables
, name
, "ip6table_", error
, mutex
);
551 static inline struct ip6t_match
*
552 find_match_lock(const char *name
, int *error
, struct semaphore
*mutex
)
554 return find_inlist_lock(&ip6t_match
, name
, "ip6t_", error
, mutex
);
558 ip6t_find_target_lock(const char *name
, int *error
, struct semaphore
*mutex
)
560 return find_inlist_lock(&ip6t_target
, name
, "ip6t_", error
, mutex
);
563 /* All zeroes == unconditional rule. */
565 unconditional(const struct ip6t_ip6
*ipv6
)
569 for (i
= 0; i
< sizeof(*ipv6
); i
++)
570 if (((char *)ipv6
)[i
])
573 return (i
== sizeof(*ipv6
));
576 /* Figures out from what hook each rule can be called: returns 0 if
577 there are loops. Puts hook bitmask in comefrom. */
579 mark_source_chains(struct ip6t_table_info
*newinfo
, unsigned int valid_hooks
)
583 /* No recursion; use packet counter to save back ptrs (reset
584 to 0 as we leave), and comefrom to save source hook bitmask */
585 for (hook
= 0; hook
< NF_IP6_NUMHOOKS
; hook
++) {
586 unsigned int pos
= newinfo
->hook_entry
[hook
];
588 = (struct ip6t_entry
*)(newinfo
->entries
+ pos
);
590 if (!(valid_hooks
& (1 << hook
)))
593 /* Set initial back pointer. */
594 e
->counters
.pcnt
= pos
;
597 struct ip6t_standard_target
*t
598 = (void *)ip6t_get_target(e
);
600 if (e
->comefrom
& (1 << NF_IP6_NUMHOOKS
)) {
601 printk("iptables: loop hook %u pos %u %08X.\n",
602 hook
, pos
, e
->comefrom
);
606 |= ((1 << hook
) | (1 << NF_IP6_NUMHOOKS
));
608 /* Unconditional return/END. */
609 if (e
->target_offset
== sizeof(struct ip6t_entry
)
610 && (strcmp(t
->target
.u
.user
.name
,
611 IP6T_STANDARD_TARGET
) == 0)
613 && unconditional(&e
->ipv6
)) {
614 unsigned int oldpos
, size
;
616 /* Return: backtrack through the last
619 e
->comefrom
^= (1<<NF_IP6_NUMHOOKS
);
620 #ifdef DEBUG_IP_FIREWALL_USER
622 & (1 << NF_IP6_NUMHOOKS
)) {
623 duprintf("Back unset "
630 pos
= e
->counters
.pcnt
;
631 e
->counters
.pcnt
= 0;
633 /* We're at the start. */
637 e
= (struct ip6t_entry
*)
638 (newinfo
->entries
+ pos
);
639 } while (oldpos
== pos
+ e
->next_offset
);
642 size
= e
->next_offset
;
643 e
= (struct ip6t_entry
*)
644 (newinfo
->entries
+ pos
+ size
);
645 e
->counters
.pcnt
= pos
;
648 int newpos
= t
->verdict
;
650 if (strcmp(t
->target
.u
.user
.name
,
651 IP6T_STANDARD_TARGET
) == 0
653 /* This a jump; chase it. */
654 duprintf("Jump rule %u -> %u\n",
657 /* ... this is a fallthru */
658 newpos
= pos
+ e
->next_offset
;
660 e
= (struct ip6t_entry
*)
661 (newinfo
->entries
+ newpos
);
662 e
->counters
.pcnt
= pos
;
667 duprintf("Finished chain %u\n", hook
);
673 cleanup_match(struct ip6t_entry_match
*m
, unsigned int *i
)
675 if (i
&& (*i
)-- == 0)
678 if (m
->u
.kernel
.match
->destroy
)
679 m
->u
.kernel
.match
->destroy(m
->data
,
680 m
->u
.match_size
- sizeof(*m
));
681 module_put(m
->u
.kernel
.match
->me
);
686 standard_check(const struct ip6t_entry_target
*t
,
687 unsigned int max_offset
)
689 struct ip6t_standard_target
*targ
= (void *)t
;
691 /* Check standard info. */
693 != IP6T_ALIGN(sizeof(struct ip6t_standard_target
))) {
694 duprintf("standard_check: target size %u != %u\n",
696 IP6T_ALIGN(sizeof(struct ip6t_standard_target
)));
700 if (targ
->verdict
>= 0
701 && targ
->verdict
> max_offset
- sizeof(struct ip6t_entry
)) {
702 duprintf("ip6t_standard_check: bad verdict (%i)\n",
707 if (targ
->verdict
< -NF_MAX_VERDICT
- 1) {
708 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
716 check_match(struct ip6t_entry_match
*m
,
718 const struct ip6t_ip6
*ipv6
,
719 unsigned int hookmask
,
723 struct ip6t_match
*match
;
725 match
= find_match_lock(m
->u
.user
.name
, &ret
, &ip6t_mutex
);
727 // duprintf("check_match: `%s' not found\n", m->u.name);
730 if (!try_module_get(match
->me
)) {
734 m
->u
.kernel
.match
= match
;
737 if (m
->u
.kernel
.match
->checkentry
738 && !m
->u
.kernel
.match
->checkentry(name
, ipv6
, m
->data
,
739 m
->u
.match_size
- sizeof(*m
),
741 module_put(m
->u
.kernel
.match
->me
);
742 duprintf("ip_tables: check failed for `%s'.\n",
743 m
->u
.kernel
.match
->name
);
751 static struct ip6t_target ip6t_standard_target
;
754 check_entry(struct ip6t_entry
*e
, const char *name
, unsigned int size
,
757 struct ip6t_entry_target
*t
;
758 struct ip6t_target
*target
;
762 if (!ip6_checkentry(&e
->ipv6
)) {
763 duprintf("ip_tables: ip check failed %p %s.\n", e
, name
);
768 ret
= IP6T_MATCH_ITERATE(e
, check_match
, name
, &e
->ipv6
, e
->comefrom
, &j
);
770 goto cleanup_matches
;
772 t
= ip6t_get_target(e
);
773 target
= ip6t_find_target_lock(t
->u
.user
.name
, &ret
, &ip6t_mutex
);
775 duprintf("check_entry: `%s' not found\n", t
->u
.user
.name
);
776 goto cleanup_matches
;
778 if (!try_module_get(target
->me
)) {
781 goto cleanup_matches
;
783 t
->u
.kernel
.target
= target
;
785 if (!t
->u
.kernel
.target
) {
787 goto cleanup_matches
;
789 if (t
->u
.kernel
.target
== &ip6t_standard_target
) {
790 if (!standard_check(t
, size
)) {
792 goto cleanup_matches
;
794 } else if (t
->u
.kernel
.target
->checkentry
795 && !t
->u
.kernel
.target
->checkentry(name
, e
, t
->data
,
799 module_put(t
->u
.kernel
.target
->me
);
800 duprintf("ip_tables: check failed for `%s'.\n",
801 t
->u
.kernel
.target
->name
);
803 goto cleanup_matches
;
810 IP6T_MATCH_ITERATE(e
, cleanup_match
, &j
);
815 check_entry_size_and_hooks(struct ip6t_entry
*e
,
816 struct ip6t_table_info
*newinfo
,
818 unsigned char *limit
,
819 const unsigned int *hook_entries
,
820 const unsigned int *underflows
,
825 if ((unsigned long)e
% __alignof__(struct ip6t_entry
) != 0
826 || (unsigned char *)e
+ sizeof(struct ip6t_entry
) >= limit
) {
827 duprintf("Bad offset %p\n", e
);
832 < sizeof(struct ip6t_entry
) + sizeof(struct ip6t_entry_target
)) {
833 duprintf("checking: element %p size %u\n",
838 /* Check hooks & underflows */
839 for (h
= 0; h
< NF_IP6_NUMHOOKS
; h
++) {
840 if ((unsigned char *)e
- base
== hook_entries
[h
])
841 newinfo
->hook_entry
[h
] = hook_entries
[h
];
842 if ((unsigned char *)e
- base
== underflows
[h
])
843 newinfo
->underflow
[h
] = underflows
[h
];
846 /* FIXME: underflows must be unconditional, standard verdicts
847 < 0 (not IP6T_RETURN). --RR */
849 /* Clear counters and comefrom */
850 e
->counters
= ((struct ip6t_counters
) { 0, 0 });
858 cleanup_entry(struct ip6t_entry
*e
, unsigned int *i
)
860 struct ip6t_entry_target
*t
;
862 if (i
&& (*i
)-- == 0)
865 /* Cleanup all matches */
866 IP6T_MATCH_ITERATE(e
, cleanup_match
, NULL
);
867 t
= ip6t_get_target(e
);
868 if (t
->u
.kernel
.target
->destroy
)
869 t
->u
.kernel
.target
->destroy(t
->data
,
870 t
->u
.target_size
- sizeof(*t
));
871 module_put(t
->u
.kernel
.target
->me
);
875 /* Checks and translates the user-supplied table segment (held in
878 translate_table(const char *name
,
879 unsigned int valid_hooks
,
880 struct ip6t_table_info
*newinfo
,
883 const unsigned int *hook_entries
,
884 const unsigned int *underflows
)
889 newinfo
->size
= size
;
890 newinfo
->number
= number
;
892 /* Init all hooks to impossible value. */
893 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
894 newinfo
->hook_entry
[i
] = 0xFFFFFFFF;
895 newinfo
->underflow
[i
] = 0xFFFFFFFF;
898 duprintf("translate_table: size %u\n", newinfo
->size
);
900 /* Walk through entries, checking offsets. */
901 ret
= IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
902 check_entry_size_and_hooks
,
905 newinfo
->entries
+ size
,
906 hook_entries
, underflows
, &i
);
911 duprintf("translate_table: %u not %u entries\n",
916 /* Check hooks all assigned */
917 for (i
= 0; i
< NF_IP6_NUMHOOKS
; i
++) {
918 /* Only hooks which are valid */
919 if (!(valid_hooks
& (1 << i
)))
921 if (newinfo
->hook_entry
[i
] == 0xFFFFFFFF) {
922 duprintf("Invalid hook entry %u %u\n",
926 if (newinfo
->underflow
[i
] == 0xFFFFFFFF) {
927 duprintf("Invalid underflow %u %u\n",
933 if (!mark_source_chains(newinfo
, valid_hooks
))
936 /* Finally, each sanity check must pass */
938 ret
= IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
939 check_entry
, name
, size
, &i
);
942 IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
,
947 /* And one copy for every other CPU */
948 for (i
= 1; i
< NR_CPUS
; i
++) {
949 memcpy(newinfo
->entries
+ SMP_ALIGN(newinfo
->size
)*i
,
951 SMP_ALIGN(newinfo
->size
));
957 static struct ip6t_table_info
*
958 replace_table(struct ip6t_table
*table
,
959 unsigned int num_counters
,
960 struct ip6t_table_info
*newinfo
,
963 struct ip6t_table_info
*oldinfo
;
965 #ifdef CONFIG_NETFILTER_DEBUG
967 struct ip6t_entry
*table_base
;
970 for (i
= 0; i
< NR_CPUS
; i
++) {
972 (void *)newinfo
->entries
973 + TABLE_OFFSET(newinfo
, i
);
975 table_base
->comefrom
= 0xdead57ac;
980 /* Do the substitution. */
981 write_lock_bh(&table
->lock
);
982 /* Check inside lock: is the old number correct? */
983 if (num_counters
!= table
->private->number
) {
984 duprintf("num_counters != table->private->number (%u/%u)\n",
985 num_counters
, table
->private->number
);
986 write_unlock_bh(&table
->lock
);
990 oldinfo
= table
->private;
991 table
->private = newinfo
;
992 newinfo
->initial_entries
= oldinfo
->initial_entries
;
993 write_unlock_bh(&table
->lock
);
1000 add_entry_to_counter(const struct ip6t_entry
*e
,
1001 struct ip6t_counters total
[],
1004 ADD_COUNTER(total
[*i
], e
->counters
.bcnt
, e
->counters
.pcnt
);
1011 get_counters(const struct ip6t_table_info
*t
,
1012 struct ip6t_counters counters
[])
1017 for (cpu
= 0; cpu
< NR_CPUS
; cpu
++) {
1019 IP6T_ENTRY_ITERATE(t
->entries
+ TABLE_OFFSET(t
, cpu
),
1021 add_entry_to_counter
,
1028 copy_entries_to_user(unsigned int total_size
,
1029 struct ip6t_table
*table
,
1030 void __user
*userptr
)
1032 unsigned int off
, num
, countersize
;
1033 struct ip6t_entry
*e
;
1034 struct ip6t_counters
*counters
;
1037 /* We need atomic snapshot of counters: rest doesn't change
1038 (other than comefrom, which userspace doesn't care
1040 countersize
= sizeof(struct ip6t_counters
) * table
->private->number
;
1041 counters
= vmalloc(countersize
);
1043 if (counters
== NULL
)
1046 /* First, sum counters... */
1047 memset(counters
, 0, countersize
);
1048 write_lock_bh(&table
->lock
);
1049 get_counters(table
->private, counters
);
1050 write_unlock_bh(&table
->lock
);
1052 /* ... then copy entire thing from CPU 0... */
1053 if (copy_to_user(userptr
, table
->private->entries
, total_size
) != 0) {
1058 /* FIXME: use iterator macros --RR */
1059 /* ... then go back and fix counters and names */
1060 for (off
= 0, num
= 0; off
< total_size
; off
+= e
->next_offset
, num
++){
1062 struct ip6t_entry_match
*m
;
1063 struct ip6t_entry_target
*t
;
1065 e
= (struct ip6t_entry
*)(table
->private->entries
+ off
);
1066 if (copy_to_user(userptr
+ off
1067 + offsetof(struct ip6t_entry
, counters
),
1069 sizeof(counters
[num
])) != 0) {
1074 for (i
= sizeof(struct ip6t_entry
);
1075 i
< e
->target_offset
;
1076 i
+= m
->u
.match_size
) {
1079 if (copy_to_user(userptr
+ off
+ i
1080 + offsetof(struct ip6t_entry_match
,
1082 m
->u
.kernel
.match
->name
,
1083 strlen(m
->u
.kernel
.match
->name
)+1)
1090 t
= ip6t_get_target(e
);
1091 if (copy_to_user(userptr
+ off
+ e
->target_offset
1092 + offsetof(struct ip6t_entry_target
,
1094 t
->u
.kernel
.target
->name
,
1095 strlen(t
->u
.kernel
.target
->name
)+1) != 0) {
1107 get_entries(const struct ip6t_get_entries
*entries
,
1108 struct ip6t_get_entries __user
*uptr
)
1111 struct ip6t_table
*t
;
1113 t
= ip6t_find_table_lock(entries
->name
, &ret
, &ip6t_mutex
);
1115 duprintf("t->private->number = %u\n",
1116 t
->private->number
);
1117 if (entries
->size
== t
->private->size
)
1118 ret
= copy_entries_to_user(t
->private->size
,
1119 t
, uptr
->entrytable
);
1121 duprintf("get_entries: I've got %u not %u!\n",
1128 duprintf("get_entries: Can't find %s!\n",
1135 do_replace(void __user
*user
, unsigned int len
)
1138 struct ip6t_replace tmp
;
1139 struct ip6t_table
*t
;
1140 struct ip6t_table_info
*newinfo
, *oldinfo
;
1141 struct ip6t_counters
*counters
;
1143 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1146 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1147 if ((SMP_ALIGN(tmp
.size
) >> PAGE_SHIFT
) + 2 > num_physpages
)
1150 newinfo
= vmalloc(sizeof(struct ip6t_table_info
)
1151 + SMP_ALIGN(tmp
.size
) * NR_CPUS
);
1155 if (copy_from_user(newinfo
->entries
, user
+ sizeof(tmp
),
1161 counters
= vmalloc(tmp
.num_counters
* sizeof(struct ip6t_counters
));
1166 memset(counters
, 0, tmp
.num_counters
* sizeof(struct ip6t_counters
));
1168 ret
= translate_table(tmp
.name
, tmp
.valid_hooks
,
1169 newinfo
, tmp
.size
, tmp
.num_entries
,
1170 tmp
.hook_entry
, tmp
.underflow
);
1172 goto free_newinfo_counters
;
1174 duprintf("ip_tables: Translated table\n");
1176 t
= ip6t_find_table_lock(tmp
.name
, &ret
, &ip6t_mutex
);
1178 goto free_newinfo_counters_untrans
;
1181 if (tmp
.valid_hooks
!= t
->valid_hooks
) {
1182 duprintf("Valid hook crap: %08X vs %08X\n",
1183 tmp
.valid_hooks
, t
->valid_hooks
);
1185 goto free_newinfo_counters_untrans_unlock
;
1188 /* Get a reference in advance, we're not allowed fail later */
1189 if (!try_module_get(t
->me
)) {
1191 goto free_newinfo_counters_untrans_unlock
;
1194 oldinfo
= replace_table(t
, tmp
.num_counters
, newinfo
, &ret
);
1198 /* Update module usage count based on number of rules */
1199 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1200 oldinfo
->number
, oldinfo
->initial_entries
, newinfo
->number
);
1201 if ((oldinfo
->number
> oldinfo
->initial_entries
) ||
1202 (newinfo
->number
<= oldinfo
->initial_entries
))
1204 if ((oldinfo
->number
> oldinfo
->initial_entries
) &&
1205 (newinfo
->number
<= oldinfo
->initial_entries
))
1208 /* Get the old counters. */
1209 get_counters(oldinfo
, counters
);
1210 /* Decrease module usage counts and free resource */
1211 IP6T_ENTRY_ITERATE(oldinfo
->entries
, oldinfo
->size
, cleanup_entry
,NULL
);
1213 /* Silent error: too late now. */
1214 copy_to_user(tmp
.counters
, counters
,
1215 sizeof(struct ip6t_counters
) * tmp
.num_counters
);
1222 free_newinfo_counters_untrans_unlock
:
1224 free_newinfo_counters_untrans
:
1225 IP6T_ENTRY_ITERATE(newinfo
->entries
, newinfo
->size
, cleanup_entry
,NULL
);
1226 free_newinfo_counters
:
1233 /* We're lazy, and add to the first CPU; overflow works its fey magic
1234 * and everything is OK. */
1236 add_counter_to_entry(struct ip6t_entry
*e
,
1237 const struct ip6t_counters addme
[],
1241 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1243 (long unsigned int)e
->counters
.pcnt
,
1244 (long unsigned int)e
->counters
.bcnt
,
1245 (long unsigned int)addme
[*i
].pcnt
,
1246 (long unsigned int)addme
[*i
].bcnt
);
1249 ADD_COUNTER(e
->counters
, addme
[*i
].bcnt
, addme
[*i
].pcnt
);
1256 do_add_counters(void __user
*user
, unsigned int len
)
1259 struct ip6t_counters_info tmp
, *paddc
;
1260 struct ip6t_table
*t
;
1263 if (copy_from_user(&tmp
, user
, sizeof(tmp
)) != 0)
1266 if (len
!= sizeof(tmp
) + tmp
.num_counters
*sizeof(struct ip6t_counters
))
1269 paddc
= vmalloc(len
);
1273 if (copy_from_user(paddc
, user
, len
) != 0) {
1278 t
= ip6t_find_table_lock(tmp
.name
, &ret
, &ip6t_mutex
);
1282 write_lock_bh(&t
->lock
);
1283 if (t
->private->number
!= paddc
->num_counters
) {
1285 goto unlock_up_free
;
1289 IP6T_ENTRY_ITERATE(t
->private->entries
,
1291 add_counter_to_entry
,
1295 write_unlock_bh(&t
->lock
);
1304 do_ip6t_set_ctl(struct sock
*sk
, int cmd
, void __user
*user
, unsigned int len
)
1308 if (!capable(CAP_NET_ADMIN
))
1312 case IP6T_SO_SET_REPLACE
:
1313 ret
= do_replace(user
, len
);
1316 case IP6T_SO_SET_ADD_COUNTERS
:
1317 ret
= do_add_counters(user
, len
);
1321 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd
);
1329 do_ip6t_get_ctl(struct sock
*sk
, int cmd
, void __user
*user
, int *len
)
1333 if (!capable(CAP_NET_ADMIN
))
1337 case IP6T_SO_GET_INFO
: {
1338 char name
[IP6T_TABLE_MAXNAMELEN
];
1339 struct ip6t_table
*t
;
1341 if (*len
!= sizeof(struct ip6t_getinfo
)) {
1342 duprintf("length %u != %u\n", *len
,
1343 sizeof(struct ip6t_getinfo
));
1348 if (copy_from_user(name
, user
, sizeof(name
)) != 0) {
1352 name
[IP6T_TABLE_MAXNAMELEN
-1] = '\0';
1353 t
= ip6t_find_table_lock(name
, &ret
, &ip6t_mutex
);
1355 struct ip6t_getinfo info
;
1357 info
.valid_hooks
= t
->valid_hooks
;
1358 memcpy(info
.hook_entry
, t
->private->hook_entry
,
1359 sizeof(info
.hook_entry
));
1360 memcpy(info
.underflow
, t
->private->underflow
,
1361 sizeof(info
.underflow
));
1362 info
.num_entries
= t
->private->number
;
1363 info
.size
= t
->private->size
;
1364 strcpy(info
.name
, name
);
1366 if (copy_to_user(user
, &info
, *len
) != 0)
1376 case IP6T_SO_GET_ENTRIES
: {
1377 struct ip6t_get_entries get
;
1379 if (*len
< sizeof(get
)) {
1380 duprintf("get_entries: %u < %u\n", *len
, sizeof(get
));
1382 } else if (copy_from_user(&get
, user
, sizeof(get
)) != 0) {
1384 } else if (*len
!= sizeof(struct ip6t_get_entries
) + get
.size
) {
1385 duprintf("get_entries: %u != %u\n", *len
,
1386 sizeof(struct ip6t_get_entries
) + get
.size
);
1389 ret
= get_entries(&get
, user
);
1394 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd
);
1401 /* Registration hooks for targets. */
1403 ip6t_register_target(struct ip6t_target
*target
)
1407 ret
= down_interruptible(&ip6t_mutex
);
1411 if (!list_named_insert(&ip6t_target
, target
)) {
1412 duprintf("ip6t_register_target: `%s' already in list!\n",
1421 ip6t_unregister_target(struct ip6t_target
*target
)
1424 LIST_DELETE(&ip6t_target
, target
);
1429 ip6t_register_match(struct ip6t_match
*match
)
1433 ret
= down_interruptible(&ip6t_mutex
);
1437 if (!list_named_insert(&ip6t_match
, match
)) {
1438 duprintf("ip6t_register_match: `%s' already in list!\n",
1448 ip6t_unregister_match(struct ip6t_match
*match
)
1451 LIST_DELETE(&ip6t_match
, match
);
1455 int ip6t_register_table(struct ip6t_table
*table
)
1458 struct ip6t_table_info
*newinfo
;
1459 static struct ip6t_table_info bootstrap
1460 = { 0, 0, 0, { 0 }, { 0 }, { } };
1462 newinfo
= vmalloc(sizeof(struct ip6t_table_info
)
1463 + SMP_ALIGN(table
->table
->size
) * NR_CPUS
);
1467 memcpy(newinfo
->entries
, table
->table
->entries
, table
->table
->size
);
1469 ret
= translate_table(table
->name
, table
->valid_hooks
,
1470 newinfo
, table
->table
->size
,
1471 table
->table
->num_entries
,
1472 table
->table
->hook_entry
,
1473 table
->table
->underflow
);
1479 ret
= down_interruptible(&ip6t_mutex
);
1485 /* Don't autoload: we'd eat our tail... */
1486 if (list_named_find(&ip6t_tables
, table
->name
)) {
1491 /* Simplifies replace_table code. */
1492 table
->private = &bootstrap
;
1493 if (!replace_table(table
, 0, newinfo
, &ret
))
1496 duprintf("table->private->number = %u\n",
1497 table
->private->number
);
1499 /* save number of initial entries */
1500 table
->private->initial_entries
= table
->private->number
;
1502 table
->lock
= RW_LOCK_UNLOCKED
;
1503 list_prepend(&ip6t_tables
, table
);
1514 void ip6t_unregister_table(struct ip6t_table
*table
)
1517 LIST_DELETE(&ip6t_tables
, table
);
1520 /* Decrease module usage counts and free resources */
1521 IP6T_ENTRY_ITERATE(table
->private->entries
, table
->private->size
,
1522 cleanup_entry
, NULL
);
1523 vfree(table
->private);
1526 /* Returns 1 if the port is matched by the range, 0 otherwise */
1528 port_match(u_int16_t min
, u_int16_t max
, u_int16_t port
, int invert
)
1532 ret
= (port
>= min
&& port
<= max
) ^ invert
;
1537 tcp_find_option(u_int8_t option
,
1538 const struct tcphdr
*tcp
,
1543 unsigned int i
= sizeof(struct tcphdr
);
1544 const u_int8_t
*opt
= (u_int8_t
*)tcp
;
1546 duprintf("tcp_match: finding option\n");
1547 /* If we don't have the whole header, drop packet. */
1548 if (tcp
->doff
* 4 < sizeof(struct tcphdr
) ||
1549 tcp
->doff
* 4 > datalen
) {
1554 while (i
< tcp
->doff
* 4) {
1555 if (opt
[i
] == option
) return !invert
;
1556 if (opt
[i
] < 2) i
++;
1557 else i
+= opt
[i
+1]?:1;
1564 tcp_match(const struct sk_buff
*skb
,
1565 const struct net_device
*in
,
1566 const struct net_device
*out
,
1567 const void *matchinfo
,
1573 const struct tcphdr
*tcp
;
1574 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1576 u8 nexthdr
= skb
->nh
.ipv6h
->nexthdr
;
1580 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1581 causes this. Its a cracker trying to break in by doing a
1582 flag overwrite to pass the direction checks.
1586 duprintf("Dropping evil TCP offset=1 frag.\n");
1589 } else if (offset
== 0 && datalen
< sizeof(struct tcphdr
)) {
1590 /* We've been asked to examine this packet, and we
1591 can't. Hence, no choice but to drop. */
1592 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1597 tcpoff
= (u8
*)(skb
->nh
.ipv6h
+ 1) - skb
->data
;
1598 tcpoff
= ipv6_skip_exthdr(skb
, tcpoff
, &nexthdr
, skb
->len
- tcpoff
);
1599 if (tcpoff
< 0 || tcpoff
> skb
->len
) {
1600 duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
1603 } else if (nexthdr
== IPPROTO_FRAGMENT
)
1605 else if (nexthdr
!= IPPROTO_TCP
||
1606 skb
->len
- tcpoff
< sizeof(struct tcphdr
)) {
1607 /* cannot be occured */
1608 duprintf("tcp_match: cannot get TCP header. Dropping.\n");
1613 tcp
= (struct tcphdr
*)(skb
->data
+ tcpoff
);
1615 /* FIXME: Try tcp doff >> packet len against various stacks --RR */
1617 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1619 /* Must not be a fragment. */
1621 && port_match(tcpinfo
->spts
[0], tcpinfo
->spts
[1],
1623 !!(tcpinfo
->invflags
& IP6T_TCP_INV_SRCPT
))
1624 && port_match(tcpinfo
->dpts
[0], tcpinfo
->dpts
[1],
1626 !!(tcpinfo
->invflags
& IP6T_TCP_INV_DSTPT
))
1627 && FWINVTCP((((unsigned char *)tcp
)[13]
1628 & tcpinfo
->flg_mask
)
1629 == tcpinfo
->flg_cmp
,
1631 && (!tcpinfo
->option
1632 || tcp_find_option(tcpinfo
->option
, tcp
, datalen
,
1634 & IP6T_TCP_INV_OPTION
,
1638 /* Called when user tries to insert an entry of this type. */
1640 tcp_checkentry(const char *tablename
,
1641 const struct ip6t_ip6
*ipv6
,
1643 unsigned int matchsize
,
1644 unsigned int hook_mask
)
1646 const struct ip6t_tcp
*tcpinfo
= matchinfo
;
1648 /* Must specify proto == TCP, and no unknown invflags */
1649 return ipv6
->proto
== IPPROTO_TCP
1650 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1651 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_tcp
))
1652 && !(tcpinfo
->invflags
& ~IP6T_TCP_INV_MASK
);
1656 udp_match(const struct sk_buff
*skb
,
1657 const struct net_device
*in
,
1658 const struct net_device
*out
,
1659 const void *matchinfo
,
1665 const struct udphdr
*udp
;
1666 const struct ip6t_udp
*udpinfo
= matchinfo
;
1668 u8 nexthdr
= skb
->nh
.ipv6h
->nexthdr
;
1670 if (offset
== 0 && datalen
< sizeof(struct udphdr
)) {
1671 /* We've been asked to examine this packet, and we
1672 can't. Hence, no choice but to drop. */
1673 duprintf("Dropping evil UDP tinygram.\n");
1678 udpoff
= (u8
*)(skb
->nh
.ipv6h
+ 1) - skb
->data
;
1679 udpoff
= ipv6_skip_exthdr(skb
, udpoff
, &nexthdr
, skb
->len
- udpoff
);
1680 if (udpoff
< 0 || udpoff
> skb
->len
) {
1681 duprintf("udp_match: cannot skip exthdr. Dropping.\n");
1684 } else if (nexthdr
== IPPROTO_FRAGMENT
)
1686 else if (nexthdr
!= IPPROTO_UDP
||
1687 skb
->len
- udpoff
< sizeof(struct udphdr
)) {
1688 duprintf("udp_match: cannot get UDP header. Dropping.\n");
1693 udp
= (struct udphdr
*)(skb
->data
+ udpoff
);
1695 /* Must not be a fragment. */
1697 && port_match(udpinfo
->spts
[0], udpinfo
->spts
[1],
1699 !!(udpinfo
->invflags
& IP6T_UDP_INV_SRCPT
))
1700 && port_match(udpinfo
->dpts
[0], udpinfo
->dpts
[1],
1702 !!(udpinfo
->invflags
& IP6T_UDP_INV_DSTPT
));
1705 /* Called when user tries to insert an entry of this type. */
1707 udp_checkentry(const char *tablename
,
1708 const struct ip6t_ip6
*ipv6
,
1710 unsigned int matchinfosize
,
1711 unsigned int hook_mask
)
1713 const struct ip6t_udp
*udpinfo
= matchinfo
;
1715 /* Must specify proto == UDP, and no unknown invflags */
1716 if (ipv6
->proto
!= IPPROTO_UDP
|| (ipv6
->invflags
& IP6T_INV_PROTO
)) {
1717 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6
->proto
,
1721 if (matchinfosize
!= IP6T_ALIGN(sizeof(struct ip6t_udp
))) {
1722 duprintf("ip6t_udp: matchsize %u != %u\n",
1723 matchinfosize
, IP6T_ALIGN(sizeof(struct ip6t_udp
)));
1726 if (udpinfo
->invflags
& ~IP6T_UDP_INV_MASK
) {
1727 duprintf("ip6t_udp: unknown flags %X\n",
1735 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1737 icmp6_type_code_match(u_int8_t test_type
, u_int8_t min_code
, u_int8_t max_code
,
1738 u_int8_t type
, u_int8_t code
,
1741 return (type
== test_type
&& code
>= min_code
&& code
<= max_code
)
1746 icmp6_match(const struct sk_buff
*skb
,
1747 const struct net_device
*in
,
1748 const struct net_device
*out
,
1749 const void *matchinfo
,
1755 const struct icmp6hdr
*icmp
= hdr
;
1756 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1758 if (offset
== 0 && datalen
< 2) {
1759 /* We've been asked to examine this packet, and we
1760 can't. Hence, no choice but to drop. */
1761 duprintf("Dropping evil ICMP tinygram.\n");
1766 /* Must not be a fragment. */
1768 && icmp6_type_code_match(icmpinfo
->type
,
1771 icmp
->icmp6_type
, icmp
->icmp6_code
,
1772 !!(icmpinfo
->invflags
&IP6T_ICMP_INV
));
1775 /* Called when user tries to insert an entry of this type. */
1777 icmp6_checkentry(const char *tablename
,
1778 const struct ip6t_ip6
*ipv6
,
1780 unsigned int matchsize
,
1781 unsigned int hook_mask
)
1783 const struct ip6t_icmp
*icmpinfo
= matchinfo
;
1785 /* Must specify proto == ICMP, and no unknown invflags */
1786 return ipv6
->proto
== IPPROTO_ICMPV6
1787 && !(ipv6
->invflags
& IP6T_INV_PROTO
)
1788 && matchsize
== IP6T_ALIGN(sizeof(struct ip6t_icmp
))
1789 && !(icmpinfo
->invflags
& ~IP6T_ICMP_INV
);
1792 /* The built-in targets: standard (NULL) and error. */
1793 static struct ip6t_target ip6t_standard_target
= {
1794 .name
= IP6T_STANDARD_TARGET
,
1797 static struct ip6t_target ip6t_error_target
= {
1798 .name
= IP6T_ERROR_TARGET
,
1799 .target
= ip6t_error
,
1802 static struct nf_sockopt_ops ip6t_sockopts
= {
1804 .set_optmin
= IP6T_BASE_CTL
,
1805 .set_optmax
= IP6T_SO_SET_MAX
+1,
1806 .set
= do_ip6t_set_ctl
,
1807 .get_optmin
= IP6T_BASE_CTL
,
1808 .get_optmax
= IP6T_SO_GET_MAX
+1,
1809 .get
= do_ip6t_get_ctl
,
1812 static struct ip6t_match tcp_matchstruct
= {
1814 .match
= &tcp_match
,
1815 .checkentry
= &tcp_checkentry
,
1818 static struct ip6t_match udp_matchstruct
= {
1820 .match
= &udp_match
,
1821 .checkentry
= &udp_checkentry
,
1824 static struct ip6t_match icmp6_matchstruct
= {
1826 .match
= &icmp6_match
,
1827 .checkentry
= &icmp6_checkentry
,
1830 #ifdef CONFIG_PROC_FS
1831 static inline int print_name(const char *i
,
1832 off_t start_offset
, char *buffer
, int length
,
1833 off_t
*pos
, unsigned int *count
)
1835 if ((*count
)++ >= start_offset
) {
1836 unsigned int namelen
;
1838 namelen
= sprintf(buffer
+ *pos
, "%s\n",
1839 i
+ sizeof(struct list_head
));
1840 if (*pos
+ namelen
> length
) {
1841 /* Stop iterating */
1849 static inline int print_target(const struct ip6t_target
*t
,
1850 off_t start_offset
, char *buffer
, int length
,
1851 off_t
*pos
, unsigned int *count
)
1853 if (t
== &ip6t_standard_target
|| t
== &ip6t_error_target
)
1855 return print_name((char *)t
, start_offset
, buffer
, length
, pos
, count
);
1858 static int ip6t_get_tables(char *buffer
, char **start
, off_t offset
, int length
)
1861 unsigned int count
= 0;
1863 if (down_interruptible(&ip6t_mutex
) != 0)
1866 LIST_FIND(&ip6t_tables
, print_name
, char *,
1867 offset
, buffer
, length
, &pos
, &count
);
1871 /* `start' hack - see fs/proc/generic.c line ~105 */
1872 *start
=(char *)((unsigned long)count
-offset
);
1876 static int ip6t_get_targets(char *buffer
, char **start
, off_t offset
, int length
)
1879 unsigned int count
= 0;
1881 if (down_interruptible(&ip6t_mutex
) != 0)
1884 LIST_FIND(&ip6t_target
, print_target
, struct ip6t_target
*,
1885 offset
, buffer
, length
, &pos
, &count
);
1889 *start
= (char *)((unsigned long)count
- offset
);
1893 static int ip6t_get_matches(char *buffer
, char **start
, off_t offset
, int length
)
1896 unsigned int count
= 0;
1898 if (down_interruptible(&ip6t_mutex
) != 0)
1901 LIST_FIND(&ip6t_match
, print_name
, char *,
1902 offset
, buffer
, length
, &pos
, &count
);
1906 *start
= (char *)((unsigned long)count
- offset
);
1910 static struct { char *name
; get_info_t
*get_info
; } ip6t_proc_entry
[] =
1911 { { "ip6_tables_names", ip6t_get_tables
},
1912 { "ip6_tables_targets", ip6t_get_targets
},
1913 { "ip6_tables_matches", ip6t_get_matches
},
1915 #endif /*CONFIG_PROC_FS*/
1917 static int __init
init(void)
1921 /* Noone else will be downing sem now, so we won't sleep */
1923 list_append(&ip6t_target
, &ip6t_standard_target
);
1924 list_append(&ip6t_target
, &ip6t_error_target
);
1925 list_append(&ip6t_match
, &tcp_matchstruct
);
1926 list_append(&ip6t_match
, &udp_matchstruct
);
1927 list_append(&ip6t_match
, &icmp6_matchstruct
);
1930 /* Register setsockopt */
1931 ret
= nf_register_sockopt(&ip6t_sockopts
);
1933 duprintf("Unable to register sockopts.\n");
1937 #ifdef CONFIG_PROC_FS
1939 struct proc_dir_entry
*proc
;
1942 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++) {
1943 proc
= proc_net_create(ip6t_proc_entry
[i
].name
, 0,
1944 ip6t_proc_entry
[i
].get_info
);
1947 proc_net_remove(ip6t_proc_entry
[i
].name
);
1948 nf_unregister_sockopt(&ip6t_sockopts
);
1951 proc
->owner
= THIS_MODULE
;
1956 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1960 static void __exit
fini(void)
1962 nf_unregister_sockopt(&ip6t_sockopts
);
1963 #ifdef CONFIG_PROC_FS
1966 for (i
= 0; ip6t_proc_entry
[i
].name
; i
++)
1967 proc_net_remove(ip6t_proc_entry
[i
].name
);
1972 EXPORT_SYMBOL(ip6t_register_table
);
1973 EXPORT_SYMBOL(ip6t_unregister_table
);
1974 EXPORT_SYMBOL(ip6t_do_table
);
1975 EXPORT_SYMBOL(ip6t_find_target_lock
);
1976 EXPORT_SYMBOL(ip6t_register_match
);
1977 EXPORT_SYMBOL(ip6t_unregister_match
);
1978 EXPORT_SYMBOL(ip6t_register_target
);
1979 EXPORT_SYMBOL(ip6t_unregister_target
);
1980 EXPORT_SYMBOL(ip6t_ext_hdr
);