Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-block.git] / net / ipv6 / netfilter / ip6_tables.c
CommitLineData
1da177e4
LT
1/*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
6 *
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.
10 *
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
16 */
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>
31
32#include <linux/netfilter_ipv6/ip6_tables.h>
33
34MODULE_LICENSE("GPL");
35MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36MODULE_DESCRIPTION("IPv6 packet filter");
37
38#define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
39#define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
40
41/*#define DEBUG_IP_FIREWALL*/
42/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
43/*#define DEBUG_IP_FIREWALL_USER*/
44
45#ifdef DEBUG_IP_FIREWALL
46#define dprintf(format, args...) printk(format , ## args)
47#else
48#define dprintf(format, args...)
49#endif
50
51#ifdef DEBUG_IP_FIREWALL_USER
52#define duprintf(format, args...) printk(format , ## args)
53#else
54#define duprintf(format, args...)
55#endif
56
57#ifdef CONFIG_NETFILTER_DEBUG
58#define IP_NF_ASSERT(x) \
59do { \
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))
68
69static DECLARE_MUTEX(ip6t_mutex);
70
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)
1da177e4
LT
74#include <linux/netfilter_ipv4/listhelp.h>
75
76#if 0
77/* All the better to debug you with... */
78#define static
79#define inline
80#endif
81
82/* Locking is simple: we assume at worst case there will be one packet
83 in user context and one from bottom halves (or soft irq if Alexey's
84 softnet patch was applied).
85
86 We keep a set of rules for each CPU, so we can avoid write-locking
87 them; doing a readlock_bh() stops packets coming through if we're
88 in user context.
89
90 To be cache friendly on SMP, we arrange them like so:
91 [ n-entries ]
92 ... cache-align padding ...
93 [ n-entries ]
94
95 Hence the start of any table is given by get_table() below. */
96
97/* The table itself */
98struct ip6t_table_info
99{
100 /* Size per table */
101 unsigned int size;
102 /* Number of entries: FIXME. --RR */
103 unsigned int number;
104 /* Initial number of entries. Needed for module usage count */
105 unsigned int initial_entries;
106
107 /* Entry points and underflows */
108 unsigned int hook_entry[NF_IP6_NUMHOOKS];
109 unsigned int underflow[NF_IP6_NUMHOOKS];
110
111 /* ip6t_entry tables: one per CPU */
112 char entries[0] ____cacheline_aligned;
113};
114
115static LIST_HEAD(ip6t_target);
116static LIST_HEAD(ip6t_match);
117static LIST_HEAD(ip6t_tables);
118#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
119
120#ifdef CONFIG_SMP
121#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
122#else
123#define TABLE_OFFSET(t,p) 0
124#endif
125
126#if 0
127#define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
128#define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
129#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
130#endif
131
132static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
133 struct in6_addr addr2)
134{
135 int i;
136 for( i = 0; i < 16; i++){
137 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
138 (addr2.s6_addr[i] & mask.s6_addr[i]))
139 return 1;
140 }
141 return 0;
142}
143
144/* Check for an extension */
145int
146ip6t_ext_hdr(u8 nexthdr)
147{
148 return ( (nexthdr == IPPROTO_HOPOPTS) ||
149 (nexthdr == IPPROTO_ROUTING) ||
150 (nexthdr == IPPROTO_FRAGMENT) ||
151 (nexthdr == IPPROTO_ESP) ||
152 (nexthdr == IPPROTO_AH) ||
153 (nexthdr == IPPROTO_NONE) ||
154 (nexthdr == IPPROTO_DSTOPTS) );
155}
156
157/* Returns whether matches rule or not. */
158static inline int
159ip6_packet_match(const struct sk_buff *skb,
160 const char *indev,
161 const char *outdev,
162 const struct ip6t_ip6 *ip6info,
163 unsigned int *protoff,
164 int *fragoff)
165{
166 size_t i;
167 unsigned long ret;
168 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
169
170#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
171
172 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
173 IP6T_INV_SRCIP)
174 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
175 IP6T_INV_DSTIP)) {
176 dprintf("Source or dest mismatch.\n");
177/*
178 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
179 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
180 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
181 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
182 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
183 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
184 return 0;
185 }
186
187 /* Look for ifname matches; this should unroll nicely. */
188 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
189 ret |= (((const unsigned long *)indev)[i]
190 ^ ((const unsigned long *)ip6info->iniface)[i])
191 & ((const unsigned long *)ip6info->iniface_mask)[i];
192 }
193
194 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
195 dprintf("VIA in mismatch (%s vs %s).%s\n",
196 indev, ip6info->iniface,
197 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
198 return 0;
199 }
200
201 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
202 ret |= (((const unsigned long *)outdev)[i]
203 ^ ((const unsigned long *)ip6info->outiface)[i])
204 & ((const unsigned long *)ip6info->outiface_mask)[i];
205 }
206
207 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
208 dprintf("VIA out mismatch (%s vs %s).%s\n",
209 outdev, ip6info->outiface,
210 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
211 return 0;
212 }
213
214/* ... might want to do something with class and flowlabel here ... */
215
216 /* look for the desired protocol header */
217 if((ip6info->flags & IP6T_F_PROTO)) {
218 u_int8_t currenthdr = ipv6->nexthdr;
219 struct ipv6_opt_hdr _hdr, *hp;
220 u_int16_t ptr; /* Header offset in skb */
221 u_int16_t hdrlen; /* Header */
222 u_int16_t _fragoff = 0, *fp = NULL;
223
224 ptr = IPV6_HDR_LEN;
225
226 while (ip6t_ext_hdr(currenthdr)) {
227 /* Is there enough space for the next ext header? */
228 if (skb->len - ptr < IPV6_OPTHDR_LEN)
229 return 0;
230
231 /* NONE or ESP: there isn't protocol part */
232 /* If we want to count these packets in '-p all',
233 * we will change the return 0 to 1*/
234 if ((currenthdr == IPPROTO_NONE) ||
235 (currenthdr == IPPROTO_ESP))
236 break;
237
238 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
239 BUG_ON(hp == NULL);
240
241 /* Size calculation */
242 if (currenthdr == IPPROTO_FRAGMENT) {
243 fp = skb_header_pointer(skb,
244 ptr+offsetof(struct frag_hdr,
245 frag_off),
246 sizeof(_fragoff),
247 &_fragoff);
248 if (fp == NULL)
249 return 0;
250
251 _fragoff = ntohs(*fp) & ~0x7;
252 hdrlen = 8;
253 } else if (currenthdr == IPPROTO_AH)
254 hdrlen = (hp->hdrlen+2)<<2;
255 else
256 hdrlen = ipv6_optlen(hp);
257
258 currenthdr = hp->nexthdr;
259 ptr += hdrlen;
260 /* ptr is too large */
261 if ( ptr > skb->len )
262 return 0;
263 if (_fragoff) {
264 if (ip6t_ext_hdr(currenthdr))
265 return 0;
266 break;
267 }
268 }
269
270 *protoff = ptr;
271 *fragoff = _fragoff;
272
273 /* currenthdr contains the protocol header */
274
275 dprintf("Packet protocol %hi ?= %s%hi.\n",
276 currenthdr,
277 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
278 ip6info->proto);
279
280 if (ip6info->proto == currenthdr) {
281 if(ip6info->invflags & IP6T_INV_PROTO) {
282 return 0;
283 }
284 return 1;
285 }
286
287 /* We need match for the '-p all', too! */
288 if ((ip6info->proto != 0) &&
289 !(ip6info->invflags & IP6T_INV_PROTO))
290 return 0;
291 }
292 return 1;
293}
294
295/* should be ip6 safe */
296static inline int
297ip6_checkentry(const struct ip6t_ip6 *ipv6)
298{
299 if (ipv6->flags & ~IP6T_F_MASK) {
300 duprintf("Unknown flag bits set: %08X\n",
301 ipv6->flags & ~IP6T_F_MASK);
302 return 0;
303 }
304 if (ipv6->invflags & ~IP6T_INV_MASK) {
305 duprintf("Unknown invflag bits set: %08X\n",
306 ipv6->invflags & ~IP6T_INV_MASK);
307 return 0;
308 }
309 return 1;
310}
311
312static unsigned int
313ip6t_error(struct sk_buff **pskb,
314 const struct net_device *in,
315 const struct net_device *out,
316 unsigned int hooknum,
317 const void *targinfo,
318 void *userinfo)
319{
320 if (net_ratelimit())
321 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
322
323 return NF_DROP;
324}
325
326static inline
327int do_match(struct ip6t_entry_match *m,
328 const struct sk_buff *skb,
329 const struct net_device *in,
330 const struct net_device *out,
331 int offset,
332 unsigned int protoff,
333 int *hotdrop)
334{
335 /* Stop iteration if it doesn't match */
336 if (!m->u.kernel.match->match(skb, in, out, m->data,
337 offset, protoff, hotdrop))
338 return 1;
339 else
340 return 0;
341}
342
343static inline struct ip6t_entry *
344get_entry(void *base, unsigned int offset)
345{
346 return (struct ip6t_entry *)(base + offset);
347}
348
349/* Returns one of the generic firewall policies, like NF_ACCEPT. */
350unsigned int
351ip6t_do_table(struct sk_buff **pskb,
352 unsigned int hook,
353 const struct net_device *in,
354 const struct net_device *out,
355 struct ip6t_table *table,
356 void *userdata)
357{
358 static const char nulldevname[IFNAMSIZ];
359 int offset = 0;
360 unsigned int protoff = 0;
361 int hotdrop = 0;
362 /* Initializing verdict to NF_DROP keeps gcc happy. */
363 unsigned int verdict = NF_DROP;
364 const char *indev, *outdev;
365 void *table_base;
366 struct ip6t_entry *e, *back;
367
368 /* Initialization */
369 indev = in ? in->name : nulldevname;
370 outdev = out ? out->name : nulldevname;
371
372 /* We handle fragments by dealing with the first fragment as
373 * if it was a normal packet. All other fragments are treated
374 * normally, except that they will NEVER match rules that ask
375 * things we don't know, ie. tcp syn flag or ports). If the
376 * rule is also a fragment-specific rule, non-fragments won't
377 * match it. */
378
379 read_lock_bh(&table->lock);
380 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
381 table_base = (void *)table->private->entries
382 + TABLE_OFFSET(table->private, smp_processor_id());
383 e = get_entry(table_base, table->private->hook_entry[hook]);
384
385#ifdef CONFIG_NETFILTER_DEBUG
386 /* Check noone else using our table */
387 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
388 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
389 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
390 smp_processor_id(),
391 table->name,
392 &((struct ip6t_entry *)table_base)->comefrom,
393 ((struct ip6t_entry *)table_base)->comefrom);
394 }
395 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
396#endif
397
398 /* For return from builtin chain */
399 back = get_entry(table_base, table->private->underflow[hook]);
400
401 do {
402 IP_NF_ASSERT(e);
403 IP_NF_ASSERT(back);
1da177e4
LT
404 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
405 &protoff, &offset)) {
406 struct ip6t_entry_target *t;
407
408 if (IP6T_MATCH_ITERATE(e, do_match,
409 *pskb, in, out,
410 offset, protoff, &hotdrop) != 0)
411 goto no_match;
412
413 ADD_COUNTER(e->counters,
414 ntohs((*pskb)->nh.ipv6h->payload_len)
415 + IPV6_HDR_LEN,
416 1);
417
418 t = ip6t_get_target(e);
419 IP_NF_ASSERT(t->u.kernel.target);
420 /* Standard target? */
421 if (!t->u.kernel.target->target) {
422 int v;
423
424 v = ((struct ip6t_standard_target *)t)->verdict;
425 if (v < 0) {
426 /* Pop from stack? */
427 if (v != IP6T_RETURN) {
428 verdict = (unsigned)(-v) - 1;
429 break;
430 }
431 e = back;
432 back = get_entry(table_base,
433 back->comefrom);
434 continue;
435 }
05465343
PM
436 if (table_base + v != (void *)e + e->next_offset
437 && !(e->ipv6.flags & IP6T_F_GOTO)) {
1da177e4
LT
438 /* Save old back ptr in next entry */
439 struct ip6t_entry *next
440 = (void *)e + e->next_offset;
441 next->comefrom
442 = (void *)back - table_base;
443 /* set back pointer to next entry */
444 back = next;
445 }
446
447 e = get_entry(table_base, v);
448 } else {
449 /* Targets which reenter must return
450 abs. verdicts */
451#ifdef CONFIG_NETFILTER_DEBUG
452 ((struct ip6t_entry *)table_base)->comefrom
453 = 0xeeeeeeec;
454#endif
455 verdict = t->u.kernel.target->target(pskb,
456 in, out,
457 hook,
458 t->data,
459 userdata);
460
461#ifdef CONFIG_NETFILTER_DEBUG
462 if (((struct ip6t_entry *)table_base)->comefrom
463 != 0xeeeeeeec
464 && verdict == IP6T_CONTINUE) {
465 printk("Target %s reentered!\n",
466 t->u.kernel.target->name);
467 verdict = NF_DROP;
468 }
469 ((struct ip6t_entry *)table_base)->comefrom
470 = 0x57acc001;
471#endif
472 if (verdict == IP6T_CONTINUE)
473 e = (void *)e + e->next_offset;
474 else
475 /* Verdict */
476 break;
477 }
478 } else {
479
480 no_match:
481 e = (void *)e + e->next_offset;
482 }
483 } while (!hotdrop);
484
485#ifdef CONFIG_NETFILTER_DEBUG
486 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
487#endif
488 read_unlock_bh(&table->lock);
489
490#ifdef DEBUG_ALLOW_ALL
491 return NF_ACCEPT;
492#else
493 if (hotdrop)
494 return NF_DROP;
495 else return verdict;
496#endif
497}
498
499/* If it succeeds, returns element and locks mutex */
500static inline void *
501find_inlist_lock_noload(struct list_head *head,
502 const char *name,
503 int *error,
504 struct semaphore *mutex)
505{
506 void *ret;
507
508#if 1
509 duprintf("find_inlist: searching for `%s' in %s.\n",
510 name, head == &ip6t_target ? "ip6t_target"
511 : head == &ip6t_match ? "ip6t_match"
512 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
513#endif
514
515 *error = down_interruptible(mutex);
516 if (*error != 0)
517 return NULL;
518
519 ret = list_named_find(head, name);
520 if (!ret) {
521 *error = -ENOENT;
522 up(mutex);
523 }
524 return ret;
525}
526
527#ifndef CONFIG_KMOD
528#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
529#else
530static void *
531find_inlist_lock(struct list_head *head,
532 const char *name,
533 const char *prefix,
534 int *error,
535 struct semaphore *mutex)
536{
537 void *ret;
538
539 ret = find_inlist_lock_noload(head, name, error, mutex);
540 if (!ret) {
541 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
542 request_module("%s%s", prefix, name);
543 ret = find_inlist_lock_noload(head, name, error, mutex);
544 }
545
546 return ret;
547}
548#endif
549
550static inline struct ip6t_table *
551ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
552{
553 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
554}
555
556static inline struct ip6t_match *
557find_match_lock(const char *name, int *error, struct semaphore *mutex)
558{
559 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
560}
561
562static struct ip6t_target *
563ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
564{
565 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
566}
567
568/* All zeroes == unconditional rule. */
569static inline int
570unconditional(const struct ip6t_ip6 *ipv6)
571{
572 unsigned int i;
573
574 for (i = 0; i < sizeof(*ipv6); i++)
575 if (((char *)ipv6)[i])
576 break;
577
578 return (i == sizeof(*ipv6));
579}
580
581/* Figures out from what hook each rule can be called: returns 0 if
582 there are loops. Puts hook bitmask in comefrom. */
583static int
584mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
585{
586 unsigned int hook;
587
588 /* No recursion; use packet counter to save back ptrs (reset
589 to 0 as we leave), and comefrom to save source hook bitmask */
590 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
591 unsigned int pos = newinfo->hook_entry[hook];
592 struct ip6t_entry *e
593 = (struct ip6t_entry *)(newinfo->entries + pos);
594
595 if (!(valid_hooks & (1 << hook)))
596 continue;
597
598 /* Set initial back pointer. */
599 e->counters.pcnt = pos;
600
601 for (;;) {
602 struct ip6t_standard_target *t
603 = (void *)ip6t_get_target(e);
604
605 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
606 printk("iptables: loop hook %u pos %u %08X.\n",
607 hook, pos, e->comefrom);
608 return 0;
609 }
610 e->comefrom
611 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
612
613 /* Unconditional return/END. */
614 if (e->target_offset == sizeof(struct ip6t_entry)
615 && (strcmp(t->target.u.user.name,
616 IP6T_STANDARD_TARGET) == 0)
617 && t->verdict < 0
618 && unconditional(&e->ipv6)) {
619 unsigned int oldpos, size;
620
621 /* Return: backtrack through the last
622 big jump. */
623 do {
624 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
625#ifdef DEBUG_IP_FIREWALL_USER
626 if (e->comefrom
627 & (1 << NF_IP6_NUMHOOKS)) {
628 duprintf("Back unset "
629 "on hook %u "
630 "rule %u\n",
631 hook, pos);
632 }
633#endif
634 oldpos = pos;
635 pos = e->counters.pcnt;
636 e->counters.pcnt = 0;
637
638 /* We're at the start. */
639 if (pos == oldpos)
640 goto next;
641
642 e = (struct ip6t_entry *)
643 (newinfo->entries + pos);
644 } while (oldpos == pos + e->next_offset);
645
646 /* Move along one */
647 size = e->next_offset;
648 e = (struct ip6t_entry *)
649 (newinfo->entries + pos + size);
650 e->counters.pcnt = pos;
651 pos += size;
652 } else {
653 int newpos = t->verdict;
654
655 if (strcmp(t->target.u.user.name,
656 IP6T_STANDARD_TARGET) == 0
657 && newpos >= 0) {
658 /* This a jump; chase it. */
659 duprintf("Jump rule %u -> %u\n",
660 pos, newpos);
661 } else {
662 /* ... this is a fallthru */
663 newpos = pos + e->next_offset;
664 }
665 e = (struct ip6t_entry *)
666 (newinfo->entries + newpos);
667 e->counters.pcnt = pos;
668 pos = newpos;
669 }
670 }
671 next:
672 duprintf("Finished chain %u\n", hook);
673 }
674 return 1;
675}
676
677static inline int
678cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
679{
680 if (i && (*i)-- == 0)
681 return 1;
682
683 if (m->u.kernel.match->destroy)
684 m->u.kernel.match->destroy(m->data,
685 m->u.match_size - sizeof(*m));
686 module_put(m->u.kernel.match->me);
687 return 0;
688}
689
690static inline int
691standard_check(const struct ip6t_entry_target *t,
692 unsigned int max_offset)
693{
694 struct ip6t_standard_target *targ = (void *)t;
695
696 /* Check standard info. */
697 if (t->u.target_size
698 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
699 duprintf("standard_check: target size %u != %u\n",
700 t->u.target_size,
701 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
702 return 0;
703 }
704
705 if (targ->verdict >= 0
706 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
707 duprintf("ip6t_standard_check: bad verdict (%i)\n",
708 targ->verdict);
709 return 0;
710 }
711
712 if (targ->verdict < -NF_MAX_VERDICT - 1) {
713 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
714 targ->verdict);
715 return 0;
716 }
717 return 1;
718}
719
720static inline int
721check_match(struct ip6t_entry_match *m,
722 const char *name,
723 const struct ip6t_ip6 *ipv6,
724 unsigned int hookmask,
725 unsigned int *i)
726{
727 int ret;
728 struct ip6t_match *match;
729
730 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
731 if (!match) {
732 // duprintf("check_match: `%s' not found\n", m->u.name);
733 return ret;
734 }
735 if (!try_module_get(match->me)) {
736 up(&ip6t_mutex);
737 return -ENOENT;
738 }
739 m->u.kernel.match = match;
740 up(&ip6t_mutex);
741
742 if (m->u.kernel.match->checkentry
743 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
744 m->u.match_size - sizeof(*m),
745 hookmask)) {
746 module_put(m->u.kernel.match->me);
747 duprintf("ip_tables: check failed for `%s'.\n",
748 m->u.kernel.match->name);
749 return -EINVAL;
750 }
751
752 (*i)++;
753 return 0;
754}
755
756static struct ip6t_target ip6t_standard_target;
757
758static inline int
759check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
760 unsigned int *i)
761{
762 struct ip6t_entry_target *t;
763 struct ip6t_target *target;
764 int ret;
765 unsigned int j;
766
767 if (!ip6_checkentry(&e->ipv6)) {
768 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
769 return -EINVAL;
770 }
771
772 j = 0;
773 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
774 if (ret != 0)
775 goto cleanup_matches;
776
777 t = ip6t_get_target(e);
778 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
779 if (!target) {
780 duprintf("check_entry: `%s' not found\n", t->u.user.name);
781 goto cleanup_matches;
782 }
783 if (!try_module_get(target->me)) {
784 up(&ip6t_mutex);
785 ret = -ENOENT;
786 goto cleanup_matches;
787 }
788 t->u.kernel.target = target;
789 up(&ip6t_mutex);
790 if (!t->u.kernel.target) {
791 ret = -EBUSY;
792 goto cleanup_matches;
793 }
794 if (t->u.kernel.target == &ip6t_standard_target) {
795 if (!standard_check(t, size)) {
796 ret = -EINVAL;
797 goto cleanup_matches;
798 }
799 } else if (t->u.kernel.target->checkentry
800 && !t->u.kernel.target->checkentry(name, e, t->data,
801 t->u.target_size
802 - sizeof(*t),
803 e->comefrom)) {
804 module_put(t->u.kernel.target->me);
805 duprintf("ip_tables: check failed for `%s'.\n",
806 t->u.kernel.target->name);
807 ret = -EINVAL;
808 goto cleanup_matches;
809 }
810
811 (*i)++;
812 return 0;
813
814 cleanup_matches:
815 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
816 return ret;
817}
818
819static inline int
820check_entry_size_and_hooks(struct ip6t_entry *e,
821 struct ip6t_table_info *newinfo,
822 unsigned char *base,
823 unsigned char *limit,
824 const unsigned int *hook_entries,
825 const unsigned int *underflows,
826 unsigned int *i)
827{
828 unsigned int h;
829
830 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
831 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
832 duprintf("Bad offset %p\n", e);
833 return -EINVAL;
834 }
835
836 if (e->next_offset
837 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
838 duprintf("checking: element %p size %u\n",
839 e, e->next_offset);
840 return -EINVAL;
841 }
842
843 /* Check hooks & underflows */
844 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
845 if ((unsigned char *)e - base == hook_entries[h])
846 newinfo->hook_entry[h] = hook_entries[h];
847 if ((unsigned char *)e - base == underflows[h])
848 newinfo->underflow[h] = underflows[h];
849 }
850
851 /* FIXME: underflows must be unconditional, standard verdicts
852 < 0 (not IP6T_RETURN). --RR */
853
854 /* Clear counters and comefrom */
855 e->counters = ((struct ip6t_counters) { 0, 0 });
856 e->comefrom = 0;
857
858 (*i)++;
859 return 0;
860}
861
862static inline int
863cleanup_entry(struct ip6t_entry *e, unsigned int *i)
864{
865 struct ip6t_entry_target *t;
866
867 if (i && (*i)-- == 0)
868 return 1;
869
870 /* Cleanup all matches */
871 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
872 t = ip6t_get_target(e);
873 if (t->u.kernel.target->destroy)
874 t->u.kernel.target->destroy(t->data,
875 t->u.target_size - sizeof(*t));
876 module_put(t->u.kernel.target->me);
877 return 0;
878}
879
880/* Checks and translates the user-supplied table segment (held in
881 newinfo) */
882static int
883translate_table(const char *name,
884 unsigned int valid_hooks,
885 struct ip6t_table_info *newinfo,
886 unsigned int size,
887 unsigned int number,
888 const unsigned int *hook_entries,
889 const unsigned int *underflows)
890{
891 unsigned int i;
892 int ret;
893
894 newinfo->size = size;
895 newinfo->number = number;
896
897 /* Init all hooks to impossible value. */
898 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
899 newinfo->hook_entry[i] = 0xFFFFFFFF;
900 newinfo->underflow[i] = 0xFFFFFFFF;
901 }
902
903 duprintf("translate_table: size %u\n", newinfo->size);
904 i = 0;
905 /* Walk through entries, checking offsets. */
906 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
907 check_entry_size_and_hooks,
908 newinfo,
909 newinfo->entries,
910 newinfo->entries + size,
911 hook_entries, underflows, &i);
912 if (ret != 0)
913 return ret;
914
915 if (i != number) {
916 duprintf("translate_table: %u not %u entries\n",
917 i, number);
918 return -EINVAL;
919 }
920
921 /* Check hooks all assigned */
922 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
923 /* Only hooks which are valid */
924 if (!(valid_hooks & (1 << i)))
925 continue;
926 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
927 duprintf("Invalid hook entry %u %u\n",
928 i, hook_entries[i]);
929 return -EINVAL;
930 }
931 if (newinfo->underflow[i] == 0xFFFFFFFF) {
932 duprintf("Invalid underflow %u %u\n",
933 i, underflows[i]);
934 return -EINVAL;
935 }
936 }
937
938 if (!mark_source_chains(newinfo, valid_hooks))
939 return -ELOOP;
940
941 /* Finally, each sanity check must pass */
942 i = 0;
943 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
944 check_entry, name, size, &i);
945
946 if (ret != 0) {
947 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
948 cleanup_entry, &i);
949 return ret;
950 }
951
952 /* And one copy for every other CPU */
953 for (i = 1; i < num_possible_cpus(); i++) {
954 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
955 newinfo->entries,
956 SMP_ALIGN(newinfo->size));
957 }
958
959 return ret;
960}
961
962static struct ip6t_table_info *
963replace_table(struct ip6t_table *table,
964 unsigned int num_counters,
965 struct ip6t_table_info *newinfo,
966 int *error)
967{
968 struct ip6t_table_info *oldinfo;
969
970#ifdef CONFIG_NETFILTER_DEBUG
971 {
972 struct ip6t_entry *table_base;
973 unsigned int i;
974
975 for (i = 0; i < num_possible_cpus(); i++) {
976 table_base =
977 (void *)newinfo->entries
978 + TABLE_OFFSET(newinfo, i);
979
980 table_base->comefrom = 0xdead57ac;
981 }
982 }
983#endif
984
985 /* Do the substitution. */
986 write_lock_bh(&table->lock);
987 /* Check inside lock: is the old number correct? */
988 if (num_counters != table->private->number) {
989 duprintf("num_counters != table->private->number (%u/%u)\n",
990 num_counters, table->private->number);
991 write_unlock_bh(&table->lock);
992 *error = -EAGAIN;
993 return NULL;
994 }
995 oldinfo = table->private;
996 table->private = newinfo;
997 newinfo->initial_entries = oldinfo->initial_entries;
998 write_unlock_bh(&table->lock);
999
1000 return oldinfo;
1001}
1002
1003/* Gets counters. */
1004static inline int
1005add_entry_to_counter(const struct ip6t_entry *e,
1006 struct ip6t_counters total[],
1007 unsigned int *i)
1008{
1009 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1010
1011 (*i)++;
1012 return 0;
1013}
1014
1015static void
1016get_counters(const struct ip6t_table_info *t,
1017 struct ip6t_counters counters[])
1018{
1019 unsigned int cpu;
1020 unsigned int i;
1021
1022 for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
1023 i = 0;
1024 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1025 t->size,
1026 add_entry_to_counter,
1027 counters,
1028 &i);
1029 }
1030}
1031
1032static int
1033copy_entries_to_user(unsigned int total_size,
1034 struct ip6t_table *table,
1035 void __user *userptr)
1036{
1037 unsigned int off, num, countersize;
1038 struct ip6t_entry *e;
1039 struct ip6t_counters *counters;
1040 int ret = 0;
1041
1042 /* We need atomic snapshot of counters: rest doesn't change
1043 (other than comefrom, which userspace doesn't care
1044 about). */
1045 countersize = sizeof(struct ip6t_counters) * table->private->number;
1046 counters = vmalloc(countersize);
1047
1048 if (counters == NULL)
1049 return -ENOMEM;
1050
1051 /* First, sum counters... */
1052 memset(counters, 0, countersize);
1053 write_lock_bh(&table->lock);
1054 get_counters(table->private, counters);
1055 write_unlock_bh(&table->lock);
1056
1057 /* ... then copy entire thing from CPU 0... */
1058 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1059 ret = -EFAULT;
1060 goto free_counters;
1061 }
1062
1063 /* FIXME: use iterator macros --RR */
1064 /* ... then go back and fix counters and names */
1065 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1066 unsigned int i;
1067 struct ip6t_entry_match *m;
1068 struct ip6t_entry_target *t;
1069
1070 e = (struct ip6t_entry *)(table->private->entries + off);
1071 if (copy_to_user(userptr + off
1072 + offsetof(struct ip6t_entry, counters),
1073 &counters[num],
1074 sizeof(counters[num])) != 0) {
1075 ret = -EFAULT;
1076 goto free_counters;
1077 }
1078
1079 for (i = sizeof(struct ip6t_entry);
1080 i < e->target_offset;
1081 i += m->u.match_size) {
1082 m = (void *)e + i;
1083
1084 if (copy_to_user(userptr + off + i
1085 + offsetof(struct ip6t_entry_match,
1086 u.user.name),
1087 m->u.kernel.match->name,
1088 strlen(m->u.kernel.match->name)+1)
1089 != 0) {
1090 ret = -EFAULT;
1091 goto free_counters;
1092 }
1093 }
1094
1095 t = ip6t_get_target(e);
1096 if (copy_to_user(userptr + off + e->target_offset
1097 + offsetof(struct ip6t_entry_target,
1098 u.user.name),
1099 t->u.kernel.target->name,
1100 strlen(t->u.kernel.target->name)+1) != 0) {
1101 ret = -EFAULT;
1102 goto free_counters;
1103 }
1104 }
1105
1106 free_counters:
1107 vfree(counters);
1108 return ret;
1109}
1110
1111static int
1112get_entries(const struct ip6t_get_entries *entries,
1113 struct ip6t_get_entries __user *uptr)
1114{
1115 int ret;
1116 struct ip6t_table *t;
1117
1118 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1119 if (t) {
1120 duprintf("t->private->number = %u\n",
1121 t->private->number);
1122 if (entries->size == t->private->size)
1123 ret = copy_entries_to_user(t->private->size,
1124 t, uptr->entrytable);
1125 else {
1126 duprintf("get_entries: I've got %u not %u!\n",
1127 t->private->size,
1128 entries->size);
1129 ret = -EINVAL;
1130 }
1131 up(&ip6t_mutex);
1132 } else
1133 duprintf("get_entries: Can't find %s!\n",
1134 entries->name);
1135
1136 return ret;
1137}
1138
1139static int
1140do_replace(void __user *user, unsigned int len)
1141{
1142 int ret;
1143 struct ip6t_replace tmp;
1144 struct ip6t_table *t;
1145 struct ip6t_table_info *newinfo, *oldinfo;
1146 struct ip6t_counters *counters;
1147
1148 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1149 return -EFAULT;
1150
1151 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1152 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1153 return -ENOMEM;
1154
1155 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1156 + SMP_ALIGN(tmp.size) * num_possible_cpus());
1157 if (!newinfo)
1158 return -ENOMEM;
1159
1160 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1161 tmp.size) != 0) {
1162 ret = -EFAULT;
1163 goto free_newinfo;
1164 }
1165
1166 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1167 if (!counters) {
1168 ret = -ENOMEM;
1169 goto free_newinfo;
1170 }
1171 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1172
1173 ret = translate_table(tmp.name, tmp.valid_hooks,
1174 newinfo, tmp.size, tmp.num_entries,
1175 tmp.hook_entry, tmp.underflow);
1176 if (ret != 0)
1177 goto free_newinfo_counters;
1178
1179 duprintf("ip_tables: Translated table\n");
1180
1181 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1182 if (!t)
1183 goto free_newinfo_counters_untrans;
1184
1185 /* You lied! */
1186 if (tmp.valid_hooks != t->valid_hooks) {
1187 duprintf("Valid hook crap: %08X vs %08X\n",
1188 tmp.valid_hooks, t->valid_hooks);
1189 ret = -EINVAL;
1190 goto free_newinfo_counters_untrans_unlock;
1191 }
1192
1193 /* Get a reference in advance, we're not allowed fail later */
1194 if (!try_module_get(t->me)) {
1195 ret = -EBUSY;
1196 goto free_newinfo_counters_untrans_unlock;
1197 }
1198
1199 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1200 if (!oldinfo)
1201 goto put_module;
1202
1203 /* Update module usage count based on number of rules */
1204 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1205 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1206 if ((oldinfo->number > oldinfo->initial_entries) ||
1207 (newinfo->number <= oldinfo->initial_entries))
1208 module_put(t->me);
1209 if ((oldinfo->number > oldinfo->initial_entries) &&
1210 (newinfo->number <= oldinfo->initial_entries))
1211 module_put(t->me);
1212
1213 /* Get the old counters. */
1214 get_counters(oldinfo, counters);
1215 /* Decrease module usage counts and free resource */
1216 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1217 vfree(oldinfo);
1218 /* Silent error: too late now. */
1219 if (copy_to_user(tmp.counters, counters,
1220 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1221 ret = -EFAULT;
1222 vfree(counters);
1223 up(&ip6t_mutex);
1224 return ret;
1225
1226 put_module:
1227 module_put(t->me);
1228 free_newinfo_counters_untrans_unlock:
1229 up(&ip6t_mutex);
1230 free_newinfo_counters_untrans:
1231 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1232 free_newinfo_counters:
1233 vfree(counters);
1234 free_newinfo:
1235 vfree(newinfo);
1236 return ret;
1237}
1238
1239/* We're lazy, and add to the first CPU; overflow works its fey magic
1240 * and everything is OK. */
1241static inline int
1242add_counter_to_entry(struct ip6t_entry *e,
1243 const struct ip6t_counters addme[],
1244 unsigned int *i)
1245{
1246#if 0
1247 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1248 *i,
1249 (long unsigned int)e->counters.pcnt,
1250 (long unsigned int)e->counters.bcnt,
1251 (long unsigned int)addme[*i].pcnt,
1252 (long unsigned int)addme[*i].bcnt);
1253#endif
1254
1255 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1256
1257 (*i)++;
1258 return 0;
1259}
1260
1261static int
1262do_add_counters(void __user *user, unsigned int len)
1263{
1264 unsigned int i;
1265 struct ip6t_counters_info tmp, *paddc;
1266 struct ip6t_table *t;
1267 int ret;
1268
1269 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1270 return -EFAULT;
1271
1272 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1273 return -EINVAL;
1274
1275 paddc = vmalloc(len);
1276 if (!paddc)
1277 return -ENOMEM;
1278
1279 if (copy_from_user(paddc, user, len) != 0) {
1280 ret = -EFAULT;
1281 goto free;
1282 }
1283
1284 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1285 if (!t)
1286 goto free;
1287
1288 write_lock_bh(&t->lock);
1289 if (t->private->number != paddc->num_counters) {
1290 ret = -EINVAL;
1291 goto unlock_up_free;
1292 }
1293
1294 i = 0;
1295 IP6T_ENTRY_ITERATE(t->private->entries,
1296 t->private->size,
1297 add_counter_to_entry,
1298 paddc->counters,
1299 &i);
1300 unlock_up_free:
1301 write_unlock_bh(&t->lock);
1302 up(&ip6t_mutex);
1303 free:
1304 vfree(paddc);
1305
1306 return ret;
1307}
1308
1309static int
1310do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1311{
1312 int ret;
1313
1314 if (!capable(CAP_NET_ADMIN))
1315 return -EPERM;
1316
1317 switch (cmd) {
1318 case IP6T_SO_SET_REPLACE:
1319 ret = do_replace(user, len);
1320 break;
1321
1322 case IP6T_SO_SET_ADD_COUNTERS:
1323 ret = do_add_counters(user, len);
1324 break;
1325
1326 default:
1327 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1328 ret = -EINVAL;
1329 }
1330
1331 return ret;
1332}
1333
1334static int
1335do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1336{
1337 int ret;
1338
1339 if (!capable(CAP_NET_ADMIN))
1340 return -EPERM;
1341
1342 switch (cmd) {
1343 case IP6T_SO_GET_INFO: {
1344 char name[IP6T_TABLE_MAXNAMELEN];
1345 struct ip6t_table *t;
1346
1347 if (*len != sizeof(struct ip6t_getinfo)) {
1348 duprintf("length %u != %u\n", *len,
1349 sizeof(struct ip6t_getinfo));
1350 ret = -EINVAL;
1351 break;
1352 }
1353
1354 if (copy_from_user(name, user, sizeof(name)) != 0) {
1355 ret = -EFAULT;
1356 break;
1357 }
1358 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1359 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1360 if (t) {
1361 struct ip6t_getinfo info;
1362
1363 info.valid_hooks = t->valid_hooks;
1364 memcpy(info.hook_entry, t->private->hook_entry,
1365 sizeof(info.hook_entry));
1366 memcpy(info.underflow, t->private->underflow,
1367 sizeof(info.underflow));
1368 info.num_entries = t->private->number;
1369 info.size = t->private->size;
1370 memcpy(info.name, name, sizeof(info.name));
1371
1372 if (copy_to_user(user, &info, *len) != 0)
1373 ret = -EFAULT;
1374 else
1375 ret = 0;
1376
1377 up(&ip6t_mutex);
1378 }
1379 }
1380 break;
1381
1382 case IP6T_SO_GET_ENTRIES: {
1383 struct ip6t_get_entries get;
1384
1385 if (*len < sizeof(get)) {
1386 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1387 ret = -EINVAL;
1388 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1389 ret = -EFAULT;
1390 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1391 duprintf("get_entries: %u != %u\n", *len,
1392 sizeof(struct ip6t_get_entries) + get.size);
1393 ret = -EINVAL;
1394 } else
1395 ret = get_entries(&get, user);
1396 break;
1397 }
1398
1399 default:
1400 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1401 ret = -EINVAL;
1402 }
1403
1404 return ret;
1405}
1406
1407/* Registration hooks for targets. */
1408int
1409ip6t_register_target(struct ip6t_target *target)
1410{
1411 int ret;
1412
1413 ret = down_interruptible(&ip6t_mutex);
1414 if (ret != 0)
1415 return ret;
1416
1417 if (!list_named_insert(&ip6t_target, target)) {
1418 duprintf("ip6t_register_target: `%s' already in list!\n",
1419 target->name);
1420 ret = -EINVAL;
1421 }
1422 up(&ip6t_mutex);
1423 return ret;
1424}
1425
1426void
1427ip6t_unregister_target(struct ip6t_target *target)
1428{
1429 down(&ip6t_mutex);
1430 LIST_DELETE(&ip6t_target, target);
1431 up(&ip6t_mutex);
1432}
1433
1434int
1435ip6t_register_match(struct ip6t_match *match)
1436{
1437 int ret;
1438
1439 ret = down_interruptible(&ip6t_mutex);
1440 if (ret != 0)
1441 return ret;
1442
1443 if (!list_named_insert(&ip6t_match, match)) {
1444 duprintf("ip6t_register_match: `%s' already in list!\n",
1445 match->name);
1446 ret = -EINVAL;
1447 }
1448 up(&ip6t_mutex);
1449
1450 return ret;
1451}
1452
1453void
1454ip6t_unregister_match(struct ip6t_match *match)
1455{
1456 down(&ip6t_mutex);
1457 LIST_DELETE(&ip6t_match, match);
1458 up(&ip6t_mutex);
1459}
1460
1461int ip6t_register_table(struct ip6t_table *table,
1462 const struct ip6t_replace *repl)
1463{
1464 int ret;
1465 struct ip6t_table_info *newinfo;
1466 static struct ip6t_table_info bootstrap
1467 = { 0, 0, 0, { 0 }, { 0 }, { } };
1468
1469 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1470 + SMP_ALIGN(repl->size) * num_possible_cpus());
1471 if (!newinfo)
1472 return -ENOMEM;
1473
1474 memcpy(newinfo->entries, repl->entries, repl->size);
1475
1476 ret = translate_table(table->name, table->valid_hooks,
1477 newinfo, repl->size,
1478 repl->num_entries,
1479 repl->hook_entry,
1480 repl->underflow);
1481 if (ret != 0) {
1482 vfree(newinfo);
1483 return ret;
1484 }
1485
1486 ret = down_interruptible(&ip6t_mutex);
1487 if (ret != 0) {
1488 vfree(newinfo);
1489 return ret;
1490 }
1491
1492 /* Don't autoload: we'd eat our tail... */
1493 if (list_named_find(&ip6t_tables, table->name)) {
1494 ret = -EEXIST;
1495 goto free_unlock;
1496 }
1497
1498 /* Simplifies replace_table code. */
1499 table->private = &bootstrap;
1500 if (!replace_table(table, 0, newinfo, &ret))
1501 goto free_unlock;
1502
1503 duprintf("table->private->number = %u\n",
1504 table->private->number);
1505
1506 /* save number of initial entries */
1507 table->private->initial_entries = table->private->number;
1508
1509 rwlock_init(&table->lock);
1510 list_prepend(&ip6t_tables, table);
1511
1512 unlock:
1513 up(&ip6t_mutex);
1514 return ret;
1515
1516 free_unlock:
1517 vfree(newinfo);
1518 goto unlock;
1519}
1520
1521void ip6t_unregister_table(struct ip6t_table *table)
1522{
1523 down(&ip6t_mutex);
1524 LIST_DELETE(&ip6t_tables, table);
1525 up(&ip6t_mutex);
1526
1527 /* Decrease module usage counts and free resources */
1528 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1529 cleanup_entry, NULL);
1530 vfree(table->private);
1531}
1532
1533/* Returns 1 if the port is matched by the range, 0 otherwise */
1534static inline int
1535port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1536{
1537 int ret;
1538
1539 ret = (port >= min && port <= max) ^ invert;
1540 return ret;
1541}
1542
1543static int
1544tcp_find_option(u_int8_t option,
1545 const struct sk_buff *skb,
1546 unsigned int tcpoff,
1547 unsigned int optlen,
1548 int invert,
1549 int *hotdrop)
1550{
1551 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1552 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1553 unsigned int i;
1554
1555 duprintf("tcp_match: finding option\n");
1556 if (!optlen)
1557 return invert;
1558 /* If we don't have the whole header, drop packet. */
1559 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1560 _opt);
1561 if (op == NULL) {
1562 *hotdrop = 1;
1563 return 0;
1564 }
1565
1566 for (i = 0; i < optlen; ) {
1567 if (op[i] == option) return !invert;
1568 if (op[i] < 2) i++;
1569 else i += op[i+1]?:1;
1570 }
1571
1572 return invert;
1573}
1574
1575static int
1576tcp_match(const struct sk_buff *skb,
1577 const struct net_device *in,
1578 const struct net_device *out,
1579 const void *matchinfo,
1580 int offset,
1581 unsigned int protoff,
1582 int *hotdrop)
1583{
1584 struct tcphdr _tcph, *th;
1585 const struct ip6t_tcp *tcpinfo = matchinfo;
1586
1587 if (offset) {
1588 /* To quote Alan:
1589
1590 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1591 causes this. Its a cracker trying to break in by doing a
1592 flag overwrite to pass the direction checks.
1593 */
1594 if (offset == 1) {
1595 duprintf("Dropping evil TCP offset=1 frag.\n");
1596 *hotdrop = 1;
1597 }
1598 /* Must not be a fragment. */
1599 return 0;
1600 }
1601
1602#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1603
1604 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1605 if (th == NULL) {
1606 /* We've been asked to examine this packet, and we
1607 can't. Hence, no choice but to drop. */
1608 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1609 *hotdrop = 1;
1610 return 0;
1611 }
1612
1613 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1614 ntohs(th->source),
1615 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1616 return 0;
1617 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1618 ntohs(th->dest),
1619 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1620 return 0;
1621 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1622 == tcpinfo->flg_cmp,
1623 IP6T_TCP_INV_FLAGS))
1624 return 0;
1625 if (tcpinfo->option) {
1626 if (th->doff * 4 < sizeof(_tcph)) {
1627 *hotdrop = 1;
1628 return 0;
1629 }
1630 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1631 th->doff*4 - sizeof(*th),
1632 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1633 hotdrop))
1634 return 0;
1635 }
1636 return 1;
1637}
1638
1639/* Called when user tries to insert an entry of this type. */
1640static int
1641tcp_checkentry(const char *tablename,
1642 const struct ip6t_ip6 *ipv6,
1643 void *matchinfo,
1644 unsigned int matchsize,
1645 unsigned int hook_mask)
1646{
1647 const struct ip6t_tcp *tcpinfo = matchinfo;
1648
1649 /* Must specify proto == TCP, and no unknown invflags */
1650 return ipv6->proto == IPPROTO_TCP
1651 && !(ipv6->invflags & IP6T_INV_PROTO)
1652 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1653 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1654}
1655
1656static int
1657udp_match(const struct sk_buff *skb,
1658 const struct net_device *in,
1659 const struct net_device *out,
1660 const void *matchinfo,
1661 int offset,
1662 unsigned int protoff,
1663 int *hotdrop)
1664{
1665 struct udphdr _udph, *uh;
1666 const struct ip6t_udp *udpinfo = matchinfo;
1667
1668 /* Must not be a fragment. */
1669 if (offset)
1670 return 0;
1671
1672 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1673 if (uh == NULL) {
1674 /* We've been asked to examine this packet, and we
1675 can't. Hence, no choice but to drop. */
1676 duprintf("Dropping evil UDP tinygram.\n");
1677 *hotdrop = 1;
1678 return 0;
1679 }
1680
1681 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1682 ntohs(uh->source),
1683 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1684 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1685 ntohs(uh->dest),
1686 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1687}
1688
1689/* Called when user tries to insert an entry of this type. */
1690static int
1691udp_checkentry(const char *tablename,
1692 const struct ip6t_ip6 *ipv6,
1693 void *matchinfo,
1694 unsigned int matchinfosize,
1695 unsigned int hook_mask)
1696{
1697 const struct ip6t_udp *udpinfo = matchinfo;
1698
1699 /* Must specify proto == UDP, and no unknown invflags */
1700 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1701 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1702 IPPROTO_UDP);
1703 return 0;
1704 }
1705 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1706 duprintf("ip6t_udp: matchsize %u != %u\n",
1707 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1708 return 0;
1709 }
1710 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1711 duprintf("ip6t_udp: unknown flags %X\n",
1712 udpinfo->invflags);
1713 return 0;
1714 }
1715
1716 return 1;
1717}
1718
1719/* Returns 1 if the type and code is matched by the range, 0 otherwise */
1720static inline int
1721icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1722 u_int8_t type, u_int8_t code,
1723 int invert)
1724{
1725 return (type == test_type && code >= min_code && code <= max_code)
1726 ^ invert;
1727}
1728
1729static int
1730icmp6_match(const struct sk_buff *skb,
1731 const struct net_device *in,
1732 const struct net_device *out,
1733 const void *matchinfo,
1734 int offset,
1735 unsigned int protoff,
1736 int *hotdrop)
1737{
1738 struct icmp6hdr _icmp, *ic;
1739 const struct ip6t_icmp *icmpinfo = matchinfo;
1740
1741 /* Must not be a fragment. */
1742 if (offset)
1743 return 0;
1744
1745 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1746 if (ic == NULL) {
1747 /* We've been asked to examine this packet, and we
1748 can't. Hence, no choice but to drop. */
1749 duprintf("Dropping evil ICMP tinygram.\n");
1750 *hotdrop = 1;
1751 return 0;
1752 }
1753
1754 return icmp6_type_code_match(icmpinfo->type,
1755 icmpinfo->code[0],
1756 icmpinfo->code[1],
1757 ic->icmp6_type, ic->icmp6_code,
1758 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1759}
1760
1761/* Called when user tries to insert an entry of this type. */
1762static int
1763icmp6_checkentry(const char *tablename,
1764 const struct ip6t_ip6 *ipv6,
1765 void *matchinfo,
1766 unsigned int matchsize,
1767 unsigned int hook_mask)
1768{
1769 const struct ip6t_icmp *icmpinfo = matchinfo;
1770
1771 /* Must specify proto == ICMP, and no unknown invflags */
1772 return ipv6->proto == IPPROTO_ICMPV6
1773 && !(ipv6->invflags & IP6T_INV_PROTO)
1774 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1775 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1776}
1777
1778/* The built-in targets: standard (NULL) and error. */
1779static struct ip6t_target ip6t_standard_target = {
1780 .name = IP6T_STANDARD_TARGET,
1781};
1782
1783static struct ip6t_target ip6t_error_target = {
1784 .name = IP6T_ERROR_TARGET,
1785 .target = ip6t_error,
1786};
1787
1788static struct nf_sockopt_ops ip6t_sockopts = {
1789 .pf = PF_INET6,
1790 .set_optmin = IP6T_BASE_CTL,
1791 .set_optmax = IP6T_SO_SET_MAX+1,
1792 .set = do_ip6t_set_ctl,
1793 .get_optmin = IP6T_BASE_CTL,
1794 .get_optmax = IP6T_SO_GET_MAX+1,
1795 .get = do_ip6t_get_ctl,
1796};
1797
1798static struct ip6t_match tcp_matchstruct = {
1799 .name = "tcp",
1800 .match = &tcp_match,
1801 .checkentry = &tcp_checkentry,
1802};
1803
1804static struct ip6t_match udp_matchstruct = {
1805 .name = "udp",
1806 .match = &udp_match,
1807 .checkentry = &udp_checkentry,
1808};
1809
1810static struct ip6t_match icmp6_matchstruct = {
1811 .name = "icmp6",
1812 .match = &icmp6_match,
1813 .checkentry = &icmp6_checkentry,
1814};
1815
1816#ifdef CONFIG_PROC_FS
1817static inline int print_name(const char *i,
1818 off_t start_offset, char *buffer, int length,
1819 off_t *pos, unsigned int *count)
1820{
1821 if ((*count)++ >= start_offset) {
1822 unsigned int namelen;
1823
1824 namelen = sprintf(buffer + *pos, "%s\n",
1825 i + sizeof(struct list_head));
1826 if (*pos + namelen > length) {
1827 /* Stop iterating */
1828 return 1;
1829 }
1830 *pos += namelen;
1831 }
1832 return 0;
1833}
1834
1835static inline int print_target(const struct ip6t_target *t,
1836 off_t start_offset, char *buffer, int length,
1837 off_t *pos, unsigned int *count)
1838{
1839 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1840 return 0;
1841 return print_name((char *)t, start_offset, buffer, length, pos, count);
1842}
1843
1844static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1845{
1846 off_t pos = 0;
1847 unsigned int count = 0;
1848
1849 if (down_interruptible(&ip6t_mutex) != 0)
1850 return 0;
1851
1852 LIST_FIND(&ip6t_tables, print_name, char *,
1853 offset, buffer, length, &pos, &count);
1854
1855 up(&ip6t_mutex);
1856
1857 /* `start' hack - see fs/proc/generic.c line ~105 */
1858 *start=(char *)((unsigned long)count-offset);
1859 return pos;
1860}
1861
1862static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1863{
1864 off_t pos = 0;
1865 unsigned int count = 0;
1866
1867 if (down_interruptible(&ip6t_mutex) != 0)
1868 return 0;
1869
1870 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1871 offset, buffer, length, &pos, &count);
1872
1873 up(&ip6t_mutex);
1874
1875 *start = (char *)((unsigned long)count - offset);
1876 return pos;
1877}
1878
1879static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1880{
1881 off_t pos = 0;
1882 unsigned int count = 0;
1883
1884 if (down_interruptible(&ip6t_mutex) != 0)
1885 return 0;
1886
1887 LIST_FIND(&ip6t_match, print_name, char *,
1888 offset, buffer, length, &pos, &count);
1889
1890 up(&ip6t_mutex);
1891
1892 *start = (char *)((unsigned long)count - offset);
1893 return pos;
1894}
1895
1896static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1897{ { "ip6_tables_names", ip6t_get_tables },
1898 { "ip6_tables_targets", ip6t_get_targets },
1899 { "ip6_tables_matches", ip6t_get_matches },
1900 { NULL, NULL} };
1901#endif /*CONFIG_PROC_FS*/
1902
1903static int __init init(void)
1904{
1905 int ret;
1906
1907 /* Noone else will be downing sem now, so we won't sleep */
1908 down(&ip6t_mutex);
1909 list_append(&ip6t_target, &ip6t_standard_target);
1910 list_append(&ip6t_target, &ip6t_error_target);
1911 list_append(&ip6t_match, &tcp_matchstruct);
1912 list_append(&ip6t_match, &udp_matchstruct);
1913 list_append(&ip6t_match, &icmp6_matchstruct);
1914 up(&ip6t_mutex);
1915
1916 /* Register setsockopt */
1917 ret = nf_register_sockopt(&ip6t_sockopts);
1918 if (ret < 0) {
1919 duprintf("Unable to register sockopts.\n");
1920 return ret;
1921 }
1922
1923#ifdef CONFIG_PROC_FS
1924 {
1925 struct proc_dir_entry *proc;
1926 int i;
1927
1928 for (i = 0; ip6t_proc_entry[i].name; i++) {
1929 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1930 ip6t_proc_entry[i].get_info);
1931 if (!proc) {
1932 while (--i >= 0)
1933 proc_net_remove(ip6t_proc_entry[i].name);
1934 nf_unregister_sockopt(&ip6t_sockopts);
1935 return -ENOMEM;
1936 }
1937 proc->owner = THIS_MODULE;
1938 }
1939 }
1940#endif
1941
1942 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1943 return 0;
1944}
1945
1946static void __exit fini(void)
1947{
1948 nf_unregister_sockopt(&ip6t_sockopts);
1949#ifdef CONFIG_PROC_FS
1950 {
1951 int i;
1952 for (i = 0; ip6t_proc_entry[i].name; i++)
1953 proc_net_remove(ip6t_proc_entry[i].name);
1954 }
1955#endif
1956}
1957
e674d0f3
YK
1958/*
1959 * find specified header up to transport protocol header.
1960 * If found target header, the offset to the header is set to *offset
1961 * and return 0. otherwise, return -1.
1962 *
1963 * Notes: - non-1st Fragment Header isn't skipped.
1964 * - ESP header isn't skipped.
1965 * - The target header may be trancated.
1966 */
1967int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
1968{
1969 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1970 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1971 unsigned int len = skb->len - start;
1972
1973 while (nexthdr != target) {
1974 struct ipv6_opt_hdr _hdr, *hp;
1975 unsigned int hdrlen;
1976
1977 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
1978 return -1;
1979 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
1980 if (hp == NULL)
1981 return -1;
1982 if (nexthdr == NEXTHDR_FRAGMENT) {
1983 unsigned short _frag_off, *fp;
1984 fp = skb_header_pointer(skb,
1985 start+offsetof(struct frag_hdr,
1986 frag_off),
1987 sizeof(_frag_off),
1988 &_frag_off);
1989 if (fp == NULL)
1990 return -1;
1991
1992 if (ntohs(*fp) & ~0x7)
1993 return -1;
1994 hdrlen = 8;
1995 } else if (nexthdr == NEXTHDR_AUTH)
1996 hdrlen = (hp->hdrlen + 2) << 2;
1997 else
1998 hdrlen = ipv6_optlen(hp);
1999
2000 nexthdr = hp->nexthdr;
2001 len -= hdrlen;
2002 start += hdrlen;
2003 }
2004
2005 *offset = start;
2006 return 0;
2007}
2008
1da177e4
LT
2009EXPORT_SYMBOL(ip6t_register_table);
2010EXPORT_SYMBOL(ip6t_unregister_table);
2011EXPORT_SYMBOL(ip6t_do_table);
2012EXPORT_SYMBOL(ip6t_register_match);
2013EXPORT_SYMBOL(ip6t_unregister_match);
2014EXPORT_SYMBOL(ip6t_register_target);
2015EXPORT_SYMBOL(ip6t_unregister_target);
2016EXPORT_SYMBOL(ip6t_ext_hdr);
e674d0f3 2017EXPORT_SYMBOL(ipv6_find_hdr);
1da177e4
LT
2018
2019module_init(init);
2020module_exit(fini);