[NETFILTER]: Add "revision" support to arp_tables and ip6_tables
[linux-2.6/mini2440.git] / net / ipv6 / netfilter / ip6_tables.c
blob7d492226c16e8fef4c414872a0916e40e59d9fcc
1 /*
2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
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/ipv6.h>
27 #include <asm/uaccess.h>
28 #include <asm/semaphore.h>
29 #include <linux/proc_fs.h>
30 #include <linux/cpumask.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/listhelp.h>
76 #if 0
77 /* All the better to debug you with... */
78 #define static
79 #define inline
80 #endif
83 We keep a set of rules for each CPU, so we can avoid write-locking
84 them in the softirq when updating the counters and therefore
85 only need to read-lock in the softirq; doing a write_lock_bh() in user
86 context stops packets coming through and allows user context to read
87 the counters or update the rules.
89 To be cache friendly on SMP, we arrange them like so:
90 [ n-entries ]
91 ... cache-align padding ...
92 [ n-entries ]
94 Hence the start of any table is given by get_table() below. */
96 /* The table itself */
97 struct ip6t_table_info
99 /* Size per table */
100 unsigned int size;
101 /* Number of entries: FIXME. --RR */
102 unsigned int number;
103 /* Initial number of entries. Needed for module usage count */
104 unsigned int initial_entries;
106 /* Entry points and underflows */
107 unsigned int hook_entry[NF_IP6_NUMHOOKS];
108 unsigned int underflow[NF_IP6_NUMHOOKS];
110 /* ip6t_entry tables: one per CPU */
111 char entries[0] ____cacheline_aligned;
114 static LIST_HEAD(ip6t_target);
115 static LIST_HEAD(ip6t_match);
116 static LIST_HEAD(ip6t_tables);
117 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
119 #ifdef CONFIG_SMP
120 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
121 #else
122 #define TABLE_OFFSET(t,p) 0
123 #endif
125 #if 0
126 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
127 #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; })
128 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
129 #endif
131 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
132 struct in6_addr addr2)
134 int i;
135 for( i = 0; i < 16; i++){
136 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
137 (addr2.s6_addr[i] & mask.s6_addr[i]))
138 return 1;
140 return 0;
143 /* Check for an extension */
144 int
145 ip6t_ext_hdr(u8 nexthdr)
147 return ( (nexthdr == IPPROTO_HOPOPTS) ||
148 (nexthdr == IPPROTO_ROUTING) ||
149 (nexthdr == IPPROTO_FRAGMENT) ||
150 (nexthdr == IPPROTO_ESP) ||
151 (nexthdr == IPPROTO_AH) ||
152 (nexthdr == IPPROTO_NONE) ||
153 (nexthdr == IPPROTO_DSTOPTS) );
156 /* Returns whether matches rule or not. */
157 static inline int
158 ip6_packet_match(const struct sk_buff *skb,
159 const char *indev,
160 const char *outdev,
161 const struct ip6t_ip6 *ip6info,
162 unsigned int *protoff,
163 int *fragoff)
165 size_t i;
166 unsigned long ret;
167 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
169 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
171 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
172 IP6T_INV_SRCIP)
173 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
174 IP6T_INV_DSTIP)) {
175 dprintf("Source or dest mismatch.\n");
177 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
178 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
179 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
180 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
181 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
182 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
183 return 0;
186 /* Look for ifname matches; this should unroll nicely. */
187 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
188 ret |= (((const unsigned long *)indev)[i]
189 ^ ((const unsigned long *)ip6info->iniface)[i])
190 & ((const unsigned long *)ip6info->iniface_mask)[i];
193 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
194 dprintf("VIA in mismatch (%s vs %s).%s\n",
195 indev, ip6info->iniface,
196 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
197 return 0;
200 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
201 ret |= (((const unsigned long *)outdev)[i]
202 ^ ((const unsigned long *)ip6info->outiface)[i])
203 & ((const unsigned long *)ip6info->outiface_mask)[i];
206 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
207 dprintf("VIA out mismatch (%s vs %s).%s\n",
208 outdev, ip6info->outiface,
209 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
210 return 0;
213 /* ... might want to do something with class and flowlabel here ... */
215 /* look for the desired protocol header */
216 if((ip6info->flags & IP6T_F_PROTO)) {
217 u_int8_t currenthdr = ipv6->nexthdr;
218 struct ipv6_opt_hdr _hdr, *hp;
219 u_int16_t ptr; /* Header offset in skb */
220 u_int16_t hdrlen; /* Header */
221 u_int16_t _fragoff = 0, *fp = NULL;
223 ptr = IPV6_HDR_LEN;
225 while (ip6t_ext_hdr(currenthdr)) {
226 /* Is there enough space for the next ext header? */
227 if (skb->len - ptr < IPV6_OPTHDR_LEN)
228 return 0;
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))
235 break;
237 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
238 BUG_ON(hp == NULL);
240 /* Size calculation */
241 if (currenthdr == IPPROTO_FRAGMENT) {
242 fp = skb_header_pointer(skb,
243 ptr+offsetof(struct frag_hdr,
244 frag_off),
245 sizeof(_fragoff),
246 &_fragoff);
247 if (fp == NULL)
248 return 0;
250 _fragoff = ntohs(*fp) & ~0x7;
251 hdrlen = 8;
252 } else if (currenthdr == IPPROTO_AH)
253 hdrlen = (hp->hdrlen+2)<<2;
254 else
255 hdrlen = ipv6_optlen(hp);
257 currenthdr = hp->nexthdr;
258 ptr += hdrlen;
259 /* ptr is too large */
260 if ( ptr > skb->len )
261 return 0;
262 if (_fragoff) {
263 if (ip6t_ext_hdr(currenthdr))
264 return 0;
265 break;
269 *protoff = ptr;
270 *fragoff = _fragoff;
272 /* currenthdr contains the protocol header */
274 dprintf("Packet protocol %hi ?= %s%hi.\n",
275 currenthdr,
276 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
277 ip6info->proto);
279 if (ip6info->proto == currenthdr) {
280 if(ip6info->invflags & IP6T_INV_PROTO) {
281 return 0;
283 return 1;
286 /* We need match for the '-p all', too! */
287 if ((ip6info->proto != 0) &&
288 !(ip6info->invflags & IP6T_INV_PROTO))
289 return 0;
291 return 1;
294 /* should be ip6 safe */
295 static inline int
296 ip6_checkentry(const struct ip6t_ip6 *ipv6)
298 if (ipv6->flags & ~IP6T_F_MASK) {
299 duprintf("Unknown flag bits set: %08X\n",
300 ipv6->flags & ~IP6T_F_MASK);
301 return 0;
303 if (ipv6->invflags & ~IP6T_INV_MASK) {
304 duprintf("Unknown invflag bits set: %08X\n",
305 ipv6->invflags & ~IP6T_INV_MASK);
306 return 0;
308 return 1;
311 static unsigned int
312 ip6t_error(struct sk_buff **pskb,
313 const struct net_device *in,
314 const struct net_device *out,
315 unsigned int hooknum,
316 const void *targinfo,
317 void *userinfo)
319 if (net_ratelimit())
320 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
322 return NF_DROP;
325 static inline
326 int do_match(struct ip6t_entry_match *m,
327 const struct sk_buff *skb,
328 const struct net_device *in,
329 const struct net_device *out,
330 int offset,
331 unsigned int protoff,
332 int *hotdrop)
334 /* Stop iteration if it doesn't match */
335 if (!m->u.kernel.match->match(skb, in, out, m->data,
336 offset, protoff, hotdrop))
337 return 1;
338 else
339 return 0;
342 static inline struct ip6t_entry *
343 get_entry(void *base, unsigned int offset)
345 return (struct ip6t_entry *)(base + offset);
348 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
349 unsigned int
350 ip6t_do_table(struct sk_buff **pskb,
351 unsigned int hook,
352 const struct net_device *in,
353 const struct net_device *out,
354 struct ip6t_table *table,
355 void *userdata)
357 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
358 int offset = 0;
359 unsigned int protoff = 0;
360 int hotdrop = 0;
361 /* Initializing verdict to NF_DROP keeps gcc happy. */
362 unsigned int verdict = NF_DROP;
363 const char *indev, *outdev;
364 void *table_base;
365 struct ip6t_entry *e, *back;
367 /* Initialization */
368 indev = in ? in->name : nulldevname;
369 outdev = out ? out->name : nulldevname;
370 /* We handle fragments by dealing with the first fragment as
371 * if it was a normal packet. All other fragments are treated
372 * normally, except that they will NEVER match rules that ask
373 * things we don't know, ie. tcp syn flag or ports). If the
374 * rule is also a fragment-specific rule, non-fragments won't
375 * match it. */
377 read_lock_bh(&table->lock);
378 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
379 table_base = (void *)table->private->entries
380 + TABLE_OFFSET(table->private, smp_processor_id());
381 e = get_entry(table_base, table->private->hook_entry[hook]);
383 #ifdef CONFIG_NETFILTER_DEBUG
384 /* Check noone else using our table */
385 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
386 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
387 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
388 smp_processor_id(),
389 table->name,
390 &((struct ip6t_entry *)table_base)->comefrom,
391 ((struct ip6t_entry *)table_base)->comefrom);
393 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
394 #endif
396 /* For return from builtin chain */
397 back = get_entry(table_base, table->private->underflow[hook]);
399 do {
400 IP_NF_ASSERT(e);
401 IP_NF_ASSERT(back);
402 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
403 &protoff, &offset)) {
404 struct ip6t_entry_target *t;
406 if (IP6T_MATCH_ITERATE(e, do_match,
407 *pskb, in, out,
408 offset, protoff, &hotdrop) != 0)
409 goto no_match;
411 ADD_COUNTER(e->counters,
412 ntohs((*pskb)->nh.ipv6h->payload_len)
413 + IPV6_HDR_LEN,
416 t = ip6t_get_target(e);
417 IP_NF_ASSERT(t->u.kernel.target);
418 /* Standard target? */
419 if (!t->u.kernel.target->target) {
420 int v;
422 v = ((struct ip6t_standard_target *)t)->verdict;
423 if (v < 0) {
424 /* Pop from stack? */
425 if (v != IP6T_RETURN) {
426 verdict = (unsigned)(-v) - 1;
427 break;
429 e = back;
430 back = get_entry(table_base,
431 back->comefrom);
432 continue;
434 if (table_base + v != (void *)e + e->next_offset
435 && !(e->ipv6.flags & IP6T_F_GOTO)) {
436 /* Save old back ptr in next entry */
437 struct ip6t_entry *next
438 = (void *)e + e->next_offset;
439 next->comefrom
440 = (void *)back - table_base;
441 /* set back pointer to next entry */
442 back = next;
445 e = get_entry(table_base, v);
446 } else {
447 /* Targets which reenter must return
448 abs. verdicts */
449 #ifdef CONFIG_NETFILTER_DEBUG
450 ((struct ip6t_entry *)table_base)->comefrom
451 = 0xeeeeeeec;
452 #endif
453 verdict = t->u.kernel.target->target(pskb,
454 in, out,
455 hook,
456 t->data,
457 userdata);
459 #ifdef CONFIG_NETFILTER_DEBUG
460 if (((struct ip6t_entry *)table_base)->comefrom
461 != 0xeeeeeeec
462 && verdict == IP6T_CONTINUE) {
463 printk("Target %s reentered!\n",
464 t->u.kernel.target->name);
465 verdict = NF_DROP;
467 ((struct ip6t_entry *)table_base)->comefrom
468 = 0x57acc001;
469 #endif
470 if (verdict == IP6T_CONTINUE)
471 e = (void *)e + e->next_offset;
472 else
473 /* Verdict */
474 break;
476 } else {
478 no_match:
479 e = (void *)e + e->next_offset;
481 } while (!hotdrop);
483 #ifdef CONFIG_NETFILTER_DEBUG
484 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
485 #endif
486 read_unlock_bh(&table->lock);
488 #ifdef DEBUG_ALLOW_ALL
489 return NF_ACCEPT;
490 #else
491 if (hotdrop)
492 return NF_DROP;
493 else return verdict;
494 #endif
498 * These are weird, but module loading must not be done with mutex
499 * held (since they will register), and we have to have a single
500 * function to use try_then_request_module().
503 /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
504 static inline struct ip6t_table *find_table_lock(const char *name)
506 struct ip6t_table *t;
508 if (down_interruptible(&ip6t_mutex) != 0)
509 return ERR_PTR(-EINTR);
511 list_for_each_entry(t, &ip6t_tables, list)
512 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
513 return t;
514 up(&ip6t_mutex);
515 return NULL;
518 /* Find match, grabs ref. Returns ERR_PTR() on error. */
519 static inline struct ip6t_match *find_match(const char *name, u8 revision)
521 struct ip6t_match *m;
522 int err = 0;
524 if (down_interruptible(&ip6t_mutex) != 0)
525 return ERR_PTR(-EINTR);
527 list_for_each_entry(m, &ip6t_match, list) {
528 if (strcmp(m->name, name) == 0) {
529 if (m->revision == revision) {
530 if (try_module_get(m->me)) {
531 up(&ip6t_mutex);
532 return m;
534 } else
535 err = -EPROTOTYPE; /* Found something. */
538 up(&ip6t_mutex);
539 return ERR_PTR(err);
542 /* Find target, grabs ref. Returns ERR_PTR() on error. */
543 static inline struct ip6t_target *find_target(const char *name, u8 revision)
545 struct ip6t_target *t;
546 int err = 0;
548 if (down_interruptible(&ip6t_mutex) != 0)
549 return ERR_PTR(-EINTR);
551 list_for_each_entry(t, &ip6t_target, list) {
552 if (strcmp(t->name, name) == 0) {
553 if (t->revision == revision) {
554 if (try_module_get(t->me)) {
555 up(&ip6t_mutex);
556 return t;
558 } else
559 err = -EPROTOTYPE; /* Found something. */
562 up(&ip6t_mutex);
563 return ERR_PTR(err);
566 struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
568 struct ip6t_target *target;
570 target = try_then_request_module(find_target(name, revision),
571 "ip6t_%s", name);
572 if (IS_ERR(target) || !target)
573 return NULL;
574 return target;
577 static int match_revfn(const char *name, u8 revision, int *bestp)
579 struct ip6t_match *m;
580 int have_rev = 0;
582 list_for_each_entry(m, &ip6t_match, list) {
583 if (strcmp(m->name, name) == 0) {
584 if (m->revision > *bestp)
585 *bestp = m->revision;
586 if (m->revision == revision)
587 have_rev = 1;
590 return have_rev;
593 static int target_revfn(const char *name, u8 revision, int *bestp)
595 struct ip6t_target *t;
596 int have_rev = 0;
598 list_for_each_entry(t, &ip6t_target, list) {
599 if (strcmp(t->name, name) == 0) {
600 if (t->revision > *bestp)
601 *bestp = t->revision;
602 if (t->revision == revision)
603 have_rev = 1;
606 return have_rev;
609 /* Returns true or fals (if no such extension at all) */
610 static inline int find_revision(const char *name, u8 revision,
611 int (*revfn)(const char *, u8, int *),
612 int *err)
614 int have_rev, best = -1;
616 if (down_interruptible(&ip6t_mutex) != 0) {
617 *err = -EINTR;
618 return 1;
620 have_rev = revfn(name, revision, &best);
621 up(&ip6t_mutex);
623 /* Nothing at all? Return 0 to try loading module. */
624 if (best == -1) {
625 *err = -ENOENT;
626 return 0;
629 *err = best;
630 if (!have_rev)
631 *err = -EPROTONOSUPPORT;
632 return 1;
636 /* All zeroes == unconditional rule. */
637 static inline int
638 unconditional(const struct ip6t_ip6 *ipv6)
640 unsigned int i;
642 for (i = 0; i < sizeof(*ipv6); i++)
643 if (((char *)ipv6)[i])
644 break;
646 return (i == sizeof(*ipv6));
649 /* Figures out from what hook each rule can be called: returns 0 if
650 there are loops. Puts hook bitmask in comefrom. */
651 static int
652 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
654 unsigned int hook;
656 /* No recursion; use packet counter to save back ptrs (reset
657 to 0 as we leave), and comefrom to save source hook bitmask */
658 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
659 unsigned int pos = newinfo->hook_entry[hook];
660 struct ip6t_entry *e
661 = (struct ip6t_entry *)(newinfo->entries + pos);
663 if (!(valid_hooks & (1 << hook)))
664 continue;
666 /* Set initial back pointer. */
667 e->counters.pcnt = pos;
669 for (;;) {
670 struct ip6t_standard_target *t
671 = (void *)ip6t_get_target(e);
673 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
674 printk("iptables: loop hook %u pos %u %08X.\n",
675 hook, pos, e->comefrom);
676 return 0;
678 e->comefrom
679 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
681 /* Unconditional return/END. */
682 if (e->target_offset == sizeof(struct ip6t_entry)
683 && (strcmp(t->target.u.user.name,
684 IP6T_STANDARD_TARGET) == 0)
685 && t->verdict < 0
686 && unconditional(&e->ipv6)) {
687 unsigned int oldpos, size;
689 /* Return: backtrack through the last
690 big jump. */
691 do {
692 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
693 #ifdef DEBUG_IP_FIREWALL_USER
694 if (e->comefrom
695 & (1 << NF_IP6_NUMHOOKS)) {
696 duprintf("Back unset "
697 "on hook %u "
698 "rule %u\n",
699 hook, pos);
701 #endif
702 oldpos = pos;
703 pos = e->counters.pcnt;
704 e->counters.pcnt = 0;
706 /* We're at the start. */
707 if (pos == oldpos)
708 goto next;
710 e = (struct ip6t_entry *)
711 (newinfo->entries + pos);
712 } while (oldpos == pos + e->next_offset);
714 /* Move along one */
715 size = e->next_offset;
716 e = (struct ip6t_entry *)
717 (newinfo->entries + pos + size);
718 e->counters.pcnt = pos;
719 pos += size;
720 } else {
721 int newpos = t->verdict;
723 if (strcmp(t->target.u.user.name,
724 IP6T_STANDARD_TARGET) == 0
725 && newpos >= 0) {
726 /* This a jump; chase it. */
727 duprintf("Jump rule %u -> %u\n",
728 pos, newpos);
729 } else {
730 /* ... this is a fallthru */
731 newpos = pos + e->next_offset;
733 e = (struct ip6t_entry *)
734 (newinfo->entries + newpos);
735 e->counters.pcnt = pos;
736 pos = newpos;
739 next:
740 duprintf("Finished chain %u\n", hook);
742 return 1;
745 static inline int
746 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
748 if (i && (*i)-- == 0)
749 return 1;
751 if (m->u.kernel.match->destroy)
752 m->u.kernel.match->destroy(m->data,
753 m->u.match_size - sizeof(*m));
754 module_put(m->u.kernel.match->me);
755 return 0;
758 static inline int
759 standard_check(const struct ip6t_entry_target *t,
760 unsigned int max_offset)
762 struct ip6t_standard_target *targ = (void *)t;
764 /* Check standard info. */
765 if (t->u.target_size
766 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
767 duprintf("standard_check: target size %u != %u\n",
768 t->u.target_size,
769 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
770 return 0;
773 if (targ->verdict >= 0
774 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
775 duprintf("ip6t_standard_check: bad verdict (%i)\n",
776 targ->verdict);
777 return 0;
780 if (targ->verdict < -NF_MAX_VERDICT - 1) {
781 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
782 targ->verdict);
783 return 0;
785 return 1;
788 static inline int
789 check_match(struct ip6t_entry_match *m,
790 const char *name,
791 const struct ip6t_ip6 *ipv6,
792 unsigned int hookmask,
793 unsigned int *i)
795 struct ip6t_match *match;
797 match = try_then_request_module(find_match(m->u.user.name,
798 m->u.user.revision),
799 "ip6t_%s", m->u.user.name);
800 if (IS_ERR(match) || !match) {
801 duprintf("check_match: `%s' not found\n", m->u.user.name);
802 return match ? PTR_ERR(match) : -ENOENT;
804 m->u.kernel.match = match;
806 if (m->u.kernel.match->checkentry
807 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
808 m->u.match_size - sizeof(*m),
809 hookmask)) {
810 module_put(m->u.kernel.match->me);
811 duprintf("ip_tables: check failed for `%s'.\n",
812 m->u.kernel.match->name);
813 return -EINVAL;
816 (*i)++;
817 return 0;
820 static struct ip6t_target ip6t_standard_target;
822 static inline int
823 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
824 unsigned int *i)
826 struct ip6t_entry_target *t;
827 struct ip6t_target *target;
828 int ret;
829 unsigned int j;
831 if (!ip6_checkentry(&e->ipv6)) {
832 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
833 return -EINVAL;
836 j = 0;
837 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
838 if (ret != 0)
839 goto cleanup_matches;
841 t = ip6t_get_target(e);
842 target = try_then_request_module(find_target(t->u.user.name,
843 t->u.user.revision),
844 "ip6t_%s", t->u.user.name);
845 if (IS_ERR(target) || !target) {
846 duprintf("check_entry: `%s' not found\n", t->u.user.name);
847 ret = target ? PTR_ERR(target) : -ENOENT;
848 goto cleanup_matches;
850 t->u.kernel.target = target;
852 if (t->u.kernel.target == &ip6t_standard_target) {
853 if (!standard_check(t, size)) {
854 ret = -EINVAL;
855 goto cleanup_matches;
857 } else if (t->u.kernel.target->checkentry
858 && !t->u.kernel.target->checkentry(name, e, t->data,
859 t->u.target_size
860 - sizeof(*t),
861 e->comefrom)) {
862 module_put(t->u.kernel.target->me);
863 duprintf("ip_tables: check failed for `%s'.\n",
864 t->u.kernel.target->name);
865 ret = -EINVAL;
866 goto cleanup_matches;
869 (*i)++;
870 return 0;
872 cleanup_matches:
873 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
874 return ret;
877 static inline int
878 check_entry_size_and_hooks(struct ip6t_entry *e,
879 struct ip6t_table_info *newinfo,
880 unsigned char *base,
881 unsigned char *limit,
882 const unsigned int *hook_entries,
883 const unsigned int *underflows,
884 unsigned int *i)
886 unsigned int h;
888 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
889 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
890 duprintf("Bad offset %p\n", e);
891 return -EINVAL;
894 if (e->next_offset
895 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
896 duprintf("checking: element %p size %u\n",
897 e, e->next_offset);
898 return -EINVAL;
901 /* Check hooks & underflows */
902 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
903 if ((unsigned char *)e - base == hook_entries[h])
904 newinfo->hook_entry[h] = hook_entries[h];
905 if ((unsigned char *)e - base == underflows[h])
906 newinfo->underflow[h] = underflows[h];
909 /* FIXME: underflows must be unconditional, standard verdicts
910 < 0 (not IP6T_RETURN). --RR */
912 /* Clear counters and comefrom */
913 e->counters = ((struct ip6t_counters) { 0, 0 });
914 e->comefrom = 0;
916 (*i)++;
917 return 0;
920 static inline int
921 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
923 struct ip6t_entry_target *t;
925 if (i && (*i)-- == 0)
926 return 1;
928 /* Cleanup all matches */
929 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
930 t = ip6t_get_target(e);
931 if (t->u.kernel.target->destroy)
932 t->u.kernel.target->destroy(t->data,
933 t->u.target_size - sizeof(*t));
934 module_put(t->u.kernel.target->me);
935 return 0;
938 /* Checks and translates the user-supplied table segment (held in
939 newinfo) */
940 static int
941 translate_table(const char *name,
942 unsigned int valid_hooks,
943 struct ip6t_table_info *newinfo,
944 unsigned int size,
945 unsigned int number,
946 const unsigned int *hook_entries,
947 const unsigned int *underflows)
949 unsigned int i;
950 int ret;
952 newinfo->size = size;
953 newinfo->number = number;
955 /* Init all hooks to impossible value. */
956 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
957 newinfo->hook_entry[i] = 0xFFFFFFFF;
958 newinfo->underflow[i] = 0xFFFFFFFF;
961 duprintf("translate_table: size %u\n", newinfo->size);
962 i = 0;
963 /* Walk through entries, checking offsets. */
964 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
965 check_entry_size_and_hooks,
966 newinfo,
967 newinfo->entries,
968 newinfo->entries + size,
969 hook_entries, underflows, &i);
970 if (ret != 0)
971 return ret;
973 if (i != number) {
974 duprintf("translate_table: %u not %u entries\n",
975 i, number);
976 return -EINVAL;
979 /* Check hooks all assigned */
980 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
981 /* Only hooks which are valid */
982 if (!(valid_hooks & (1 << i)))
983 continue;
984 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
985 duprintf("Invalid hook entry %u %u\n",
986 i, hook_entries[i]);
987 return -EINVAL;
989 if (newinfo->underflow[i] == 0xFFFFFFFF) {
990 duprintf("Invalid underflow %u %u\n",
991 i, underflows[i]);
992 return -EINVAL;
996 if (!mark_source_chains(newinfo, valid_hooks))
997 return -ELOOP;
999 /* Finally, each sanity check must pass */
1000 i = 0;
1001 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1002 check_entry, name, size, &i);
1004 if (ret != 0) {
1005 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
1006 cleanup_entry, &i);
1007 return ret;
1010 /* And one copy for every other CPU */
1011 for_each_cpu(i) {
1012 if (i == 0)
1013 continue;
1014 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,
1015 newinfo->entries,
1016 SMP_ALIGN(newinfo->size));
1019 return ret;
1022 static struct ip6t_table_info *
1023 replace_table(struct ip6t_table *table,
1024 unsigned int num_counters,
1025 struct ip6t_table_info *newinfo,
1026 int *error)
1028 struct ip6t_table_info *oldinfo;
1030 #ifdef CONFIG_NETFILTER_DEBUG
1032 struct ip6t_entry *table_base;
1033 unsigned int i;
1035 for_each_cpu(i) {
1036 table_base =
1037 (void *)newinfo->entries
1038 + TABLE_OFFSET(newinfo, i);
1040 table_base->comefrom = 0xdead57ac;
1043 #endif
1045 /* Do the substitution. */
1046 write_lock_bh(&table->lock);
1047 /* Check inside lock: is the old number correct? */
1048 if (num_counters != table->private->number) {
1049 duprintf("num_counters != table->private->number (%u/%u)\n",
1050 num_counters, table->private->number);
1051 write_unlock_bh(&table->lock);
1052 *error = -EAGAIN;
1053 return NULL;
1055 oldinfo = table->private;
1056 table->private = newinfo;
1057 newinfo->initial_entries = oldinfo->initial_entries;
1058 write_unlock_bh(&table->lock);
1060 return oldinfo;
1063 /* Gets counters. */
1064 static inline int
1065 add_entry_to_counter(const struct ip6t_entry *e,
1066 struct ip6t_counters total[],
1067 unsigned int *i)
1069 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1071 (*i)++;
1072 return 0;
1075 static void
1076 get_counters(const struct ip6t_table_info *t,
1077 struct ip6t_counters counters[])
1079 unsigned int cpu;
1080 unsigned int i;
1082 for_each_cpu(cpu) {
1083 i = 0;
1084 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1085 t->size,
1086 add_entry_to_counter,
1087 counters,
1088 &i);
1092 static int
1093 copy_entries_to_user(unsigned int total_size,
1094 struct ip6t_table *table,
1095 void __user *userptr)
1097 unsigned int off, num, countersize;
1098 struct ip6t_entry *e;
1099 struct ip6t_counters *counters;
1100 int ret = 0;
1102 /* We need atomic snapshot of counters: rest doesn't change
1103 (other than comefrom, which userspace doesn't care
1104 about). */
1105 countersize = sizeof(struct ip6t_counters) * table->private->number;
1106 counters = vmalloc(countersize);
1108 if (counters == NULL)
1109 return -ENOMEM;
1111 /* First, sum counters... */
1112 memset(counters, 0, countersize);
1113 write_lock_bh(&table->lock);
1114 get_counters(table->private, counters);
1115 write_unlock_bh(&table->lock);
1117 /* ... then copy entire thing from CPU 0... */
1118 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1119 ret = -EFAULT;
1120 goto free_counters;
1123 /* FIXME: use iterator macros --RR */
1124 /* ... then go back and fix counters and names */
1125 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1126 unsigned int i;
1127 struct ip6t_entry_match *m;
1128 struct ip6t_entry_target *t;
1130 e = (struct ip6t_entry *)(table->private->entries + off);
1131 if (copy_to_user(userptr + off
1132 + offsetof(struct ip6t_entry, counters),
1133 &counters[num],
1134 sizeof(counters[num])) != 0) {
1135 ret = -EFAULT;
1136 goto free_counters;
1139 for (i = sizeof(struct ip6t_entry);
1140 i < e->target_offset;
1141 i += m->u.match_size) {
1142 m = (void *)e + i;
1144 if (copy_to_user(userptr + off + i
1145 + offsetof(struct ip6t_entry_match,
1146 u.user.name),
1147 m->u.kernel.match->name,
1148 strlen(m->u.kernel.match->name)+1)
1149 != 0) {
1150 ret = -EFAULT;
1151 goto free_counters;
1155 t = ip6t_get_target(e);
1156 if (copy_to_user(userptr + off + e->target_offset
1157 + offsetof(struct ip6t_entry_target,
1158 u.user.name),
1159 t->u.kernel.target->name,
1160 strlen(t->u.kernel.target->name)+1) != 0) {
1161 ret = -EFAULT;
1162 goto free_counters;
1166 free_counters:
1167 vfree(counters);
1168 return ret;
1171 static int
1172 get_entries(const struct ip6t_get_entries *entries,
1173 struct ip6t_get_entries __user *uptr)
1175 int ret;
1176 struct ip6t_table *t;
1178 t = find_table_lock(entries->name);
1179 if (t && !IS_ERR(t)) {
1180 duprintf("t->private->number = %u\n",
1181 t->private->number);
1182 if (entries->size == t->private->size)
1183 ret = copy_entries_to_user(t->private->size,
1184 t, uptr->entrytable);
1185 else {
1186 duprintf("get_entries: I've got %u not %u!\n",
1187 t->private->size,
1188 entries->size);
1189 ret = -EINVAL;
1191 module_put(t->me);
1192 up(&ip6t_mutex);
1193 } else
1194 ret = t ? PTR_ERR(t) : -ENOENT;
1196 return ret;
1199 static int
1200 do_replace(void __user *user, unsigned int len)
1202 int ret;
1203 struct ip6t_replace tmp;
1204 struct ip6t_table *t;
1205 struct ip6t_table_info *newinfo, *oldinfo;
1206 struct ip6t_counters *counters;
1208 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1209 return -EFAULT;
1211 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1212 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1213 return -ENOMEM;
1215 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1216 + SMP_ALIGN(tmp.size) *
1217 (highest_possible_processor_id()+1));
1218 if (!newinfo)
1219 return -ENOMEM;
1221 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1222 tmp.size) != 0) {
1223 ret = -EFAULT;
1224 goto free_newinfo;
1227 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1228 if (!counters) {
1229 ret = -ENOMEM;
1230 goto free_newinfo;
1232 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1234 ret = translate_table(tmp.name, tmp.valid_hooks,
1235 newinfo, tmp.size, tmp.num_entries,
1236 tmp.hook_entry, tmp.underflow);
1237 if (ret != 0)
1238 goto free_newinfo_counters;
1240 duprintf("ip_tables: Translated table\n");
1242 t = try_then_request_module(find_table_lock(tmp.name),
1243 "ip6table_%s", tmp.name);
1244 if (!t || IS_ERR(t)) {
1245 ret = t ? PTR_ERR(t) : -ENOENT;
1246 goto free_newinfo_counters_untrans;
1249 /* You lied! */
1250 if (tmp.valid_hooks != t->valid_hooks) {
1251 duprintf("Valid hook crap: %08X vs %08X\n",
1252 tmp.valid_hooks, t->valid_hooks);
1253 ret = -EINVAL;
1254 goto put_module;
1257 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1258 if (!oldinfo)
1259 goto put_module;
1261 /* Update module usage count based on number of rules */
1262 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1263 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1264 if ((oldinfo->number > oldinfo->initial_entries) ||
1265 (newinfo->number <= oldinfo->initial_entries))
1266 module_put(t->me);
1267 if ((oldinfo->number > oldinfo->initial_entries) &&
1268 (newinfo->number <= oldinfo->initial_entries))
1269 module_put(t->me);
1271 /* Get the old counters. */
1272 get_counters(oldinfo, counters);
1273 /* Decrease module usage counts and free resource */
1274 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1275 vfree(oldinfo);
1276 if (copy_to_user(tmp.counters, counters,
1277 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1278 ret = -EFAULT;
1279 vfree(counters);
1280 up(&ip6t_mutex);
1281 return ret;
1283 put_module:
1284 module_put(t->me);
1285 up(&ip6t_mutex);
1286 free_newinfo_counters_untrans:
1287 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1288 free_newinfo_counters:
1289 vfree(counters);
1290 free_newinfo:
1291 vfree(newinfo);
1292 return ret;
1295 /* We're lazy, and add to the first CPU; overflow works its fey magic
1296 * and everything is OK. */
1297 static inline int
1298 add_counter_to_entry(struct ip6t_entry *e,
1299 const struct ip6t_counters addme[],
1300 unsigned int *i)
1302 #if 0
1303 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1305 (long unsigned int)e->counters.pcnt,
1306 (long unsigned int)e->counters.bcnt,
1307 (long unsigned int)addme[*i].pcnt,
1308 (long unsigned int)addme[*i].bcnt);
1309 #endif
1311 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1313 (*i)++;
1314 return 0;
1317 static int
1318 do_add_counters(void __user *user, unsigned int len)
1320 unsigned int i;
1321 struct ip6t_counters_info tmp, *paddc;
1322 struct ip6t_table *t;
1323 int ret = 0;
1325 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1326 return -EFAULT;
1328 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1329 return -EINVAL;
1331 paddc = vmalloc(len);
1332 if (!paddc)
1333 return -ENOMEM;
1335 if (copy_from_user(paddc, user, len) != 0) {
1336 ret = -EFAULT;
1337 goto free;
1340 t = find_table_lock(tmp.name);
1341 if (!t || IS_ERR(t)) {
1342 ret = t ? PTR_ERR(t) : -ENOENT;
1343 goto free;
1346 write_lock_bh(&t->lock);
1347 if (t->private->number != paddc->num_counters) {
1348 ret = -EINVAL;
1349 goto unlock_up_free;
1352 i = 0;
1353 IP6T_ENTRY_ITERATE(t->private->entries,
1354 t->private->size,
1355 add_counter_to_entry,
1356 paddc->counters,
1357 &i);
1358 unlock_up_free:
1359 write_unlock_bh(&t->lock);
1360 up(&ip6t_mutex);
1361 module_put(t->me);
1362 free:
1363 vfree(paddc);
1365 return ret;
1368 static int
1369 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1371 int ret;
1373 if (!capable(CAP_NET_ADMIN))
1374 return -EPERM;
1376 switch (cmd) {
1377 case IP6T_SO_SET_REPLACE:
1378 ret = do_replace(user, len);
1379 break;
1381 case IP6T_SO_SET_ADD_COUNTERS:
1382 ret = do_add_counters(user, len);
1383 break;
1385 default:
1386 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1387 ret = -EINVAL;
1390 return ret;
1393 static int
1394 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1396 int ret;
1398 if (!capable(CAP_NET_ADMIN))
1399 return -EPERM;
1401 switch (cmd) {
1402 case IP6T_SO_GET_INFO: {
1403 char name[IP6T_TABLE_MAXNAMELEN];
1404 struct ip6t_table *t;
1406 if (*len != sizeof(struct ip6t_getinfo)) {
1407 duprintf("length %u != %u\n", *len,
1408 sizeof(struct ip6t_getinfo));
1409 ret = -EINVAL;
1410 break;
1413 if (copy_from_user(name, user, sizeof(name)) != 0) {
1414 ret = -EFAULT;
1415 break;
1417 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1419 t = try_then_request_module(find_table_lock(name),
1420 "ip6table_%s", name);
1421 if (t && !IS_ERR(t)) {
1422 struct ip6t_getinfo info;
1424 info.valid_hooks = t->valid_hooks;
1425 memcpy(info.hook_entry, t->private->hook_entry,
1426 sizeof(info.hook_entry));
1427 memcpy(info.underflow, t->private->underflow,
1428 sizeof(info.underflow));
1429 info.num_entries = t->private->number;
1430 info.size = t->private->size;
1431 memcpy(info.name, name, sizeof(info.name));
1433 if (copy_to_user(user, &info, *len) != 0)
1434 ret = -EFAULT;
1435 else
1436 ret = 0;
1437 up(&ip6t_mutex);
1438 module_put(t->me);
1439 } else
1440 ret = t ? PTR_ERR(t) : -ENOENT;
1442 break;
1444 case IP6T_SO_GET_ENTRIES: {
1445 struct ip6t_get_entries get;
1447 if (*len < sizeof(get)) {
1448 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1449 ret = -EINVAL;
1450 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1451 ret = -EFAULT;
1452 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1453 duprintf("get_entries: %u != %u\n", *len,
1454 sizeof(struct ip6t_get_entries) + get.size);
1455 ret = -EINVAL;
1456 } else
1457 ret = get_entries(&get, user);
1458 break;
1461 case IP6T_SO_GET_REVISION_MATCH:
1462 case IP6T_SO_GET_REVISION_TARGET: {
1463 struct ip6t_get_revision rev;
1464 int (*revfn)(const char *, u8, int *);
1466 if (*len != sizeof(rev)) {
1467 ret = -EINVAL;
1468 break;
1470 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1471 ret = -EFAULT;
1472 break;
1475 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1476 revfn = target_revfn;
1477 else
1478 revfn = match_revfn;
1480 try_then_request_module(find_revision(rev.name, rev.revision,
1481 revfn, &ret),
1482 "ip6t_%s", rev.name);
1483 break;
1486 default:
1487 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1488 ret = -EINVAL;
1491 return ret;
1494 /* Registration hooks for targets. */
1496 ip6t_register_target(struct ip6t_target *target)
1498 int ret;
1500 ret = down_interruptible(&ip6t_mutex);
1501 if (ret != 0)
1502 return ret;
1503 list_add(&target->list, &ip6t_target);
1504 up(&ip6t_mutex);
1505 return ret;
1508 void
1509 ip6t_unregister_target(struct ip6t_target *target)
1511 down(&ip6t_mutex);
1512 LIST_DELETE(&ip6t_target, target);
1513 up(&ip6t_mutex);
1517 ip6t_register_match(struct ip6t_match *match)
1519 int ret;
1521 ret = down_interruptible(&ip6t_mutex);
1522 if (ret != 0)
1523 return ret;
1525 list_add(&match->list, &ip6t_match);
1526 up(&ip6t_mutex);
1528 return ret;
1531 void
1532 ip6t_unregister_match(struct ip6t_match *match)
1534 down(&ip6t_mutex);
1535 LIST_DELETE(&ip6t_match, match);
1536 up(&ip6t_mutex);
1539 int ip6t_register_table(struct ip6t_table *table,
1540 const struct ip6t_replace *repl)
1542 int ret;
1543 struct ip6t_table_info *newinfo;
1544 static struct ip6t_table_info bootstrap
1545 = { 0, 0, 0, { 0 }, { 0 }, { } };
1547 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1548 + SMP_ALIGN(repl->size) *
1549 (highest_possible_processor_id()+1));
1550 if (!newinfo)
1551 return -ENOMEM;
1553 memcpy(newinfo->entries, repl->entries, repl->size);
1555 ret = translate_table(table->name, table->valid_hooks,
1556 newinfo, repl->size,
1557 repl->num_entries,
1558 repl->hook_entry,
1559 repl->underflow);
1560 if (ret != 0) {
1561 vfree(newinfo);
1562 return ret;
1565 ret = down_interruptible(&ip6t_mutex);
1566 if (ret != 0) {
1567 vfree(newinfo);
1568 return ret;
1571 /* Don't autoload: we'd eat our tail... */
1572 if (list_named_find(&ip6t_tables, table->name)) {
1573 ret = -EEXIST;
1574 goto free_unlock;
1577 /* Simplifies replace_table code. */
1578 table->private = &bootstrap;
1579 if (!replace_table(table, 0, newinfo, &ret))
1580 goto free_unlock;
1582 duprintf("table->private->number = %u\n",
1583 table->private->number);
1585 /* save number of initial entries */
1586 table->private->initial_entries = table->private->number;
1588 rwlock_init(&table->lock);
1589 list_prepend(&ip6t_tables, table);
1591 unlock:
1592 up(&ip6t_mutex);
1593 return ret;
1595 free_unlock:
1596 vfree(newinfo);
1597 goto unlock;
1600 void ip6t_unregister_table(struct ip6t_table *table)
1602 down(&ip6t_mutex);
1603 LIST_DELETE(&ip6t_tables, table);
1604 up(&ip6t_mutex);
1606 /* Decrease module usage counts and free resources */
1607 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1608 cleanup_entry, NULL);
1609 vfree(table->private);
1612 /* Returns 1 if the port is matched by the range, 0 otherwise */
1613 static inline int
1614 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1616 int ret;
1618 ret = (port >= min && port <= max) ^ invert;
1619 return ret;
1622 static int
1623 tcp_find_option(u_int8_t option,
1624 const struct sk_buff *skb,
1625 unsigned int tcpoff,
1626 unsigned int optlen,
1627 int invert,
1628 int *hotdrop)
1630 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1631 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1632 unsigned int i;
1634 duprintf("tcp_match: finding option\n");
1635 if (!optlen)
1636 return invert;
1637 /* If we don't have the whole header, drop packet. */
1638 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1639 _opt);
1640 if (op == NULL) {
1641 *hotdrop = 1;
1642 return 0;
1645 for (i = 0; i < optlen; ) {
1646 if (op[i] == option) return !invert;
1647 if (op[i] < 2) i++;
1648 else i += op[i+1]?:1;
1651 return invert;
1654 static int
1655 tcp_match(const struct sk_buff *skb,
1656 const struct net_device *in,
1657 const struct net_device *out,
1658 const void *matchinfo,
1659 int offset,
1660 unsigned int protoff,
1661 int *hotdrop)
1663 struct tcphdr _tcph, *th;
1664 const struct ip6t_tcp *tcpinfo = matchinfo;
1666 if (offset) {
1667 /* To quote Alan:
1669 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1670 causes this. Its a cracker trying to break in by doing a
1671 flag overwrite to pass the direction checks.
1673 if (offset == 1) {
1674 duprintf("Dropping evil TCP offset=1 frag.\n");
1675 *hotdrop = 1;
1677 /* Must not be a fragment. */
1678 return 0;
1681 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1683 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1684 if (th == NULL) {
1685 /* We've been asked to examine this packet, and we
1686 can't. Hence, no choice but to drop. */
1687 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1688 *hotdrop = 1;
1689 return 0;
1692 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1693 ntohs(th->source),
1694 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1695 return 0;
1696 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1697 ntohs(th->dest),
1698 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1699 return 0;
1700 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1701 == tcpinfo->flg_cmp,
1702 IP6T_TCP_INV_FLAGS))
1703 return 0;
1704 if (tcpinfo->option) {
1705 if (th->doff * 4 < sizeof(_tcph)) {
1706 *hotdrop = 1;
1707 return 0;
1709 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1710 th->doff*4 - sizeof(*th),
1711 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1712 hotdrop))
1713 return 0;
1715 return 1;
1718 /* Called when user tries to insert an entry of this type. */
1719 static int
1720 tcp_checkentry(const char *tablename,
1721 const struct ip6t_ip6 *ipv6,
1722 void *matchinfo,
1723 unsigned int matchsize,
1724 unsigned int hook_mask)
1726 const struct ip6t_tcp *tcpinfo = matchinfo;
1728 /* Must specify proto == TCP, and no unknown invflags */
1729 return ipv6->proto == IPPROTO_TCP
1730 && !(ipv6->invflags & IP6T_INV_PROTO)
1731 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1732 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1735 static int
1736 udp_match(const struct sk_buff *skb,
1737 const struct net_device *in,
1738 const struct net_device *out,
1739 const void *matchinfo,
1740 int offset,
1741 unsigned int protoff,
1742 int *hotdrop)
1744 struct udphdr _udph, *uh;
1745 const struct ip6t_udp *udpinfo = matchinfo;
1747 /* Must not be a fragment. */
1748 if (offset)
1749 return 0;
1751 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1752 if (uh == NULL) {
1753 /* We've been asked to examine this packet, and we
1754 can't. Hence, no choice but to drop. */
1755 duprintf("Dropping evil UDP tinygram.\n");
1756 *hotdrop = 1;
1757 return 0;
1760 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1761 ntohs(uh->source),
1762 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1763 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1764 ntohs(uh->dest),
1765 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1768 /* Called when user tries to insert an entry of this type. */
1769 static int
1770 udp_checkentry(const char *tablename,
1771 const struct ip6t_ip6 *ipv6,
1772 void *matchinfo,
1773 unsigned int matchinfosize,
1774 unsigned int hook_mask)
1776 const struct ip6t_udp *udpinfo = matchinfo;
1778 /* Must specify proto == UDP, and no unknown invflags */
1779 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1780 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1781 IPPROTO_UDP);
1782 return 0;
1784 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1785 duprintf("ip6t_udp: matchsize %u != %u\n",
1786 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1787 return 0;
1789 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1790 duprintf("ip6t_udp: unknown flags %X\n",
1791 udpinfo->invflags);
1792 return 0;
1795 return 1;
1798 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1799 static inline int
1800 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1801 u_int8_t type, u_int8_t code,
1802 int invert)
1804 return (type == test_type && code >= min_code && code <= max_code)
1805 ^ invert;
1808 static int
1809 icmp6_match(const struct sk_buff *skb,
1810 const struct net_device *in,
1811 const struct net_device *out,
1812 const void *matchinfo,
1813 int offset,
1814 unsigned int protoff,
1815 int *hotdrop)
1817 struct icmp6hdr _icmp, *ic;
1818 const struct ip6t_icmp *icmpinfo = matchinfo;
1820 /* Must not be a fragment. */
1821 if (offset)
1822 return 0;
1824 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1825 if (ic == NULL) {
1826 /* We've been asked to examine this packet, and we
1827 can't. Hence, no choice but to drop. */
1828 duprintf("Dropping evil ICMP tinygram.\n");
1829 *hotdrop = 1;
1830 return 0;
1833 return icmp6_type_code_match(icmpinfo->type,
1834 icmpinfo->code[0],
1835 icmpinfo->code[1],
1836 ic->icmp6_type, ic->icmp6_code,
1837 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1840 /* Called when user tries to insert an entry of this type. */
1841 static int
1842 icmp6_checkentry(const char *tablename,
1843 const struct ip6t_ip6 *ipv6,
1844 void *matchinfo,
1845 unsigned int matchsize,
1846 unsigned int hook_mask)
1848 const struct ip6t_icmp *icmpinfo = matchinfo;
1850 /* Must specify proto == ICMP, and no unknown invflags */
1851 return ipv6->proto == IPPROTO_ICMPV6
1852 && !(ipv6->invflags & IP6T_INV_PROTO)
1853 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1854 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1857 /* The built-in targets: standard (NULL) and error. */
1858 static struct ip6t_target ip6t_standard_target = {
1859 .name = IP6T_STANDARD_TARGET,
1862 static struct ip6t_target ip6t_error_target = {
1863 .name = IP6T_ERROR_TARGET,
1864 .target = ip6t_error,
1867 static struct nf_sockopt_ops ip6t_sockopts = {
1868 .pf = PF_INET6,
1869 .set_optmin = IP6T_BASE_CTL,
1870 .set_optmax = IP6T_SO_SET_MAX+1,
1871 .set = do_ip6t_set_ctl,
1872 .get_optmin = IP6T_BASE_CTL,
1873 .get_optmax = IP6T_SO_GET_MAX+1,
1874 .get = do_ip6t_get_ctl,
1877 static struct ip6t_match tcp_matchstruct = {
1878 .name = "tcp",
1879 .match = &tcp_match,
1880 .checkentry = &tcp_checkentry,
1883 static struct ip6t_match udp_matchstruct = {
1884 .name = "udp",
1885 .match = &udp_match,
1886 .checkentry = &udp_checkentry,
1889 static struct ip6t_match icmp6_matchstruct = {
1890 .name = "icmp6",
1891 .match = &icmp6_match,
1892 .checkentry = &icmp6_checkentry,
1895 #ifdef CONFIG_PROC_FS
1896 static inline int print_name(const char *i,
1897 off_t start_offset, char *buffer, int length,
1898 off_t *pos, unsigned int *count)
1900 if ((*count)++ >= start_offset) {
1901 unsigned int namelen;
1903 namelen = sprintf(buffer + *pos, "%s\n",
1904 i + sizeof(struct list_head));
1905 if (*pos + namelen > length) {
1906 /* Stop iterating */
1907 return 1;
1909 *pos += namelen;
1911 return 0;
1914 static inline int print_target(const struct ip6t_target *t,
1915 off_t start_offset, char *buffer, int length,
1916 off_t *pos, unsigned int *count)
1918 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1919 return 0;
1920 return print_name((char *)t, start_offset, buffer, length, pos, count);
1923 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1925 off_t pos = 0;
1926 unsigned int count = 0;
1928 if (down_interruptible(&ip6t_mutex) != 0)
1929 return 0;
1931 LIST_FIND(&ip6t_tables, print_name, char *,
1932 offset, buffer, length, &pos, &count);
1934 up(&ip6t_mutex);
1936 /* `start' hack - see fs/proc/generic.c line ~105 */
1937 *start=(char *)((unsigned long)count-offset);
1938 return pos;
1941 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1943 off_t pos = 0;
1944 unsigned int count = 0;
1946 if (down_interruptible(&ip6t_mutex) != 0)
1947 return 0;
1949 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1950 offset, buffer, length, &pos, &count);
1952 up(&ip6t_mutex);
1954 *start = (char *)((unsigned long)count - offset);
1955 return pos;
1958 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1960 off_t pos = 0;
1961 unsigned int count = 0;
1963 if (down_interruptible(&ip6t_mutex) != 0)
1964 return 0;
1966 LIST_FIND(&ip6t_match, print_name, char *,
1967 offset, buffer, length, &pos, &count);
1969 up(&ip6t_mutex);
1971 *start = (char *)((unsigned long)count - offset);
1972 return pos;
1975 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1976 { { "ip6_tables_names", ip6t_get_tables },
1977 { "ip6_tables_targets", ip6t_get_targets },
1978 { "ip6_tables_matches", ip6t_get_matches },
1979 { NULL, NULL} };
1980 #endif /*CONFIG_PROC_FS*/
1982 static int __init init(void)
1984 int ret;
1986 /* Noone else will be downing sem now, so we won't sleep */
1987 down(&ip6t_mutex);
1988 list_append(&ip6t_target, &ip6t_standard_target);
1989 list_append(&ip6t_target, &ip6t_error_target);
1990 list_append(&ip6t_match, &tcp_matchstruct);
1991 list_append(&ip6t_match, &udp_matchstruct);
1992 list_append(&ip6t_match, &icmp6_matchstruct);
1993 up(&ip6t_mutex);
1995 /* Register setsockopt */
1996 ret = nf_register_sockopt(&ip6t_sockopts);
1997 if (ret < 0) {
1998 duprintf("Unable to register sockopts.\n");
1999 return ret;
2002 #ifdef CONFIG_PROC_FS
2004 struct proc_dir_entry *proc;
2005 int i;
2007 for (i = 0; ip6t_proc_entry[i].name; i++) {
2008 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
2009 ip6t_proc_entry[i].get_info);
2010 if (!proc) {
2011 while (--i >= 0)
2012 proc_net_remove(ip6t_proc_entry[i].name);
2013 nf_unregister_sockopt(&ip6t_sockopts);
2014 return -ENOMEM;
2016 proc->owner = THIS_MODULE;
2019 #endif
2021 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2022 return 0;
2025 static void __exit fini(void)
2027 nf_unregister_sockopt(&ip6t_sockopts);
2028 #ifdef CONFIG_PROC_FS
2030 int i;
2031 for (i = 0; ip6t_proc_entry[i].name; i++)
2032 proc_net_remove(ip6t_proc_entry[i].name);
2034 #endif
2038 * find specified header up to transport protocol header.
2039 * If found target header, the offset to the header is set to *offset
2040 * and return 0. otherwise, return -1.
2042 * Notes: - non-1st Fragment Header isn't skipped.
2043 * - ESP header isn't skipped.
2044 * - The target header may be trancated.
2046 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2048 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2049 u8 nexthdr = skb->nh.ipv6h->nexthdr;
2050 unsigned int len = skb->len - start;
2052 while (nexthdr != target) {
2053 struct ipv6_opt_hdr _hdr, *hp;
2054 unsigned int hdrlen;
2056 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
2057 return -1;
2058 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2059 if (hp == NULL)
2060 return -1;
2061 if (nexthdr == NEXTHDR_FRAGMENT) {
2062 unsigned short _frag_off, *fp;
2063 fp = skb_header_pointer(skb,
2064 start+offsetof(struct frag_hdr,
2065 frag_off),
2066 sizeof(_frag_off),
2067 &_frag_off);
2068 if (fp == NULL)
2069 return -1;
2071 if (ntohs(*fp) & ~0x7)
2072 return -1;
2073 hdrlen = 8;
2074 } else if (nexthdr == NEXTHDR_AUTH)
2075 hdrlen = (hp->hdrlen + 2) << 2;
2076 else
2077 hdrlen = ipv6_optlen(hp);
2079 nexthdr = hp->nexthdr;
2080 len -= hdrlen;
2081 start += hdrlen;
2084 *offset = start;
2085 return 0;
2088 EXPORT_SYMBOL(ip6t_register_table);
2089 EXPORT_SYMBOL(ip6t_unregister_table);
2090 EXPORT_SYMBOL(ip6t_do_table);
2091 EXPORT_SYMBOL(ip6t_register_match);
2092 EXPORT_SYMBOL(ip6t_unregister_match);
2093 EXPORT_SYMBOL(ip6t_register_target);
2094 EXPORT_SYMBOL(ip6t_unregister_target);
2095 EXPORT_SYMBOL(ip6t_ext_hdr);
2096 EXPORT_SYMBOL(ipv6_find_hdr);
2098 module_init(init);
2099 module_exit(fini);