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