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