[CPUFREQ] fix up comment in cpufreq.h
[linux-2.6/mini2440.git] / net / ipv6 / netfilter / ip6_tables.c
blobc735276fdd5fbcd6c31f040d470bb79cd5998032
1 /*
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
13 * a table
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>
26 #include <net/ip.h>
27 #include <net/ipv6.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)
47 #else
48 #define dprintf(format, args...)
49 #endif
51 #ifdef DEBUG_IP_FIREWALL_USER
52 #define duprintf(format, args...) printk(format , ## args)
53 #else
54 #define duprintf(format, args...)
55 #endif
57 #ifdef CONFIG_NETFILTER_DEBUG
58 #define IP_NF_ASSERT(x) \
59 do { \
60 if (!(x)) \
61 printk("IP_NF_ASSERT: %s:%s:%u\n", \
62 __FUNCTION__, __FILE__, __LINE__); \
63 } while(0)
64 #else
65 #define IP_NF_ASSERT(x)
66 #endif
67 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69 static DECLARE_MUTEX(ip6t_mutex);
71 /* Must have 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>
77 #if 0
78 /* All the better to debug you with... */
79 #define static
80 #define inline
81 #endif
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
89 in user context.
91 To be cache friendly on SMP, we arrange them like so:
92 [ n-entries ]
93 ... cache-align padding ...
94 [ n-entries ]
96 Hence the start of any table is given by get_table() below. */
98 /* The table itself */
99 struct ip6t_table_info
101 /* Size per table */
102 unsigned int size;
103 /* Number of entries: FIXME. --RR */
104 unsigned int number;
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)
121 #ifdef CONFIG_SMP
122 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
123 #else
124 #define TABLE_OFFSET(t,p) 0
125 #endif
127 #if 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)
131 #endif
133 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
134 struct in6_addr addr2)
136 int i;
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]))
140 return 1;
142 return 0;
145 /* Check for an extension */
146 int
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. */
159 static inline int
160 ip6_packet_match(const struct sk_buff *skb,
161 const char *indev,
162 const char *outdev,
163 const struct ip6t_ip6 *ip6info,
164 unsigned int *protoff,
165 int *fragoff)
167 size_t i;
168 unsigned long ret;
169 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
171 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
173 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
174 IP6T_INV_SRCIP)
175 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
176 IP6T_INV_DSTIP)) {
177 dprintf("Source or dest mismatch.\n");
179 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
180 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
181 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
182 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
183 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
184 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
185 return 0;
188 /* Look for ifname matches; this should unroll nicely. */
189 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
190 ret |= (((const unsigned long *)indev)[i]
191 ^ ((const unsigned long *)ip6info->iniface)[i])
192 & ((const unsigned long *)ip6info->iniface_mask)[i];
195 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
196 dprintf("VIA in mismatch (%s vs %s).%s\n",
197 indev, ip6info->iniface,
198 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
199 return 0;
202 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
203 ret |= (((const unsigned long *)outdev)[i]
204 ^ ((const unsigned long *)ip6info->outiface)[i])
205 & ((const unsigned long *)ip6info->outiface_mask)[i];
208 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
209 dprintf("VIA out mismatch (%s vs %s).%s\n",
210 outdev, ip6info->outiface,
211 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
212 return 0;
215 /* ... might want to do something with class and flowlabel here ... */
217 /* look for the desired protocol header */
218 if((ip6info->flags & IP6T_F_PROTO)) {
219 u_int8_t currenthdr = ipv6->nexthdr;
220 struct ipv6_opt_hdr _hdr, *hp;
221 u_int16_t ptr; /* Header offset in skb */
222 u_int16_t hdrlen; /* Header */
223 u_int16_t _fragoff = 0, *fp = NULL;
225 ptr = IPV6_HDR_LEN;
227 while (ip6t_ext_hdr(currenthdr)) {
228 /* Is there enough space for the next ext header? */
229 if (skb->len - ptr < IPV6_OPTHDR_LEN)
230 return 0;
232 /* NONE or ESP: there isn't protocol part */
233 /* If we want to count these packets in '-p all',
234 * we will change the return 0 to 1*/
235 if ((currenthdr == IPPROTO_NONE) ||
236 (currenthdr == IPPROTO_ESP))
237 break;
239 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
240 BUG_ON(hp == NULL);
242 /* Size calculation */
243 if (currenthdr == IPPROTO_FRAGMENT) {
244 fp = skb_header_pointer(skb,
245 ptr+offsetof(struct frag_hdr,
246 frag_off),
247 sizeof(_fragoff),
248 &_fragoff);
249 if (fp == NULL)
250 return 0;
252 _fragoff = ntohs(*fp) & ~0x7;
253 hdrlen = 8;
254 } else if (currenthdr == IPPROTO_AH)
255 hdrlen = (hp->hdrlen+2)<<2;
256 else
257 hdrlen = ipv6_optlen(hp);
259 currenthdr = hp->nexthdr;
260 ptr += hdrlen;
261 /* ptr is too large */
262 if ( ptr > skb->len )
263 return 0;
264 if (_fragoff) {
265 if (ip6t_ext_hdr(currenthdr))
266 return 0;
267 break;
271 *protoff = ptr;
272 *fragoff = _fragoff;
274 /* currenthdr contains the protocol header */
276 dprintf("Packet protocol %hi ?= %s%hi.\n",
277 currenthdr,
278 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
279 ip6info->proto);
281 if (ip6info->proto == currenthdr) {
282 if(ip6info->invflags & IP6T_INV_PROTO) {
283 return 0;
285 return 1;
288 /* We need match for the '-p all', too! */
289 if ((ip6info->proto != 0) &&
290 !(ip6info->invflags & IP6T_INV_PROTO))
291 return 0;
293 return 1;
296 /* should be ip6 safe */
297 static inline int
298 ip6_checkentry(const struct ip6t_ip6 *ipv6)
300 if (ipv6->flags & ~IP6T_F_MASK) {
301 duprintf("Unknown flag bits set: %08X\n",
302 ipv6->flags & ~IP6T_F_MASK);
303 return 0;
305 if (ipv6->invflags & ~IP6T_INV_MASK) {
306 duprintf("Unknown invflag bits set: %08X\n",
307 ipv6->invflags & ~IP6T_INV_MASK);
308 return 0;
310 return 1;
313 static unsigned int
314 ip6t_error(struct sk_buff **pskb,
315 const struct net_device *in,
316 const struct net_device *out,
317 unsigned int hooknum,
318 const void *targinfo,
319 void *userinfo)
321 if (net_ratelimit())
322 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
324 return NF_DROP;
327 static inline
328 int do_match(struct ip6t_entry_match *m,
329 const struct sk_buff *skb,
330 const struct net_device *in,
331 const struct net_device *out,
332 int offset,
333 unsigned int protoff,
334 int *hotdrop)
336 /* Stop iteration if it doesn't match */
337 if (!m->u.kernel.match->match(skb, in, out, m->data,
338 offset, protoff, hotdrop))
339 return 1;
340 else
341 return 0;
344 static inline struct ip6t_entry *
345 get_entry(void *base, unsigned int offset)
347 return (struct ip6t_entry *)(base + offset);
350 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
351 unsigned int
352 ip6t_do_table(struct sk_buff **pskb,
353 unsigned int hook,
354 const struct net_device *in,
355 const struct net_device *out,
356 struct ip6t_table *table,
357 void *userdata)
359 static const char nulldevname[IFNAMSIZ];
360 int offset = 0;
361 unsigned int protoff = 0;
362 int hotdrop = 0;
363 /* Initializing verdict to NF_DROP keeps gcc happy. */
364 unsigned int verdict = NF_DROP;
365 const char *indev, *outdev;
366 void *table_base;
367 struct ip6t_entry *e, *back;
369 /* Initialization */
370 indev = in ? in->name : nulldevname;
371 outdev = out ? out->name : nulldevname;
373 /* We handle fragments by dealing with the first fragment as
374 * if it was a normal packet. All other fragments are treated
375 * normally, except that they will NEVER match rules that ask
376 * things we don't know, ie. tcp syn flag or ports). If the
377 * rule is also a fragment-specific rule, non-fragments won't
378 * match it. */
380 read_lock_bh(&table->lock);
381 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
382 table_base = (void *)table->private->entries
383 + TABLE_OFFSET(table->private, smp_processor_id());
384 e = get_entry(table_base, table->private->hook_entry[hook]);
386 #ifdef CONFIG_NETFILTER_DEBUG
387 /* Check noone else using our table */
388 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
389 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
390 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
391 smp_processor_id(),
392 table->name,
393 &((struct ip6t_entry *)table_base)->comefrom,
394 ((struct ip6t_entry *)table_base)->comefrom);
396 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
397 #endif
399 /* For return from builtin chain */
400 back = get_entry(table_base, table->private->underflow[hook]);
402 do {
403 IP_NF_ASSERT(e);
404 IP_NF_ASSERT(back);
405 (*pskb)->nfcache |= e->nfcache;
406 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
407 &protoff, &offset)) {
408 struct ip6t_entry_target *t;
410 if (IP6T_MATCH_ITERATE(e, do_match,
411 *pskb, in, out,
412 offset, protoff, &hotdrop) != 0)
413 goto no_match;
415 ADD_COUNTER(e->counters,
416 ntohs((*pskb)->nh.ipv6h->payload_len)
417 + IPV6_HDR_LEN,
420 t = ip6t_get_target(e);
421 IP_NF_ASSERT(t->u.kernel.target);
422 /* Standard target? */
423 if (!t->u.kernel.target->target) {
424 int v;
426 v = ((struct ip6t_standard_target *)t)->verdict;
427 if (v < 0) {
428 /* Pop from stack? */
429 if (v != IP6T_RETURN) {
430 verdict = (unsigned)(-v) - 1;
431 break;
433 e = back;
434 back = get_entry(table_base,
435 back->comefrom);
436 continue;
438 if (table_base + v
439 != (void *)e + e->next_offset) {
440 /* Save old back ptr in next entry */
441 struct ip6t_entry *next
442 = (void *)e + e->next_offset;
443 next->comefrom
444 = (void *)back - table_base;
445 /* set back pointer to next entry */
446 back = next;
449 e = get_entry(table_base, v);
450 } else {
451 /* Targets which reenter must return
452 abs. verdicts */
453 #ifdef CONFIG_NETFILTER_DEBUG
454 ((struct ip6t_entry *)table_base)->comefrom
455 = 0xeeeeeeec;
456 #endif
457 verdict = t->u.kernel.target->target(pskb,
458 in, out,
459 hook,
460 t->data,
461 userdata);
463 #ifdef CONFIG_NETFILTER_DEBUG
464 if (((struct ip6t_entry *)table_base)->comefrom
465 != 0xeeeeeeec
466 && verdict == IP6T_CONTINUE) {
467 printk("Target %s reentered!\n",
468 t->u.kernel.target->name);
469 verdict = NF_DROP;
471 ((struct ip6t_entry *)table_base)->comefrom
472 = 0x57acc001;
473 #endif
474 if (verdict == IP6T_CONTINUE)
475 e = (void *)e + e->next_offset;
476 else
477 /* Verdict */
478 break;
480 } else {
482 no_match:
483 e = (void *)e + e->next_offset;
485 } while (!hotdrop);
487 #ifdef CONFIG_NETFILTER_DEBUG
488 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
489 #endif
490 read_unlock_bh(&table->lock);
492 #ifdef DEBUG_ALLOW_ALL
493 return NF_ACCEPT;
494 #else
495 if (hotdrop)
496 return NF_DROP;
497 else return verdict;
498 #endif
501 /* If it succeeds, returns element and locks mutex */
502 static inline void *
503 find_inlist_lock_noload(struct list_head *head,
504 const char *name,
505 int *error,
506 struct semaphore *mutex)
508 void *ret;
510 #if 1
511 duprintf("find_inlist: searching for `%s' in %s.\n",
512 name, head == &ip6t_target ? "ip6t_target"
513 : head == &ip6t_match ? "ip6t_match"
514 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
515 #endif
517 *error = down_interruptible(mutex);
518 if (*error != 0)
519 return NULL;
521 ret = list_named_find(head, name);
522 if (!ret) {
523 *error = -ENOENT;
524 up(mutex);
526 return ret;
529 #ifndef CONFIG_KMOD
530 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
531 #else
532 static void *
533 find_inlist_lock(struct list_head *head,
534 const char *name,
535 const char *prefix,
536 int *error,
537 struct semaphore *mutex)
539 void *ret;
541 ret = find_inlist_lock_noload(head, name, error, mutex);
542 if (!ret) {
543 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
544 request_module("%s%s", prefix, name);
545 ret = find_inlist_lock_noload(head, name, error, mutex);
548 return ret;
550 #endif
552 static inline struct ip6t_table *
553 ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
555 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
558 static inline struct ip6t_match *
559 find_match_lock(const char *name, int *error, struct semaphore *mutex)
561 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
564 static struct ip6t_target *
565 ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
567 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
570 /* All zeroes == unconditional rule. */
571 static inline int
572 unconditional(const struct ip6t_ip6 *ipv6)
574 unsigned int i;
576 for (i = 0; i < sizeof(*ipv6); i++)
577 if (((char *)ipv6)[i])
578 break;
580 return (i == sizeof(*ipv6));
583 /* Figures out from what hook each rule can be called: returns 0 if
584 there are loops. Puts hook bitmask in comefrom. */
585 static int
586 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
588 unsigned int hook;
590 /* No recursion; use packet counter to save back ptrs (reset
591 to 0 as we leave), and comefrom to save source hook bitmask */
592 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
593 unsigned int pos = newinfo->hook_entry[hook];
594 struct ip6t_entry *e
595 = (struct ip6t_entry *)(newinfo->entries + pos);
597 if (!(valid_hooks & (1 << hook)))
598 continue;
600 /* Set initial back pointer. */
601 e->counters.pcnt = pos;
603 for (;;) {
604 struct ip6t_standard_target *t
605 = (void *)ip6t_get_target(e);
607 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
608 printk("iptables: loop hook %u pos %u %08X.\n",
609 hook, pos, e->comefrom);
610 return 0;
612 e->comefrom
613 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
615 /* Unconditional return/END. */
616 if (e->target_offset == sizeof(struct ip6t_entry)
617 && (strcmp(t->target.u.user.name,
618 IP6T_STANDARD_TARGET) == 0)
619 && t->verdict < 0
620 && unconditional(&e->ipv6)) {
621 unsigned int oldpos, size;
623 /* Return: backtrack through the last
624 big jump. */
625 do {
626 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
627 #ifdef DEBUG_IP_FIREWALL_USER
628 if (e->comefrom
629 & (1 << NF_IP6_NUMHOOKS)) {
630 duprintf("Back unset "
631 "on hook %u "
632 "rule %u\n",
633 hook, pos);
635 #endif
636 oldpos = pos;
637 pos = e->counters.pcnt;
638 e->counters.pcnt = 0;
640 /* We're at the start. */
641 if (pos == oldpos)
642 goto next;
644 e = (struct ip6t_entry *)
645 (newinfo->entries + pos);
646 } while (oldpos == pos + e->next_offset);
648 /* Move along one */
649 size = e->next_offset;
650 e = (struct ip6t_entry *)
651 (newinfo->entries + pos + size);
652 e->counters.pcnt = pos;
653 pos += size;
654 } else {
655 int newpos = t->verdict;
657 if (strcmp(t->target.u.user.name,
658 IP6T_STANDARD_TARGET) == 0
659 && newpos >= 0) {
660 /* This a jump; chase it. */
661 duprintf("Jump rule %u -> %u\n",
662 pos, newpos);
663 } else {
664 /* ... this is a fallthru */
665 newpos = pos + e->next_offset;
667 e = (struct ip6t_entry *)
668 (newinfo->entries + newpos);
669 e->counters.pcnt = pos;
670 pos = newpos;
673 next:
674 duprintf("Finished chain %u\n", hook);
676 return 1;
679 static inline int
680 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
682 if (i && (*i)-- == 0)
683 return 1;
685 if (m->u.kernel.match->destroy)
686 m->u.kernel.match->destroy(m->data,
687 m->u.match_size - sizeof(*m));
688 module_put(m->u.kernel.match->me);
689 return 0;
692 static inline int
693 standard_check(const struct ip6t_entry_target *t,
694 unsigned int max_offset)
696 struct ip6t_standard_target *targ = (void *)t;
698 /* Check standard info. */
699 if (t->u.target_size
700 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
701 duprintf("standard_check: target size %u != %u\n",
702 t->u.target_size,
703 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
704 return 0;
707 if (targ->verdict >= 0
708 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
709 duprintf("ip6t_standard_check: bad verdict (%i)\n",
710 targ->verdict);
711 return 0;
714 if (targ->verdict < -NF_MAX_VERDICT - 1) {
715 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
716 targ->verdict);
717 return 0;
719 return 1;
722 static inline int
723 check_match(struct ip6t_entry_match *m,
724 const char *name,
725 const struct ip6t_ip6 *ipv6,
726 unsigned int hookmask,
727 unsigned int *i)
729 int ret;
730 struct ip6t_match *match;
732 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
733 if (!match) {
734 // duprintf("check_match: `%s' not found\n", m->u.name);
735 return ret;
737 if (!try_module_get(match->me)) {
738 up(&ip6t_mutex);
739 return -ENOENT;
741 m->u.kernel.match = match;
742 up(&ip6t_mutex);
744 if (m->u.kernel.match->checkentry
745 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
746 m->u.match_size - sizeof(*m),
747 hookmask)) {
748 module_put(m->u.kernel.match->me);
749 duprintf("ip_tables: check failed for `%s'.\n",
750 m->u.kernel.match->name);
751 return -EINVAL;
754 (*i)++;
755 return 0;
758 static struct ip6t_target ip6t_standard_target;
760 static inline int
761 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
762 unsigned int *i)
764 struct ip6t_entry_target *t;
765 struct ip6t_target *target;
766 int ret;
767 unsigned int j;
769 if (!ip6_checkentry(&e->ipv6)) {
770 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
771 return -EINVAL;
774 j = 0;
775 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
776 if (ret != 0)
777 goto cleanup_matches;
779 t = ip6t_get_target(e);
780 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
781 if (!target) {
782 duprintf("check_entry: `%s' not found\n", t->u.user.name);
783 goto cleanup_matches;
785 if (!try_module_get(target->me)) {
786 up(&ip6t_mutex);
787 ret = -ENOENT;
788 goto cleanup_matches;
790 t->u.kernel.target = target;
791 up(&ip6t_mutex);
792 if (!t->u.kernel.target) {
793 ret = -EBUSY;
794 goto cleanup_matches;
796 if (t->u.kernel.target == &ip6t_standard_target) {
797 if (!standard_check(t, size)) {
798 ret = -EINVAL;
799 goto cleanup_matches;
801 } else if (t->u.kernel.target->checkentry
802 && !t->u.kernel.target->checkentry(name, e, t->data,
803 t->u.target_size
804 - sizeof(*t),
805 e->comefrom)) {
806 module_put(t->u.kernel.target->me);
807 duprintf("ip_tables: check failed for `%s'.\n",
808 t->u.kernel.target->name);
809 ret = -EINVAL;
810 goto cleanup_matches;
813 (*i)++;
814 return 0;
816 cleanup_matches:
817 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
818 return ret;
821 static inline int
822 check_entry_size_and_hooks(struct ip6t_entry *e,
823 struct ip6t_table_info *newinfo,
824 unsigned char *base,
825 unsigned char *limit,
826 const unsigned int *hook_entries,
827 const unsigned int *underflows,
828 unsigned int *i)
830 unsigned int h;
832 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
833 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
834 duprintf("Bad offset %p\n", e);
835 return -EINVAL;
838 if (e->next_offset
839 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
840 duprintf("checking: element %p size %u\n",
841 e, e->next_offset);
842 return -EINVAL;
845 /* Check hooks & underflows */
846 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
847 if ((unsigned char *)e - base == hook_entries[h])
848 newinfo->hook_entry[h] = hook_entries[h];
849 if ((unsigned char *)e - base == underflows[h])
850 newinfo->underflow[h] = underflows[h];
853 /* FIXME: underflows must be unconditional, standard verdicts
854 < 0 (not IP6T_RETURN). --RR */
856 /* Clear counters and comefrom */
857 e->counters = ((struct ip6t_counters) { 0, 0 });
858 e->comefrom = 0;
860 (*i)++;
861 return 0;
864 static inline int
865 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
867 struct ip6t_entry_target *t;
869 if (i && (*i)-- == 0)
870 return 1;
872 /* Cleanup all matches */
873 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
874 t = ip6t_get_target(e);
875 if (t->u.kernel.target->destroy)
876 t->u.kernel.target->destroy(t->data,
877 t->u.target_size - sizeof(*t));
878 module_put(t->u.kernel.target->me);
879 return 0;
882 /* Checks and translates the user-supplied table segment (held in
883 newinfo) */
884 static int
885 translate_table(const char *name,
886 unsigned int valid_hooks,
887 struct ip6t_table_info *newinfo,
888 unsigned int size,
889 unsigned int number,
890 const unsigned int *hook_entries,
891 const unsigned int *underflows)
893 unsigned int i;
894 int ret;
896 newinfo->size = size;
897 newinfo->number = number;
899 /* Init all hooks to impossible value. */
900 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
901 newinfo->hook_entry[i] = 0xFFFFFFFF;
902 newinfo->underflow[i] = 0xFFFFFFFF;
905 duprintf("translate_table: size %u\n", newinfo->size);
906 i = 0;
907 /* Walk through entries, checking offsets. */
908 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
909 check_entry_size_and_hooks,
910 newinfo,
911 newinfo->entries,
912 newinfo->entries + size,
913 hook_entries, underflows, &i);
914 if (ret != 0)
915 return ret;
917 if (i != number) {
918 duprintf("translate_table: %u not %u entries\n",
919 i, number);
920 return -EINVAL;
923 /* Check hooks all assigned */
924 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
925 /* Only hooks which are valid */
926 if (!(valid_hooks & (1 << i)))
927 continue;
928 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
929 duprintf("Invalid hook entry %u %u\n",
930 i, hook_entries[i]);
931 return -EINVAL;
933 if (newinfo->underflow[i] == 0xFFFFFFFF) {
934 duprintf("Invalid underflow %u %u\n",
935 i, underflows[i]);
936 return -EINVAL;
940 if (!mark_source_chains(newinfo, valid_hooks))
941 return -ELOOP;
943 /* Finally, each sanity check must pass */
944 i = 0;
945 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
946 check_entry, name, size, &i);
948 if (ret != 0) {
949 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
950 cleanup_entry, &i);
951 return ret;
954 /* And one copy for every other CPU */
955 for (i = 1; i < num_possible_cpus(); i++) {
956 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
957 newinfo->entries,
958 SMP_ALIGN(newinfo->size));
961 return ret;
964 static struct ip6t_table_info *
965 replace_table(struct ip6t_table *table,
966 unsigned int num_counters,
967 struct ip6t_table_info *newinfo,
968 int *error)
970 struct ip6t_table_info *oldinfo;
972 #ifdef CONFIG_NETFILTER_DEBUG
974 struct ip6t_entry *table_base;
975 unsigned int i;
977 for (i = 0; i < num_possible_cpus(); i++) {
978 table_base =
979 (void *)newinfo->entries
980 + TABLE_OFFSET(newinfo, i);
982 table_base->comefrom = 0xdead57ac;
985 #endif
987 /* Do the substitution. */
988 write_lock_bh(&table->lock);
989 /* Check inside lock: is the old number correct? */
990 if (num_counters != table->private->number) {
991 duprintf("num_counters != table->private->number (%u/%u)\n",
992 num_counters, table->private->number);
993 write_unlock_bh(&table->lock);
994 *error = -EAGAIN;
995 return NULL;
997 oldinfo = table->private;
998 table->private = newinfo;
999 newinfo->initial_entries = oldinfo->initial_entries;
1000 write_unlock_bh(&table->lock);
1002 return oldinfo;
1005 /* Gets counters. */
1006 static inline int
1007 add_entry_to_counter(const struct ip6t_entry *e,
1008 struct ip6t_counters total[],
1009 unsigned int *i)
1011 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1013 (*i)++;
1014 return 0;
1017 static void
1018 get_counters(const struct ip6t_table_info *t,
1019 struct ip6t_counters counters[])
1021 unsigned int cpu;
1022 unsigned int i;
1024 for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
1025 i = 0;
1026 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1027 t->size,
1028 add_entry_to_counter,
1029 counters,
1030 &i);
1034 static int
1035 copy_entries_to_user(unsigned int total_size,
1036 struct ip6t_table *table,
1037 void __user *userptr)
1039 unsigned int off, num, countersize;
1040 struct ip6t_entry *e;
1041 struct ip6t_counters *counters;
1042 int ret = 0;
1044 /* We need atomic snapshot of counters: rest doesn't change
1045 (other than comefrom, which userspace doesn't care
1046 about). */
1047 countersize = sizeof(struct ip6t_counters) * table->private->number;
1048 counters = vmalloc(countersize);
1050 if (counters == NULL)
1051 return -ENOMEM;
1053 /* First, sum counters... */
1054 memset(counters, 0, countersize);
1055 write_lock_bh(&table->lock);
1056 get_counters(table->private, counters);
1057 write_unlock_bh(&table->lock);
1059 /* ... then copy entire thing from CPU 0... */
1060 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1061 ret = -EFAULT;
1062 goto free_counters;
1065 /* FIXME: use iterator macros --RR */
1066 /* ... then go back and fix counters and names */
1067 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1068 unsigned int i;
1069 struct ip6t_entry_match *m;
1070 struct ip6t_entry_target *t;
1072 e = (struct ip6t_entry *)(table->private->entries + off);
1073 if (copy_to_user(userptr + off
1074 + offsetof(struct ip6t_entry, counters),
1075 &counters[num],
1076 sizeof(counters[num])) != 0) {
1077 ret = -EFAULT;
1078 goto free_counters;
1081 for (i = sizeof(struct ip6t_entry);
1082 i < e->target_offset;
1083 i += m->u.match_size) {
1084 m = (void *)e + i;
1086 if (copy_to_user(userptr + off + i
1087 + offsetof(struct ip6t_entry_match,
1088 u.user.name),
1089 m->u.kernel.match->name,
1090 strlen(m->u.kernel.match->name)+1)
1091 != 0) {
1092 ret = -EFAULT;
1093 goto free_counters;
1097 t = ip6t_get_target(e);
1098 if (copy_to_user(userptr + off + e->target_offset
1099 + offsetof(struct ip6t_entry_target,
1100 u.user.name),
1101 t->u.kernel.target->name,
1102 strlen(t->u.kernel.target->name)+1) != 0) {
1103 ret = -EFAULT;
1104 goto free_counters;
1108 free_counters:
1109 vfree(counters);
1110 return ret;
1113 static int
1114 get_entries(const struct ip6t_get_entries *entries,
1115 struct ip6t_get_entries __user *uptr)
1117 int ret;
1118 struct ip6t_table *t;
1120 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1121 if (t) {
1122 duprintf("t->private->number = %u\n",
1123 t->private->number);
1124 if (entries->size == t->private->size)
1125 ret = copy_entries_to_user(t->private->size,
1126 t, uptr->entrytable);
1127 else {
1128 duprintf("get_entries: I've got %u not %u!\n",
1129 t->private->size,
1130 entries->size);
1131 ret = -EINVAL;
1133 up(&ip6t_mutex);
1134 } else
1135 duprintf("get_entries: Can't find %s!\n",
1136 entries->name);
1138 return ret;
1141 static int
1142 do_replace(void __user *user, unsigned int len)
1144 int ret;
1145 struct ip6t_replace tmp;
1146 struct ip6t_table *t;
1147 struct ip6t_table_info *newinfo, *oldinfo;
1148 struct ip6t_counters *counters;
1150 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1151 return -EFAULT;
1153 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1154 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1155 return -ENOMEM;
1157 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1158 + SMP_ALIGN(tmp.size) * num_possible_cpus());
1159 if (!newinfo)
1160 return -ENOMEM;
1162 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1163 tmp.size) != 0) {
1164 ret = -EFAULT;
1165 goto free_newinfo;
1168 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1169 if (!counters) {
1170 ret = -ENOMEM;
1171 goto free_newinfo;
1173 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1175 ret = translate_table(tmp.name, tmp.valid_hooks,
1176 newinfo, tmp.size, tmp.num_entries,
1177 tmp.hook_entry, tmp.underflow);
1178 if (ret != 0)
1179 goto free_newinfo_counters;
1181 duprintf("ip_tables: Translated table\n");
1183 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1184 if (!t)
1185 goto free_newinfo_counters_untrans;
1187 /* You lied! */
1188 if (tmp.valid_hooks != t->valid_hooks) {
1189 duprintf("Valid hook crap: %08X vs %08X\n",
1190 tmp.valid_hooks, t->valid_hooks);
1191 ret = -EINVAL;
1192 goto free_newinfo_counters_untrans_unlock;
1195 /* Get a reference in advance, we're not allowed fail later */
1196 if (!try_module_get(t->me)) {
1197 ret = -EBUSY;
1198 goto free_newinfo_counters_untrans_unlock;
1201 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1202 if (!oldinfo)
1203 goto put_module;
1205 /* Update module usage count based on number of rules */
1206 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1207 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1208 if ((oldinfo->number > oldinfo->initial_entries) ||
1209 (newinfo->number <= oldinfo->initial_entries))
1210 module_put(t->me);
1211 if ((oldinfo->number > oldinfo->initial_entries) &&
1212 (newinfo->number <= oldinfo->initial_entries))
1213 module_put(t->me);
1215 /* Get the old counters. */
1216 get_counters(oldinfo, counters);
1217 /* Decrease module usage counts and free resource */
1218 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1219 vfree(oldinfo);
1220 /* Silent error: too late now. */
1221 if (copy_to_user(tmp.counters, counters,
1222 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1223 ret = -EFAULT;
1224 vfree(counters);
1225 up(&ip6t_mutex);
1226 return ret;
1228 put_module:
1229 module_put(t->me);
1230 free_newinfo_counters_untrans_unlock:
1231 up(&ip6t_mutex);
1232 free_newinfo_counters_untrans:
1233 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1234 free_newinfo_counters:
1235 vfree(counters);
1236 free_newinfo:
1237 vfree(newinfo);
1238 return ret;
1241 /* We're lazy, and add to the first CPU; overflow works its fey magic
1242 * and everything is OK. */
1243 static inline int
1244 add_counter_to_entry(struct ip6t_entry *e,
1245 const struct ip6t_counters addme[],
1246 unsigned int *i)
1248 #if 0
1249 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1251 (long unsigned int)e->counters.pcnt,
1252 (long unsigned int)e->counters.bcnt,
1253 (long unsigned int)addme[*i].pcnt,
1254 (long unsigned int)addme[*i].bcnt);
1255 #endif
1257 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1259 (*i)++;
1260 return 0;
1263 static int
1264 do_add_counters(void __user *user, unsigned int len)
1266 unsigned int i;
1267 struct ip6t_counters_info tmp, *paddc;
1268 struct ip6t_table *t;
1269 int ret;
1271 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1272 return -EFAULT;
1274 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1275 return -EINVAL;
1277 paddc = vmalloc(len);
1278 if (!paddc)
1279 return -ENOMEM;
1281 if (copy_from_user(paddc, user, len) != 0) {
1282 ret = -EFAULT;
1283 goto free;
1286 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1287 if (!t)
1288 goto free;
1290 write_lock_bh(&t->lock);
1291 if (t->private->number != paddc->num_counters) {
1292 ret = -EINVAL;
1293 goto unlock_up_free;
1296 i = 0;
1297 IP6T_ENTRY_ITERATE(t->private->entries,
1298 t->private->size,
1299 add_counter_to_entry,
1300 paddc->counters,
1301 &i);
1302 unlock_up_free:
1303 write_unlock_bh(&t->lock);
1304 up(&ip6t_mutex);
1305 free:
1306 vfree(paddc);
1308 return ret;
1311 static int
1312 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1314 int ret;
1316 if (!capable(CAP_NET_ADMIN))
1317 return -EPERM;
1319 switch (cmd) {
1320 case IP6T_SO_SET_REPLACE:
1321 ret = do_replace(user, len);
1322 break;
1324 case IP6T_SO_SET_ADD_COUNTERS:
1325 ret = do_add_counters(user, len);
1326 break;
1328 default:
1329 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1330 ret = -EINVAL;
1333 return ret;
1336 static int
1337 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1339 int ret;
1341 if (!capable(CAP_NET_ADMIN))
1342 return -EPERM;
1344 switch (cmd) {
1345 case IP6T_SO_GET_INFO: {
1346 char name[IP6T_TABLE_MAXNAMELEN];
1347 struct ip6t_table *t;
1349 if (*len != sizeof(struct ip6t_getinfo)) {
1350 duprintf("length %u != %u\n", *len,
1351 sizeof(struct ip6t_getinfo));
1352 ret = -EINVAL;
1353 break;
1356 if (copy_from_user(name, user, sizeof(name)) != 0) {
1357 ret = -EFAULT;
1358 break;
1360 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1361 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1362 if (t) {
1363 struct ip6t_getinfo info;
1365 info.valid_hooks = t->valid_hooks;
1366 memcpy(info.hook_entry, t->private->hook_entry,
1367 sizeof(info.hook_entry));
1368 memcpy(info.underflow, t->private->underflow,
1369 sizeof(info.underflow));
1370 info.num_entries = t->private->number;
1371 info.size = t->private->size;
1372 memcpy(info.name, name, sizeof(info.name));
1374 if (copy_to_user(user, &info, *len) != 0)
1375 ret = -EFAULT;
1376 else
1377 ret = 0;
1379 up(&ip6t_mutex);
1382 break;
1384 case IP6T_SO_GET_ENTRIES: {
1385 struct ip6t_get_entries get;
1387 if (*len < sizeof(get)) {
1388 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1389 ret = -EINVAL;
1390 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1391 ret = -EFAULT;
1392 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1393 duprintf("get_entries: %u != %u\n", *len,
1394 sizeof(struct ip6t_get_entries) + get.size);
1395 ret = -EINVAL;
1396 } else
1397 ret = get_entries(&get, user);
1398 break;
1401 default:
1402 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1403 ret = -EINVAL;
1406 return ret;
1409 /* Registration hooks for targets. */
1411 ip6t_register_target(struct ip6t_target *target)
1413 int ret;
1415 ret = down_interruptible(&ip6t_mutex);
1416 if (ret != 0)
1417 return ret;
1419 if (!list_named_insert(&ip6t_target, target)) {
1420 duprintf("ip6t_register_target: `%s' already in list!\n",
1421 target->name);
1422 ret = -EINVAL;
1424 up(&ip6t_mutex);
1425 return ret;
1428 void
1429 ip6t_unregister_target(struct ip6t_target *target)
1431 down(&ip6t_mutex);
1432 LIST_DELETE(&ip6t_target, target);
1433 up(&ip6t_mutex);
1437 ip6t_register_match(struct ip6t_match *match)
1439 int ret;
1441 ret = down_interruptible(&ip6t_mutex);
1442 if (ret != 0)
1443 return ret;
1445 if (!list_named_insert(&ip6t_match, match)) {
1446 duprintf("ip6t_register_match: `%s' already in list!\n",
1447 match->name);
1448 ret = -EINVAL;
1450 up(&ip6t_mutex);
1452 return ret;
1455 void
1456 ip6t_unregister_match(struct ip6t_match *match)
1458 down(&ip6t_mutex);
1459 LIST_DELETE(&ip6t_match, match);
1460 up(&ip6t_mutex);
1463 int ip6t_register_table(struct ip6t_table *table,
1464 const struct ip6t_replace *repl)
1466 int ret;
1467 struct ip6t_table_info *newinfo;
1468 static struct ip6t_table_info bootstrap
1469 = { 0, 0, 0, { 0 }, { 0 }, { } };
1471 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1472 + SMP_ALIGN(repl->size) * num_possible_cpus());
1473 if (!newinfo)
1474 return -ENOMEM;
1476 memcpy(newinfo->entries, repl->entries, repl->size);
1478 ret = translate_table(table->name, table->valid_hooks,
1479 newinfo, repl->size,
1480 repl->num_entries,
1481 repl->hook_entry,
1482 repl->underflow);
1483 if (ret != 0) {
1484 vfree(newinfo);
1485 return ret;
1488 ret = down_interruptible(&ip6t_mutex);
1489 if (ret != 0) {
1490 vfree(newinfo);
1491 return ret;
1494 /* Don't autoload: we'd eat our tail... */
1495 if (list_named_find(&ip6t_tables, table->name)) {
1496 ret = -EEXIST;
1497 goto free_unlock;
1500 /* Simplifies replace_table code. */
1501 table->private = &bootstrap;
1502 if (!replace_table(table, 0, newinfo, &ret))
1503 goto free_unlock;
1505 duprintf("table->private->number = %u\n",
1506 table->private->number);
1508 /* save number of initial entries */
1509 table->private->initial_entries = table->private->number;
1511 rwlock_init(&table->lock);
1512 list_prepend(&ip6t_tables, table);
1514 unlock:
1515 up(&ip6t_mutex);
1516 return ret;
1518 free_unlock:
1519 vfree(newinfo);
1520 goto unlock;
1523 void ip6t_unregister_table(struct ip6t_table *table)
1525 down(&ip6t_mutex);
1526 LIST_DELETE(&ip6t_tables, table);
1527 up(&ip6t_mutex);
1529 /* Decrease module usage counts and free resources */
1530 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1531 cleanup_entry, NULL);
1532 vfree(table->private);
1535 /* Returns 1 if the port is matched by the range, 0 otherwise */
1536 static inline int
1537 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1539 int ret;
1541 ret = (port >= min && port <= max) ^ invert;
1542 return ret;
1545 static int
1546 tcp_find_option(u_int8_t option,
1547 const struct sk_buff *skb,
1548 unsigned int tcpoff,
1549 unsigned int optlen,
1550 int invert,
1551 int *hotdrop)
1553 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1554 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1555 unsigned int i;
1557 duprintf("tcp_match: finding option\n");
1558 if (!optlen)
1559 return invert;
1560 /* If we don't have the whole header, drop packet. */
1561 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1562 _opt);
1563 if (op == NULL) {
1564 *hotdrop = 1;
1565 return 0;
1568 for (i = 0; i < optlen; ) {
1569 if (op[i] == option) return !invert;
1570 if (op[i] < 2) i++;
1571 else i += op[i+1]?:1;
1574 return invert;
1577 static int
1578 tcp_match(const struct sk_buff *skb,
1579 const struct net_device *in,
1580 const struct net_device *out,
1581 const void *matchinfo,
1582 int offset,
1583 unsigned int protoff,
1584 int *hotdrop)
1586 struct tcphdr _tcph, *th;
1587 const struct ip6t_tcp *tcpinfo = matchinfo;
1589 if (offset) {
1590 /* To quote Alan:
1592 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1593 causes this. Its a cracker trying to break in by doing a
1594 flag overwrite to pass the direction checks.
1596 if (offset == 1) {
1597 duprintf("Dropping evil TCP offset=1 frag.\n");
1598 *hotdrop = 1;
1600 /* Must not be a fragment. */
1601 return 0;
1604 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1606 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1607 if (th == NULL) {
1608 /* We've been asked to examine this packet, and we
1609 can't. Hence, no choice but to drop. */
1610 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1611 *hotdrop = 1;
1612 return 0;
1615 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1616 ntohs(th->source),
1617 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1618 return 0;
1619 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1620 ntohs(th->dest),
1621 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1622 return 0;
1623 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1624 == tcpinfo->flg_cmp,
1625 IP6T_TCP_INV_FLAGS))
1626 return 0;
1627 if (tcpinfo->option) {
1628 if (th->doff * 4 < sizeof(_tcph)) {
1629 *hotdrop = 1;
1630 return 0;
1632 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1633 th->doff*4 - sizeof(*th),
1634 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1635 hotdrop))
1636 return 0;
1638 return 1;
1641 /* Called when user tries to insert an entry of this type. */
1642 static int
1643 tcp_checkentry(const char *tablename,
1644 const struct ip6t_ip6 *ipv6,
1645 void *matchinfo,
1646 unsigned int matchsize,
1647 unsigned int hook_mask)
1649 const struct ip6t_tcp *tcpinfo = matchinfo;
1651 /* Must specify proto == TCP, and no unknown invflags */
1652 return ipv6->proto == IPPROTO_TCP
1653 && !(ipv6->invflags & IP6T_INV_PROTO)
1654 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1655 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1658 static int
1659 udp_match(const struct sk_buff *skb,
1660 const struct net_device *in,
1661 const struct net_device *out,
1662 const void *matchinfo,
1663 int offset,
1664 unsigned int protoff,
1665 int *hotdrop)
1667 struct udphdr _udph, *uh;
1668 const struct ip6t_udp *udpinfo = matchinfo;
1670 /* Must not be a fragment. */
1671 if (offset)
1672 return 0;
1674 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1675 if (uh == NULL) {
1676 /* We've been asked to examine this packet, and we
1677 can't. Hence, no choice but to drop. */
1678 duprintf("Dropping evil UDP tinygram.\n");
1679 *hotdrop = 1;
1680 return 0;
1683 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1684 ntohs(uh->source),
1685 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1686 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1687 ntohs(uh->dest),
1688 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1691 /* Called when user tries to insert an entry of this type. */
1692 static int
1693 udp_checkentry(const char *tablename,
1694 const struct ip6t_ip6 *ipv6,
1695 void *matchinfo,
1696 unsigned int matchinfosize,
1697 unsigned int hook_mask)
1699 const struct ip6t_udp *udpinfo = matchinfo;
1701 /* Must specify proto == UDP, and no unknown invflags */
1702 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1703 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1704 IPPROTO_UDP);
1705 return 0;
1707 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1708 duprintf("ip6t_udp: matchsize %u != %u\n",
1709 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1710 return 0;
1712 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1713 duprintf("ip6t_udp: unknown flags %X\n",
1714 udpinfo->invflags);
1715 return 0;
1718 return 1;
1721 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1722 static inline int
1723 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1724 u_int8_t type, u_int8_t code,
1725 int invert)
1727 return (type == test_type && code >= min_code && code <= max_code)
1728 ^ invert;
1731 static int
1732 icmp6_match(const struct sk_buff *skb,
1733 const struct net_device *in,
1734 const struct net_device *out,
1735 const void *matchinfo,
1736 int offset,
1737 unsigned int protoff,
1738 int *hotdrop)
1740 struct icmp6hdr _icmp, *ic;
1741 const struct ip6t_icmp *icmpinfo = matchinfo;
1743 /* Must not be a fragment. */
1744 if (offset)
1745 return 0;
1747 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1748 if (ic == NULL) {
1749 /* We've been asked to examine this packet, and we
1750 can't. Hence, no choice but to drop. */
1751 duprintf("Dropping evil ICMP tinygram.\n");
1752 *hotdrop = 1;
1753 return 0;
1756 return icmp6_type_code_match(icmpinfo->type,
1757 icmpinfo->code[0],
1758 icmpinfo->code[1],
1759 ic->icmp6_type, ic->icmp6_code,
1760 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1763 /* Called when user tries to insert an entry of this type. */
1764 static int
1765 icmp6_checkentry(const char *tablename,
1766 const struct ip6t_ip6 *ipv6,
1767 void *matchinfo,
1768 unsigned int matchsize,
1769 unsigned int hook_mask)
1771 const struct ip6t_icmp *icmpinfo = matchinfo;
1773 /* Must specify proto == ICMP, and no unknown invflags */
1774 return ipv6->proto == IPPROTO_ICMPV6
1775 && !(ipv6->invflags & IP6T_INV_PROTO)
1776 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1777 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1780 /* The built-in targets: standard (NULL) and error. */
1781 static struct ip6t_target ip6t_standard_target = {
1782 .name = IP6T_STANDARD_TARGET,
1785 static struct ip6t_target ip6t_error_target = {
1786 .name = IP6T_ERROR_TARGET,
1787 .target = ip6t_error,
1790 static struct nf_sockopt_ops ip6t_sockopts = {
1791 .pf = PF_INET6,
1792 .set_optmin = IP6T_BASE_CTL,
1793 .set_optmax = IP6T_SO_SET_MAX+1,
1794 .set = do_ip6t_set_ctl,
1795 .get_optmin = IP6T_BASE_CTL,
1796 .get_optmax = IP6T_SO_GET_MAX+1,
1797 .get = do_ip6t_get_ctl,
1800 static struct ip6t_match tcp_matchstruct = {
1801 .name = "tcp",
1802 .match = &tcp_match,
1803 .checkentry = &tcp_checkentry,
1806 static struct ip6t_match udp_matchstruct = {
1807 .name = "udp",
1808 .match = &udp_match,
1809 .checkentry = &udp_checkentry,
1812 static struct ip6t_match icmp6_matchstruct = {
1813 .name = "icmp6",
1814 .match = &icmp6_match,
1815 .checkentry = &icmp6_checkentry,
1818 #ifdef CONFIG_PROC_FS
1819 static inline int print_name(const char *i,
1820 off_t start_offset, char *buffer, int length,
1821 off_t *pos, unsigned int *count)
1823 if ((*count)++ >= start_offset) {
1824 unsigned int namelen;
1826 namelen = sprintf(buffer + *pos, "%s\n",
1827 i + sizeof(struct list_head));
1828 if (*pos + namelen > length) {
1829 /* Stop iterating */
1830 return 1;
1832 *pos += namelen;
1834 return 0;
1837 static inline int print_target(const struct ip6t_target *t,
1838 off_t start_offset, char *buffer, int length,
1839 off_t *pos, unsigned int *count)
1841 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1842 return 0;
1843 return print_name((char *)t, start_offset, buffer, length, pos, count);
1846 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1848 off_t pos = 0;
1849 unsigned int count = 0;
1851 if (down_interruptible(&ip6t_mutex) != 0)
1852 return 0;
1854 LIST_FIND(&ip6t_tables, print_name, char *,
1855 offset, buffer, length, &pos, &count);
1857 up(&ip6t_mutex);
1859 /* `start' hack - see fs/proc/generic.c line ~105 */
1860 *start=(char *)((unsigned long)count-offset);
1861 return pos;
1864 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1866 off_t pos = 0;
1867 unsigned int count = 0;
1869 if (down_interruptible(&ip6t_mutex) != 0)
1870 return 0;
1872 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1873 offset, buffer, length, &pos, &count);
1875 up(&ip6t_mutex);
1877 *start = (char *)((unsigned long)count - offset);
1878 return pos;
1881 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1883 off_t pos = 0;
1884 unsigned int count = 0;
1886 if (down_interruptible(&ip6t_mutex) != 0)
1887 return 0;
1889 LIST_FIND(&ip6t_match, print_name, char *,
1890 offset, buffer, length, &pos, &count);
1892 up(&ip6t_mutex);
1894 *start = (char *)((unsigned long)count - offset);
1895 return pos;
1898 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1899 { { "ip6_tables_names", ip6t_get_tables },
1900 { "ip6_tables_targets", ip6t_get_targets },
1901 { "ip6_tables_matches", ip6t_get_matches },
1902 { NULL, NULL} };
1903 #endif /*CONFIG_PROC_FS*/
1905 static int __init init(void)
1907 int ret;
1909 /* Noone else will be downing sem now, so we won't sleep */
1910 down(&ip6t_mutex);
1911 list_append(&ip6t_target, &ip6t_standard_target);
1912 list_append(&ip6t_target, &ip6t_error_target);
1913 list_append(&ip6t_match, &tcp_matchstruct);
1914 list_append(&ip6t_match, &udp_matchstruct);
1915 list_append(&ip6t_match, &icmp6_matchstruct);
1916 up(&ip6t_mutex);
1918 /* Register setsockopt */
1919 ret = nf_register_sockopt(&ip6t_sockopts);
1920 if (ret < 0) {
1921 duprintf("Unable to register sockopts.\n");
1922 return ret;
1925 #ifdef CONFIG_PROC_FS
1927 struct proc_dir_entry *proc;
1928 int i;
1930 for (i = 0; ip6t_proc_entry[i].name; i++) {
1931 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1932 ip6t_proc_entry[i].get_info);
1933 if (!proc) {
1934 while (--i >= 0)
1935 proc_net_remove(ip6t_proc_entry[i].name);
1936 nf_unregister_sockopt(&ip6t_sockopts);
1937 return -ENOMEM;
1939 proc->owner = THIS_MODULE;
1942 #endif
1944 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1945 return 0;
1948 static void __exit fini(void)
1950 nf_unregister_sockopt(&ip6t_sockopts);
1951 #ifdef CONFIG_PROC_FS
1953 int i;
1954 for (i = 0; ip6t_proc_entry[i].name; i++)
1955 proc_net_remove(ip6t_proc_entry[i].name);
1957 #endif
1960 EXPORT_SYMBOL(ip6t_register_table);
1961 EXPORT_SYMBOL(ip6t_unregister_table);
1962 EXPORT_SYMBOL(ip6t_do_table);
1963 EXPORT_SYMBOL(ip6t_register_match);
1964 EXPORT_SYMBOL(ip6t_unregister_match);
1965 EXPORT_SYMBOL(ip6t_register_target);
1966 EXPORT_SYMBOL(ip6t_unregister_target);
1967 EXPORT_SYMBOL(ip6t_ext_hdr);
1969 module_init(init);
1970 module_exit(fini);