]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/ipv6/netfilter/ip6_tables.c
Linux-2.6.12-rc2
[mirror_ubuntu-artful-kernel.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)
74#include <linux/netfilter_ipv4/lockhelp.h>
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);
405 (*pskb)->nfcache |= e->nfcache;
406 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
407 &protoff, &offset)) {
408 struct ip6t_entry_target *t;
409
410 if (IP6T_MATCH_ITERATE(e, do_match,
411 *pskb, in, out,
412 offset, protoff, &hotdrop) != 0)
413 goto no_match;
414
415 ADD_COUNTER(e->counters,
416 ntohs((*pskb)->nh.ipv6h->payload_len)
417 + IPV6_HDR_LEN,
418 1);
419
420 t = ip6t_get_target(e);
421 IP_NF_ASSERT(t->u.kernel.target);
422 /* Standard target? */
423 if (!t->u.kernel.target->target) {
424 int v;
425
426 v = ((struct ip6t_standard_target *)t)->verdict;
427 if (v < 0) {
428 /* Pop from stack? */
429 if (v != IP6T_RETURN) {
430 verdict = (unsigned)(-v) - 1;
431 break;
432 }
433 e = back;
434 back = get_entry(table_base,
435 back->comefrom);
436 continue;
437 }
438 if (table_base + v
439 != (void *)e + e->next_offset) {
440 /* Save old back ptr in next entry */
441 struct ip6t_entry *next
442 = (void *)e + e->next_offset;
443 next->comefrom
444 = (void *)back - table_base;
445 /* set back pointer to next entry */
446 back = next;
447 }
448
449 e = get_entry(table_base, v);
450 } else {
451 /* Targets which reenter must return
452 abs. verdicts */
453#ifdef CONFIG_NETFILTER_DEBUG
454 ((struct ip6t_entry *)table_base)->comefrom
455 = 0xeeeeeeec;
456#endif
457 verdict = t->u.kernel.target->target(pskb,
458 in, out,
459 hook,
460 t->data,
461 userdata);
462
463#ifdef CONFIG_NETFILTER_DEBUG
464 if (((struct ip6t_entry *)table_base)->comefrom
465 != 0xeeeeeeec
466 && verdict == IP6T_CONTINUE) {
467 printk("Target %s reentered!\n",
468 t->u.kernel.target->name);
469 verdict = NF_DROP;
470 }
471 ((struct ip6t_entry *)table_base)->comefrom
472 = 0x57acc001;
473#endif
474 if (verdict == IP6T_CONTINUE)
475 e = (void *)e + e->next_offset;
476 else
477 /* Verdict */
478 break;
479 }
480 } else {
481
482 no_match:
483 e = (void *)e + e->next_offset;
484 }
485 } while (!hotdrop);
486
487#ifdef CONFIG_NETFILTER_DEBUG
488 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
489#endif
490 read_unlock_bh(&table->lock);
491
492#ifdef DEBUG_ALLOW_ALL
493 return NF_ACCEPT;
494#else
495 if (hotdrop)
496 return NF_DROP;
497 else return verdict;
498#endif
499}
500
501/* If it succeeds, returns element and locks mutex */
502static inline void *
503find_inlist_lock_noload(struct list_head *head,
504 const char *name,
505 int *error,
506 struct semaphore *mutex)
507{
508 void *ret;
509
510#if 1
511 duprintf("find_inlist: searching for `%s' in %s.\n",
512 name, head == &ip6t_target ? "ip6t_target"
513 : head == &ip6t_match ? "ip6t_match"
514 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
515#endif
516
517 *error = down_interruptible(mutex);
518 if (*error != 0)
519 return NULL;
520
521 ret = list_named_find(head, name);
522 if (!ret) {
523 *error = -ENOENT;
524 up(mutex);
525 }
526 return ret;
527}
528
529#ifndef CONFIG_KMOD
530#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
531#else
532static void *
533find_inlist_lock(struct list_head *head,
534 const char *name,
535 const char *prefix,
536 int *error,
537 struct semaphore *mutex)
538{
539 void *ret;
540
541 ret = find_inlist_lock_noload(head, name, error, mutex);
542 if (!ret) {
543 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
544 request_module("%s%s", prefix, name);
545 ret = find_inlist_lock_noload(head, name, error, mutex);
546 }
547
548 return ret;
549}
550#endif
551
552static inline struct ip6t_table *
553ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
554{
555 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
556}
557
558static inline struct ip6t_match *
559find_match_lock(const char *name, int *error, struct semaphore *mutex)
560{
561 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
562}
563
564static struct ip6t_target *
565ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex)
566{
567 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
568}
569
570/* All zeroes == unconditional rule. */
571static inline int
572unconditional(const struct ip6t_ip6 *ipv6)
573{
574 unsigned int i;
575
576 for (i = 0; i < sizeof(*ipv6); i++)
577 if (((char *)ipv6)[i])
578 break;
579
580 return (i == sizeof(*ipv6));
581}
582
583/* Figures out from what hook each rule can be called: returns 0 if
584 there are loops. Puts hook bitmask in comefrom. */
585static int
586mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
587{
588 unsigned int hook;
589
590 /* No recursion; use packet counter to save back ptrs (reset
591 to 0 as we leave), and comefrom to save source hook bitmask */
592 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
593 unsigned int pos = newinfo->hook_entry[hook];
594 struct ip6t_entry *e
595 = (struct ip6t_entry *)(newinfo->entries + pos);
596
597 if (!(valid_hooks & (1 << hook)))
598 continue;
599
600 /* Set initial back pointer. */
601 e->counters.pcnt = pos;
602
603 for (;;) {
604 struct ip6t_standard_target *t
605 = (void *)ip6t_get_target(e);
606
607 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
608 printk("iptables: loop hook %u pos %u %08X.\n",
609 hook, pos, e->comefrom);
610 return 0;
611 }
612 e->comefrom
613 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
614
615 /* Unconditional return/END. */
616 if (e->target_offset == sizeof(struct ip6t_entry)
617 && (strcmp(t->target.u.user.name,
618 IP6T_STANDARD_TARGET) == 0)
619 && t->verdict < 0
620 && unconditional(&e->ipv6)) {
621 unsigned int oldpos, size;
622
623 /* Return: backtrack through the last
624 big jump. */
625 do {
626 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
627#ifdef DEBUG_IP_FIREWALL_USER
628 if (e->comefrom
629 & (1 << NF_IP6_NUMHOOKS)) {
630 duprintf("Back unset "
631 "on hook %u "
632 "rule %u\n",
633 hook, pos);
634 }
635#endif
636 oldpos = pos;
637 pos = e->counters.pcnt;
638 e->counters.pcnt = 0;
639
640 /* We're at the start. */
641 if (pos == oldpos)
642 goto next;
643
644 e = (struct ip6t_entry *)
645 (newinfo->entries + pos);
646 } while (oldpos == pos + e->next_offset);
647
648 /* Move along one */
649 size = e->next_offset;
650 e = (struct ip6t_entry *)
651 (newinfo->entries + pos + size);
652 e->counters.pcnt = pos;
653 pos += size;
654 } else {
655 int newpos = t->verdict;
656
657 if (strcmp(t->target.u.user.name,
658 IP6T_STANDARD_TARGET) == 0
659 && newpos >= 0) {
660 /* This a jump; chase it. */
661 duprintf("Jump rule %u -> %u\n",
662 pos, newpos);
663 } else {
664 /* ... this is a fallthru */
665 newpos = pos + e->next_offset;
666 }
667 e = (struct ip6t_entry *)
668 (newinfo->entries + newpos);
669 e->counters.pcnt = pos;
670 pos = newpos;
671 }
672 }
673 next:
674 duprintf("Finished chain %u\n", hook);
675 }
676 return 1;
677}
678
679static inline int
680cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
681{
682 if (i && (*i)-- == 0)
683 return 1;
684
685 if (m->u.kernel.match->destroy)
686 m->u.kernel.match->destroy(m->data,
687 m->u.match_size - sizeof(*m));
688 module_put(m->u.kernel.match->me);
689 return 0;
690}
691
692static inline int
693standard_check(const struct ip6t_entry_target *t,
694 unsigned int max_offset)
695{
696 struct ip6t_standard_target *targ = (void *)t;
697
698 /* Check standard info. */
699 if (t->u.target_size
700 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
701 duprintf("standard_check: target size %u != %u\n",
702 t->u.target_size,
703 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
704 return 0;
705 }
706
707 if (targ->verdict >= 0
708 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
709 duprintf("ip6t_standard_check: bad verdict (%i)\n",
710 targ->verdict);
711 return 0;
712 }
713
714 if (targ->verdict < -NF_MAX_VERDICT - 1) {
715 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
716 targ->verdict);
717 return 0;
718 }
719 return 1;
720}
721
722static inline int
723check_match(struct ip6t_entry_match *m,
724 const char *name,
725 const struct ip6t_ip6 *ipv6,
726 unsigned int hookmask,
727 unsigned int *i)
728{
729 int ret;
730 struct ip6t_match *match;
731
732 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
733 if (!match) {
734 // duprintf("check_match: `%s' not found\n", m->u.name);
735 return ret;
736 }
737 if (!try_module_get(match->me)) {
738 up(&ip6t_mutex);
739 return -ENOENT;
740 }
741 m->u.kernel.match = match;
742 up(&ip6t_mutex);
743
744 if (m->u.kernel.match->checkentry
745 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
746 m->u.match_size - sizeof(*m),
747 hookmask)) {
748 module_put(m->u.kernel.match->me);
749 duprintf("ip_tables: check failed for `%s'.\n",
750 m->u.kernel.match->name);
751 return -EINVAL;
752 }
753
754 (*i)++;
755 return 0;
756}
757
758static struct ip6t_target ip6t_standard_target;
759
760static inline int
761check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
762 unsigned int *i)
763{
764 struct ip6t_entry_target *t;
765 struct ip6t_target *target;
766 int ret;
767 unsigned int j;
768
769 if (!ip6_checkentry(&e->ipv6)) {
770 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
771 return -EINVAL;
772 }
773
774 j = 0;
775 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
776 if (ret != 0)
777 goto cleanup_matches;
778
779 t = ip6t_get_target(e);
780 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
781 if (!target) {
782 duprintf("check_entry: `%s' not found\n", t->u.user.name);
783 goto cleanup_matches;
784 }
785 if (!try_module_get(target->me)) {
786 up(&ip6t_mutex);
787 ret = -ENOENT;
788 goto cleanup_matches;
789 }
790 t->u.kernel.target = target;
791 up(&ip6t_mutex);
792 if (!t->u.kernel.target) {
793 ret = -EBUSY;
794 goto cleanup_matches;
795 }
796 if (t->u.kernel.target == &ip6t_standard_target) {
797 if (!standard_check(t, size)) {
798 ret = -EINVAL;
799 goto cleanup_matches;
800 }
801 } else if (t->u.kernel.target->checkentry
802 && !t->u.kernel.target->checkentry(name, e, t->data,
803 t->u.target_size
804 - sizeof(*t),
805 e->comefrom)) {
806 module_put(t->u.kernel.target->me);
807 duprintf("ip_tables: check failed for `%s'.\n",
808 t->u.kernel.target->name);
809 ret = -EINVAL;
810 goto cleanup_matches;
811 }
812
813 (*i)++;
814 return 0;
815
816 cleanup_matches:
817 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
818 return ret;
819}
820
821static inline int
822check_entry_size_and_hooks(struct ip6t_entry *e,
823 struct ip6t_table_info *newinfo,
824 unsigned char *base,
825 unsigned char *limit,
826 const unsigned int *hook_entries,
827 const unsigned int *underflows,
828 unsigned int *i)
829{
830 unsigned int h;
831
832 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
833 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
834 duprintf("Bad offset %p\n", e);
835 return -EINVAL;
836 }
837
838 if (e->next_offset
839 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
840 duprintf("checking: element %p size %u\n",
841 e, e->next_offset);
842 return -EINVAL;
843 }
844
845 /* Check hooks & underflows */
846 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
847 if ((unsigned char *)e - base == hook_entries[h])
848 newinfo->hook_entry[h] = hook_entries[h];
849 if ((unsigned char *)e - base == underflows[h])
850 newinfo->underflow[h] = underflows[h];
851 }
852
853 /* FIXME: underflows must be unconditional, standard verdicts
854 < 0 (not IP6T_RETURN). --RR */
855
856 /* Clear counters and comefrom */
857 e->counters = ((struct ip6t_counters) { 0, 0 });
858 e->comefrom = 0;
859
860 (*i)++;
861 return 0;
862}
863
864static inline int
865cleanup_entry(struct ip6t_entry *e, unsigned int *i)
866{
867 struct ip6t_entry_target *t;
868
869 if (i && (*i)-- == 0)
870 return 1;
871
872 /* Cleanup all matches */
873 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
874 t = ip6t_get_target(e);
875 if (t->u.kernel.target->destroy)
876 t->u.kernel.target->destroy(t->data,
877 t->u.target_size - sizeof(*t));
878 module_put(t->u.kernel.target->me);
879 return 0;
880}
881
882/* Checks and translates the user-supplied table segment (held in
883 newinfo) */
884static int
885translate_table(const char *name,
886 unsigned int valid_hooks,
887 struct ip6t_table_info *newinfo,
888 unsigned int size,
889 unsigned int number,
890 const unsigned int *hook_entries,
891 const unsigned int *underflows)
892{
893 unsigned int i;
894 int ret;
895
896 newinfo->size = size;
897 newinfo->number = number;
898
899 /* Init all hooks to impossible value. */
900 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
901 newinfo->hook_entry[i] = 0xFFFFFFFF;
902 newinfo->underflow[i] = 0xFFFFFFFF;
903 }
904
905 duprintf("translate_table: size %u\n", newinfo->size);
906 i = 0;
907 /* Walk through entries, checking offsets. */
908 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
909 check_entry_size_and_hooks,
910 newinfo,
911 newinfo->entries,
912 newinfo->entries + size,
913 hook_entries, underflows, &i);
914 if (ret != 0)
915 return ret;
916
917 if (i != number) {
918 duprintf("translate_table: %u not %u entries\n",
919 i, number);
920 return -EINVAL;
921 }
922
923 /* Check hooks all assigned */
924 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
925 /* Only hooks which are valid */
926 if (!(valid_hooks & (1 << i)))
927 continue;
928 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
929 duprintf("Invalid hook entry %u %u\n",
930 i, hook_entries[i]);
931 return -EINVAL;
932 }
933 if (newinfo->underflow[i] == 0xFFFFFFFF) {
934 duprintf("Invalid underflow %u %u\n",
935 i, underflows[i]);
936 return -EINVAL;
937 }
938 }
939
940 if (!mark_source_chains(newinfo, valid_hooks))
941 return -ELOOP;
942
943 /* Finally, each sanity check must pass */
944 i = 0;
945 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
946 check_entry, name, size, &i);
947
948 if (ret != 0) {
949 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
950 cleanup_entry, &i);
951 return ret;
952 }
953
954 /* And one copy for every other CPU */
955 for (i = 1; i < num_possible_cpus(); i++) {
956 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
957 newinfo->entries,
958 SMP_ALIGN(newinfo->size));
959 }
960
961 return ret;
962}
963
964static struct ip6t_table_info *
965replace_table(struct ip6t_table *table,
966 unsigned int num_counters,
967 struct ip6t_table_info *newinfo,
968 int *error)
969{
970 struct ip6t_table_info *oldinfo;
971
972#ifdef CONFIG_NETFILTER_DEBUG
973 {
974 struct ip6t_entry *table_base;
975 unsigned int i;
976
977 for (i = 0; i < num_possible_cpus(); i++) {
978 table_base =
979 (void *)newinfo->entries
980 + TABLE_OFFSET(newinfo, i);
981
982 table_base->comefrom = 0xdead57ac;
983 }
984 }
985#endif
986
987 /* Do the substitution. */
988 write_lock_bh(&table->lock);
989 /* Check inside lock: is the old number correct? */
990 if (num_counters != table->private->number) {
991 duprintf("num_counters != table->private->number (%u/%u)\n",
992 num_counters, table->private->number);
993 write_unlock_bh(&table->lock);
994 *error = -EAGAIN;
995 return NULL;
996 }
997 oldinfo = table->private;
998 table->private = newinfo;
999 newinfo->initial_entries = oldinfo->initial_entries;
1000 write_unlock_bh(&table->lock);
1001
1002 return oldinfo;
1003}
1004
1005/* Gets counters. */
1006static inline int
1007add_entry_to_counter(const struct ip6t_entry *e,
1008 struct ip6t_counters total[],
1009 unsigned int *i)
1010{
1011 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1012
1013 (*i)++;
1014 return 0;
1015}
1016
1017static void
1018get_counters(const struct ip6t_table_info *t,
1019 struct ip6t_counters counters[])
1020{
1021 unsigned int cpu;
1022 unsigned int i;
1023
1024 for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
1025 i = 0;
1026 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1027 t->size,
1028 add_entry_to_counter,
1029 counters,
1030 &i);
1031 }
1032}
1033
1034static int
1035copy_entries_to_user(unsigned int total_size,
1036 struct ip6t_table *table,
1037 void __user *userptr)
1038{
1039 unsigned int off, num, countersize;
1040 struct ip6t_entry *e;
1041 struct ip6t_counters *counters;
1042 int ret = 0;
1043
1044 /* We need atomic snapshot of counters: rest doesn't change
1045 (other than comefrom, which userspace doesn't care
1046 about). */
1047 countersize = sizeof(struct ip6t_counters) * table->private->number;
1048 counters = vmalloc(countersize);
1049
1050 if (counters == NULL)
1051 return -ENOMEM;
1052
1053 /* First, sum counters... */
1054 memset(counters, 0, countersize);
1055 write_lock_bh(&table->lock);
1056 get_counters(table->private, counters);
1057 write_unlock_bh(&table->lock);
1058
1059 /* ... then copy entire thing from CPU 0... */
1060 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1061 ret = -EFAULT;
1062 goto free_counters;
1063 }
1064
1065 /* FIXME: use iterator macros --RR */
1066 /* ... then go back and fix counters and names */
1067 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1068 unsigned int i;
1069 struct ip6t_entry_match *m;
1070 struct ip6t_entry_target *t;
1071
1072 e = (struct ip6t_entry *)(table->private->entries + off);
1073 if (copy_to_user(userptr + off
1074 + offsetof(struct ip6t_entry, counters),
1075 &counters[num],
1076 sizeof(counters[num])) != 0) {
1077 ret = -EFAULT;
1078 goto free_counters;
1079 }
1080
1081 for (i = sizeof(struct ip6t_entry);
1082 i < e->target_offset;
1083 i += m->u.match_size) {
1084 m = (void *)e + i;
1085
1086 if (copy_to_user(userptr + off + i
1087 + offsetof(struct ip6t_entry_match,
1088 u.user.name),
1089 m->u.kernel.match->name,
1090 strlen(m->u.kernel.match->name)+1)
1091 != 0) {
1092 ret = -EFAULT;
1093 goto free_counters;
1094 }
1095 }
1096
1097 t = ip6t_get_target(e);
1098 if (copy_to_user(userptr + off + e->target_offset
1099 + offsetof(struct ip6t_entry_target,
1100 u.user.name),
1101 t->u.kernel.target->name,
1102 strlen(t->u.kernel.target->name)+1) != 0) {
1103 ret = -EFAULT;
1104 goto free_counters;
1105 }
1106 }
1107
1108 free_counters:
1109 vfree(counters);
1110 return ret;
1111}
1112
1113static int
1114get_entries(const struct ip6t_get_entries *entries,
1115 struct ip6t_get_entries __user *uptr)
1116{
1117 int ret;
1118 struct ip6t_table *t;
1119
1120 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex);
1121 if (t) {
1122 duprintf("t->private->number = %u\n",
1123 t->private->number);
1124 if (entries->size == t->private->size)
1125 ret = copy_entries_to_user(t->private->size,
1126 t, uptr->entrytable);
1127 else {
1128 duprintf("get_entries: I've got %u not %u!\n",
1129 t->private->size,
1130 entries->size);
1131 ret = -EINVAL;
1132 }
1133 up(&ip6t_mutex);
1134 } else
1135 duprintf("get_entries: Can't find %s!\n",
1136 entries->name);
1137
1138 return ret;
1139}
1140
1141static int
1142do_replace(void __user *user, unsigned int len)
1143{
1144 int ret;
1145 struct ip6t_replace tmp;
1146 struct ip6t_table *t;
1147 struct ip6t_table_info *newinfo, *oldinfo;
1148 struct ip6t_counters *counters;
1149
1150 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1151 return -EFAULT;
1152
1153 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1154 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1155 return -ENOMEM;
1156
1157 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1158 + SMP_ALIGN(tmp.size) * num_possible_cpus());
1159 if (!newinfo)
1160 return -ENOMEM;
1161
1162 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1163 tmp.size) != 0) {
1164 ret = -EFAULT;
1165 goto free_newinfo;
1166 }
1167
1168 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1169 if (!counters) {
1170 ret = -ENOMEM;
1171 goto free_newinfo;
1172 }
1173 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1174
1175 ret = translate_table(tmp.name, tmp.valid_hooks,
1176 newinfo, tmp.size, tmp.num_entries,
1177 tmp.hook_entry, tmp.underflow);
1178 if (ret != 0)
1179 goto free_newinfo_counters;
1180
1181 duprintf("ip_tables: Translated table\n");
1182
1183 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1184 if (!t)
1185 goto free_newinfo_counters_untrans;
1186
1187 /* You lied! */
1188 if (tmp.valid_hooks != t->valid_hooks) {
1189 duprintf("Valid hook crap: %08X vs %08X\n",
1190 tmp.valid_hooks, t->valid_hooks);
1191 ret = -EINVAL;
1192 goto free_newinfo_counters_untrans_unlock;
1193 }
1194
1195 /* Get a reference in advance, we're not allowed fail later */
1196 if (!try_module_get(t->me)) {
1197 ret = -EBUSY;
1198 goto free_newinfo_counters_untrans_unlock;
1199 }
1200
1201 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1202 if (!oldinfo)
1203 goto put_module;
1204
1205 /* Update module usage count based on number of rules */
1206 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1207 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1208 if ((oldinfo->number > oldinfo->initial_entries) ||
1209 (newinfo->number <= oldinfo->initial_entries))
1210 module_put(t->me);
1211 if ((oldinfo->number > oldinfo->initial_entries) &&
1212 (newinfo->number <= oldinfo->initial_entries))
1213 module_put(t->me);
1214
1215 /* Get the old counters. */
1216 get_counters(oldinfo, counters);
1217 /* Decrease module usage counts and free resource */
1218 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1219 vfree(oldinfo);
1220 /* Silent error: too late now. */
1221 if (copy_to_user(tmp.counters, counters,
1222 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1223 ret = -EFAULT;
1224 vfree(counters);
1225 up(&ip6t_mutex);
1226 return ret;
1227
1228 put_module:
1229 module_put(t->me);
1230 free_newinfo_counters_untrans_unlock:
1231 up(&ip6t_mutex);
1232 free_newinfo_counters_untrans:
1233 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1234 free_newinfo_counters:
1235 vfree(counters);
1236 free_newinfo:
1237 vfree(newinfo);
1238 return ret;
1239}
1240
1241/* We're lazy, and add to the first CPU; overflow works its fey magic
1242 * and everything is OK. */
1243static inline int
1244add_counter_to_entry(struct ip6t_entry *e,
1245 const struct ip6t_counters addme[],
1246 unsigned int *i)
1247{
1248#if 0
1249 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1250 *i,
1251 (long unsigned int)e->counters.pcnt,
1252 (long unsigned int)e->counters.bcnt,
1253 (long unsigned int)addme[*i].pcnt,
1254 (long unsigned int)addme[*i].bcnt);
1255#endif
1256
1257 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1258
1259 (*i)++;
1260 return 0;
1261}
1262
1263static int
1264do_add_counters(void __user *user, unsigned int len)
1265{
1266 unsigned int i;
1267 struct ip6t_counters_info tmp, *paddc;
1268 struct ip6t_table *t;
1269 int ret;
1270
1271 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1272 return -EFAULT;
1273
1274 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1275 return -EINVAL;
1276
1277 paddc = vmalloc(len);
1278 if (!paddc)
1279 return -ENOMEM;
1280
1281 if (copy_from_user(paddc, user, len) != 0) {
1282 ret = -EFAULT;
1283 goto free;
1284 }
1285
1286 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex);
1287 if (!t)
1288 goto free;
1289
1290 write_lock_bh(&t->lock);
1291 if (t->private->number != paddc->num_counters) {
1292 ret = -EINVAL;
1293 goto unlock_up_free;
1294 }
1295
1296 i = 0;
1297 IP6T_ENTRY_ITERATE(t->private->entries,
1298 t->private->size,
1299 add_counter_to_entry,
1300 paddc->counters,
1301 &i);
1302 unlock_up_free:
1303 write_unlock_bh(&t->lock);
1304 up(&ip6t_mutex);
1305 free:
1306 vfree(paddc);
1307
1308 return ret;
1309}
1310
1311static int
1312do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1313{
1314 int ret;
1315
1316 if (!capable(CAP_NET_ADMIN))
1317 return -EPERM;
1318
1319 switch (cmd) {
1320 case IP6T_SO_SET_REPLACE:
1321 ret = do_replace(user, len);
1322 break;
1323
1324 case IP6T_SO_SET_ADD_COUNTERS:
1325 ret = do_add_counters(user, len);
1326 break;
1327
1328 default:
1329 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1330 ret = -EINVAL;
1331 }
1332
1333 return ret;
1334}
1335
1336static int
1337do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1338{
1339 int ret;
1340
1341 if (!capable(CAP_NET_ADMIN))
1342 return -EPERM;
1343
1344 switch (cmd) {
1345 case IP6T_SO_GET_INFO: {
1346 char name[IP6T_TABLE_MAXNAMELEN];
1347 struct ip6t_table *t;
1348
1349 if (*len != sizeof(struct ip6t_getinfo)) {
1350 duprintf("length %u != %u\n", *len,
1351 sizeof(struct ip6t_getinfo));
1352 ret = -EINVAL;
1353 break;
1354 }
1355
1356 if (copy_from_user(name, user, sizeof(name)) != 0) {
1357 ret = -EFAULT;
1358 break;
1359 }
1360 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1361 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex);
1362 if (t) {
1363 struct ip6t_getinfo info;
1364
1365 info.valid_hooks = t->valid_hooks;
1366 memcpy(info.hook_entry, t->private->hook_entry,
1367 sizeof(info.hook_entry));
1368 memcpy(info.underflow, t->private->underflow,
1369 sizeof(info.underflow));
1370 info.num_entries = t->private->number;
1371 info.size = t->private->size;
1372 memcpy(info.name, name, sizeof(info.name));
1373
1374 if (copy_to_user(user, &info, *len) != 0)
1375 ret = -EFAULT;
1376 else
1377 ret = 0;
1378
1379 up(&ip6t_mutex);
1380 }
1381 }
1382 break;
1383
1384 case IP6T_SO_GET_ENTRIES: {
1385 struct ip6t_get_entries get;
1386
1387 if (*len < sizeof(get)) {
1388 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1389 ret = -EINVAL;
1390 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1391 ret = -EFAULT;
1392 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1393 duprintf("get_entries: %u != %u\n", *len,
1394 sizeof(struct ip6t_get_entries) + get.size);
1395 ret = -EINVAL;
1396 } else
1397 ret = get_entries(&get, user);
1398 break;
1399 }
1400
1401 default:
1402 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1403 ret = -EINVAL;
1404 }
1405
1406 return ret;
1407}
1408
1409/* Registration hooks for targets. */
1410int
1411ip6t_register_target(struct ip6t_target *target)
1412{
1413 int ret;
1414
1415 ret = down_interruptible(&ip6t_mutex);
1416 if (ret != 0)
1417 return ret;
1418
1419 if (!list_named_insert(&ip6t_target, target)) {
1420 duprintf("ip6t_register_target: `%s' already in list!\n",
1421 target->name);
1422 ret = -EINVAL;
1423 }
1424 up(&ip6t_mutex);
1425 return ret;
1426}
1427
1428void
1429ip6t_unregister_target(struct ip6t_target *target)
1430{
1431 down(&ip6t_mutex);
1432 LIST_DELETE(&ip6t_target, target);
1433 up(&ip6t_mutex);
1434}
1435
1436int
1437ip6t_register_match(struct ip6t_match *match)
1438{
1439 int ret;
1440
1441 ret = down_interruptible(&ip6t_mutex);
1442 if (ret != 0)
1443 return ret;
1444
1445 if (!list_named_insert(&ip6t_match, match)) {
1446 duprintf("ip6t_register_match: `%s' already in list!\n",
1447 match->name);
1448 ret = -EINVAL;
1449 }
1450 up(&ip6t_mutex);
1451
1452 return ret;
1453}
1454
1455void
1456ip6t_unregister_match(struct ip6t_match *match)
1457{
1458 down(&ip6t_mutex);
1459 LIST_DELETE(&ip6t_match, match);
1460 up(&ip6t_mutex);
1461}
1462
1463int ip6t_register_table(struct ip6t_table *table,
1464 const struct ip6t_replace *repl)
1465{
1466 int ret;
1467 struct ip6t_table_info *newinfo;
1468 static struct ip6t_table_info bootstrap
1469 = { 0, 0, 0, { 0 }, { 0 }, { } };
1470
1471 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1472 + SMP_ALIGN(repl->size) * num_possible_cpus());
1473 if (!newinfo)
1474 return -ENOMEM;
1475
1476 memcpy(newinfo->entries, repl->entries, repl->size);
1477
1478 ret = translate_table(table->name, table->valid_hooks,
1479 newinfo, repl->size,
1480 repl->num_entries,
1481 repl->hook_entry,
1482 repl->underflow);
1483 if (ret != 0) {
1484 vfree(newinfo);
1485 return ret;
1486 }
1487
1488 ret = down_interruptible(&ip6t_mutex);
1489 if (ret != 0) {
1490 vfree(newinfo);
1491 return ret;
1492 }
1493
1494 /* Don't autoload: we'd eat our tail... */
1495 if (list_named_find(&ip6t_tables, table->name)) {
1496 ret = -EEXIST;
1497 goto free_unlock;
1498 }
1499
1500 /* Simplifies replace_table code. */
1501 table->private = &bootstrap;
1502 if (!replace_table(table, 0, newinfo, &ret))
1503 goto free_unlock;
1504
1505 duprintf("table->private->number = %u\n",
1506 table->private->number);
1507
1508 /* save number of initial entries */
1509 table->private->initial_entries = table->private->number;
1510
1511 rwlock_init(&table->lock);
1512 list_prepend(&ip6t_tables, table);
1513
1514 unlock:
1515 up(&ip6t_mutex);
1516 return ret;
1517
1518 free_unlock:
1519 vfree(newinfo);
1520 goto unlock;
1521}
1522
1523void ip6t_unregister_table(struct ip6t_table *table)
1524{
1525 down(&ip6t_mutex);
1526 LIST_DELETE(&ip6t_tables, table);
1527 up(&ip6t_mutex);
1528
1529 /* Decrease module usage counts and free resources */
1530 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1531 cleanup_entry, NULL);
1532 vfree(table->private);
1533}
1534
1535/* Returns 1 if the port is matched by the range, 0 otherwise */
1536static inline int
1537port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1538{
1539 int ret;
1540
1541 ret = (port >= min && port <= max) ^ invert;
1542 return ret;
1543}
1544
1545static int
1546tcp_find_option(u_int8_t option,
1547 const struct sk_buff *skb,
1548 unsigned int tcpoff,
1549 unsigned int optlen,
1550 int invert,
1551 int *hotdrop)
1552{
1553 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1554 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1555 unsigned int i;
1556
1557 duprintf("tcp_match: finding option\n");
1558 if (!optlen)
1559 return invert;
1560 /* If we don't have the whole header, drop packet. */
1561 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1562 _opt);
1563 if (op == NULL) {
1564 *hotdrop = 1;
1565 return 0;
1566 }
1567
1568 for (i = 0; i < optlen; ) {
1569 if (op[i] == option) return !invert;
1570 if (op[i] < 2) i++;
1571 else i += op[i+1]?:1;
1572 }
1573
1574 return invert;
1575}
1576
1577static int
1578tcp_match(const struct sk_buff *skb,
1579 const struct net_device *in,
1580 const struct net_device *out,
1581 const void *matchinfo,
1582 int offset,
1583 unsigned int protoff,
1584 int *hotdrop)
1585{
1586 struct tcphdr _tcph, *th;
1587 const struct ip6t_tcp *tcpinfo = matchinfo;
1588
1589 if (offset) {
1590 /* To quote Alan:
1591
1592 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1593 causes this. Its a cracker trying to break in by doing a
1594 flag overwrite to pass the direction checks.
1595 */
1596 if (offset == 1) {
1597 duprintf("Dropping evil TCP offset=1 frag.\n");
1598 *hotdrop = 1;
1599 }
1600 /* Must not be a fragment. */
1601 return 0;
1602 }
1603
1604#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1605
1606 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1607 if (th == NULL) {
1608 /* We've been asked to examine this packet, and we
1609 can't. Hence, no choice but to drop. */
1610 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1611 *hotdrop = 1;
1612 return 0;
1613 }
1614
1615 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1616 ntohs(th->source),
1617 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1618 return 0;
1619 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1620 ntohs(th->dest),
1621 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1622 return 0;
1623 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1624 == tcpinfo->flg_cmp,
1625 IP6T_TCP_INV_FLAGS))
1626 return 0;
1627 if (tcpinfo->option) {
1628 if (th->doff * 4 < sizeof(_tcph)) {
1629 *hotdrop = 1;
1630 return 0;
1631 }
1632 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1633 th->doff*4 - sizeof(*th),
1634 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1635 hotdrop))
1636 return 0;
1637 }
1638 return 1;
1639}
1640
1641/* Called when user tries to insert an entry of this type. */
1642static int
1643tcp_checkentry(const char *tablename,
1644 const struct ip6t_ip6 *ipv6,
1645 void *matchinfo,
1646 unsigned int matchsize,
1647 unsigned int hook_mask)
1648{
1649 const struct ip6t_tcp *tcpinfo = matchinfo;
1650
1651 /* Must specify proto == TCP, and no unknown invflags */
1652 return ipv6->proto == IPPROTO_TCP
1653 && !(ipv6->invflags & IP6T_INV_PROTO)
1654 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1655 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1656}
1657
1658static int
1659udp_match(const struct sk_buff *skb,
1660 const struct net_device *in,
1661 const struct net_device *out,
1662 const void *matchinfo,
1663 int offset,
1664 unsigned int protoff,
1665 int *hotdrop)
1666{
1667 struct udphdr _udph, *uh;
1668 const struct ip6t_udp *udpinfo = matchinfo;
1669
1670 /* Must not be a fragment. */
1671 if (offset)
1672 return 0;
1673
1674 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1675 if (uh == NULL) {
1676 /* We've been asked to examine this packet, and we
1677 can't. Hence, no choice but to drop. */
1678 duprintf("Dropping evil UDP tinygram.\n");
1679 *hotdrop = 1;
1680 return 0;
1681 }
1682
1683 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1684 ntohs(uh->source),
1685 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1686 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1687 ntohs(uh->dest),
1688 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1689}
1690
1691/* Called when user tries to insert an entry of this type. */
1692static int
1693udp_checkentry(const char *tablename,
1694 const struct ip6t_ip6 *ipv6,
1695 void *matchinfo,
1696 unsigned int matchinfosize,
1697 unsigned int hook_mask)
1698{
1699 const struct ip6t_udp *udpinfo = matchinfo;
1700
1701 /* Must specify proto == UDP, and no unknown invflags */
1702 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1703 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1704 IPPROTO_UDP);
1705 return 0;
1706 }
1707 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1708 duprintf("ip6t_udp: matchsize %u != %u\n",
1709 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1710 return 0;
1711 }
1712 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1713 duprintf("ip6t_udp: unknown flags %X\n",
1714 udpinfo->invflags);
1715 return 0;
1716 }
1717
1718 return 1;
1719}
1720
1721/* Returns 1 if the type and code is matched by the range, 0 otherwise */
1722static inline int
1723icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1724 u_int8_t type, u_int8_t code,
1725 int invert)
1726{
1727 return (type == test_type && code >= min_code && code <= max_code)
1728 ^ invert;
1729}
1730
1731static int
1732icmp6_match(const struct sk_buff *skb,
1733 const struct net_device *in,
1734 const struct net_device *out,
1735 const void *matchinfo,
1736 int offset,
1737 unsigned int protoff,
1738 int *hotdrop)
1739{
1740 struct icmp6hdr _icmp, *ic;
1741 const struct ip6t_icmp *icmpinfo = matchinfo;
1742
1743 /* Must not be a fragment. */
1744 if (offset)
1745 return 0;
1746
1747 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1748 if (ic == NULL) {
1749 /* We've been asked to examine this packet, and we
1750 can't. Hence, no choice but to drop. */
1751 duprintf("Dropping evil ICMP tinygram.\n");
1752 *hotdrop = 1;
1753 return 0;
1754 }
1755
1756 return icmp6_type_code_match(icmpinfo->type,
1757 icmpinfo->code[0],
1758 icmpinfo->code[1],
1759 ic->icmp6_type, ic->icmp6_code,
1760 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1761}
1762
1763/* Called when user tries to insert an entry of this type. */
1764static int
1765icmp6_checkentry(const char *tablename,
1766 const struct ip6t_ip6 *ipv6,
1767 void *matchinfo,
1768 unsigned int matchsize,
1769 unsigned int hook_mask)
1770{
1771 const struct ip6t_icmp *icmpinfo = matchinfo;
1772
1773 /* Must specify proto == ICMP, and no unknown invflags */
1774 return ipv6->proto == IPPROTO_ICMPV6
1775 && !(ipv6->invflags & IP6T_INV_PROTO)
1776 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1777 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1778}
1779
1780/* The built-in targets: standard (NULL) and error. */
1781static struct ip6t_target ip6t_standard_target = {
1782 .name = IP6T_STANDARD_TARGET,
1783};
1784
1785static struct ip6t_target ip6t_error_target = {
1786 .name = IP6T_ERROR_TARGET,
1787 .target = ip6t_error,
1788};
1789
1790static struct nf_sockopt_ops ip6t_sockopts = {
1791 .pf = PF_INET6,
1792 .set_optmin = IP6T_BASE_CTL,
1793 .set_optmax = IP6T_SO_SET_MAX+1,
1794 .set = do_ip6t_set_ctl,
1795 .get_optmin = IP6T_BASE_CTL,
1796 .get_optmax = IP6T_SO_GET_MAX+1,
1797 .get = do_ip6t_get_ctl,
1798};
1799
1800static struct ip6t_match tcp_matchstruct = {
1801 .name = "tcp",
1802 .match = &tcp_match,
1803 .checkentry = &tcp_checkentry,
1804};
1805
1806static struct ip6t_match udp_matchstruct = {
1807 .name = "udp",
1808 .match = &udp_match,
1809 .checkentry = &udp_checkentry,
1810};
1811
1812static struct ip6t_match icmp6_matchstruct = {
1813 .name = "icmp6",
1814 .match = &icmp6_match,
1815 .checkentry = &icmp6_checkentry,
1816};
1817
1818#ifdef CONFIG_PROC_FS
1819static inline int print_name(const char *i,
1820 off_t start_offset, char *buffer, int length,
1821 off_t *pos, unsigned int *count)
1822{
1823 if ((*count)++ >= start_offset) {
1824 unsigned int namelen;
1825
1826 namelen = sprintf(buffer + *pos, "%s\n",
1827 i + sizeof(struct list_head));
1828 if (*pos + namelen > length) {
1829 /* Stop iterating */
1830 return 1;
1831 }
1832 *pos += namelen;
1833 }
1834 return 0;
1835}
1836
1837static inline int print_target(const struct ip6t_target *t,
1838 off_t start_offset, char *buffer, int length,
1839 off_t *pos, unsigned int *count)
1840{
1841 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1842 return 0;
1843 return print_name((char *)t, start_offset, buffer, length, pos, count);
1844}
1845
1846static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1847{
1848 off_t pos = 0;
1849 unsigned int count = 0;
1850
1851 if (down_interruptible(&ip6t_mutex) != 0)
1852 return 0;
1853
1854 LIST_FIND(&ip6t_tables, print_name, char *,
1855 offset, buffer, length, &pos, &count);
1856
1857 up(&ip6t_mutex);
1858
1859 /* `start' hack - see fs/proc/generic.c line ~105 */
1860 *start=(char *)((unsigned long)count-offset);
1861 return pos;
1862}
1863
1864static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1865{
1866 off_t pos = 0;
1867 unsigned int count = 0;
1868
1869 if (down_interruptible(&ip6t_mutex) != 0)
1870 return 0;
1871
1872 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
1873 offset, buffer, length, &pos, &count);
1874
1875 up(&ip6t_mutex);
1876
1877 *start = (char *)((unsigned long)count - offset);
1878 return pos;
1879}
1880
1881static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1882{
1883 off_t pos = 0;
1884 unsigned int count = 0;
1885
1886 if (down_interruptible(&ip6t_mutex) != 0)
1887 return 0;
1888
1889 LIST_FIND(&ip6t_match, print_name, char *,
1890 offset, buffer, length, &pos, &count);
1891
1892 up(&ip6t_mutex);
1893
1894 *start = (char *)((unsigned long)count - offset);
1895 return pos;
1896}
1897
1898static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1899{ { "ip6_tables_names", ip6t_get_tables },
1900 { "ip6_tables_targets", ip6t_get_targets },
1901 { "ip6_tables_matches", ip6t_get_matches },
1902 { NULL, NULL} };
1903#endif /*CONFIG_PROC_FS*/
1904
1905static int __init init(void)
1906{
1907 int ret;
1908
1909 /* Noone else will be downing sem now, so we won't sleep */
1910 down(&ip6t_mutex);
1911 list_append(&ip6t_target, &ip6t_standard_target);
1912 list_append(&ip6t_target, &ip6t_error_target);
1913 list_append(&ip6t_match, &tcp_matchstruct);
1914 list_append(&ip6t_match, &udp_matchstruct);
1915 list_append(&ip6t_match, &icmp6_matchstruct);
1916 up(&ip6t_mutex);
1917
1918 /* Register setsockopt */
1919 ret = nf_register_sockopt(&ip6t_sockopts);
1920 if (ret < 0) {
1921 duprintf("Unable to register sockopts.\n");
1922 return ret;
1923 }
1924
1925#ifdef CONFIG_PROC_FS
1926 {
1927 struct proc_dir_entry *proc;
1928 int i;
1929
1930 for (i = 0; ip6t_proc_entry[i].name; i++) {
1931 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1932 ip6t_proc_entry[i].get_info);
1933 if (!proc) {
1934 while (--i >= 0)
1935 proc_net_remove(ip6t_proc_entry[i].name);
1936 nf_unregister_sockopt(&ip6t_sockopts);
1937 return -ENOMEM;
1938 }
1939 proc->owner = THIS_MODULE;
1940 }
1941 }
1942#endif
1943
1944 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1945 return 0;
1946}
1947
1948static void __exit fini(void)
1949{
1950 nf_unregister_sockopt(&ip6t_sockopts);
1951#ifdef CONFIG_PROC_FS
1952 {
1953 int i;
1954 for (i = 0; ip6t_proc_entry[i].name; i++)
1955 proc_net_remove(ip6t_proc_entry[i].name);
1956 }
1957#endif
1958}
1959
1960EXPORT_SYMBOL(ip6t_register_table);
1961EXPORT_SYMBOL(ip6t_unregister_table);
1962EXPORT_SYMBOL(ip6t_do_table);
1963EXPORT_SYMBOL(ip6t_register_match);
1964EXPORT_SYMBOL(ip6t_unregister_match);
1965EXPORT_SYMBOL(ip6t_register_target);
1966EXPORT_SYMBOL(ip6t_unregister_target);
1967EXPORT_SYMBOL(ip6t_ext_hdr);
1968
1969module_init(init);
1970module_exit(fini);