Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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 static 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 */
99 struct 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
116 static LIST_HEAD(ip6t_target);
117 static LIST_HEAD(ip6t_match);
118 static 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
133 static 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 */
146 int 
147 ip6t_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. */
159 static inline int
160 ip6_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 */
297 static inline int 
298 ip6_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
313 static unsigned int
314 ip6t_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
327 static inline
328 int 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
344 static inline struct ip6t_entry *
345 get_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. */
351 unsigned int
352 ip6t_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 */
502 static inline void *
503 find_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
532 static void *
533 find_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
552 static inline struct ip6t_table *
553 ip6t_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
558 static inline struct ip6t_match *
559 find_match_lock(const char *name, int *error, struct semaphore *mutex)
560 {
561         return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
562 }
563
564 static struct ip6t_target *
565 ip6t_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. */
571 static inline int
572 unconditional(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. */
585 static int
586 mark_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
679 static inline int
680 cleanup_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
692 static inline int
693 standard_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
722 static inline int
723 check_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
758 static struct ip6t_target ip6t_standard_target;
759
760 static inline int
761 check_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
821 static inline int
822 check_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
864 static inline int
865 cleanup_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) */
884 static int
885 translate_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
964 static struct ip6t_table_info *
965 replace_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. */
1006 static inline int
1007 add_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
1017 static void
1018 get_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
1034 static int
1035 copy_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
1113 static int
1114 get_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
1141 static int
1142 do_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. */
1243 static inline int
1244 add_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
1263 static int
1264 do_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
1311 static int
1312 do_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
1336 static int
1337 do_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. */
1410 int
1411 ip6t_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
1428 void
1429 ip6t_unregister_target(struct ip6t_target *target)
1430 {
1431         down(&ip6t_mutex);
1432         LIST_DELETE(&ip6t_target, target);
1433         up(&ip6t_mutex);
1434 }
1435
1436 int
1437 ip6t_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
1455 void
1456 ip6t_unregister_match(struct ip6t_match *match)
1457 {
1458         down(&ip6t_mutex);
1459         LIST_DELETE(&ip6t_match, match);
1460         up(&ip6t_mutex);
1461 }
1462
1463 int 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
1523 void 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 */
1536 static inline int
1537 port_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
1545 static int
1546 tcp_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
1577 static int
1578 tcp_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. */
1642 static int
1643 tcp_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
1658 static int
1659 udp_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. */
1692 static int
1693 udp_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 */
1722 static inline int
1723 icmp6_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
1731 static int
1732 icmp6_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. */
1764 static int
1765 icmp6_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. */
1781 static struct ip6t_target ip6t_standard_target = {
1782         .name           = IP6T_STANDARD_TARGET,
1783 };
1784
1785 static struct ip6t_target ip6t_error_target = {
1786         .name           = IP6T_ERROR_TARGET,
1787         .target         = ip6t_error,
1788 };
1789
1790 static 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
1800 static struct ip6t_match tcp_matchstruct = {
1801         .name           = "tcp",
1802         .match          = &tcp_match,
1803         .checkentry     = &tcp_checkentry,
1804 };
1805
1806 static struct ip6t_match udp_matchstruct = {
1807         .name           = "udp",
1808         .match          = &udp_match,
1809         .checkentry     = &udp_checkentry,
1810 };
1811
1812 static struct ip6t_match icmp6_matchstruct = {
1813         .name           = "icmp6",
1814         .match          = &icmp6_match,
1815         .checkentry     = &icmp6_checkentry,
1816 };
1817
1818 #ifdef CONFIG_PROC_FS
1819 static 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
1837 static 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
1846 static 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
1864 static 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
1881 static 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
1898 static 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
1905 static 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
1948 static 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
1960 EXPORT_SYMBOL(ip6t_register_table);
1961 EXPORT_SYMBOL(ip6t_unregister_table);
1962 EXPORT_SYMBOL(ip6t_do_table);
1963 EXPORT_SYMBOL(ip6t_register_match);
1964 EXPORT_SYMBOL(ip6t_unregister_match);
1965 EXPORT_SYMBOL(ip6t_register_target);
1966 EXPORT_SYMBOL(ip6t_unregister_target);
1967 EXPORT_SYMBOL(ip6t_ext_hdr);
1968
1969 module_init(init);
1970 module_exit(fini);