[NETFILTER]: make some netfilter globals __read_mostly
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv4 / netfilter / ip_tables.c
CommitLineData
1da177e4
LT
1/*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
2e4e6a17 5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
1da177e4
LT
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
2e4e6a17
HW
14 * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15 * - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
1da177e4 16 */
1da177e4 17#include <linux/cache.h>
4fc268d2 18#include <linux/capability.h>
1da177e4
LT
19#include <linux/skbuff.h>
20#include <linux/kmod.h>
21#include <linux/vmalloc.h>
22#include <linux/netdevice.h>
23#include <linux/module.h>
1da177e4
LT
24#include <linux/icmp.h>
25#include <net/ip.h>
2722971c 26#include <net/compat.h>
1da177e4 27#include <asm/uaccess.h>
57b47a53 28#include <linux/mutex.h>
1da177e4
LT
29#include <linux/proc_fs.h>
30#include <linux/err.h>
c8923c6b 31#include <linux/cpumask.h>
1da177e4 32
2e4e6a17 33#include <linux/netfilter/x_tables.h>
1da177e4
LT
34#include <linux/netfilter_ipv4/ip_tables.h>
35
36MODULE_LICENSE("GPL");
37MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38MODULE_DESCRIPTION("IPv4 packet filter");
39
40/*#define DEBUG_IP_FIREWALL*/
41/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
42/*#define DEBUG_IP_FIREWALL_USER*/
43
44#ifdef DEBUG_IP_FIREWALL
45#define dprintf(format, args...) printk(format , ## args)
46#else
47#define dprintf(format, args...)
48#endif
49
50#ifdef DEBUG_IP_FIREWALL_USER
51#define duprintf(format, args...) printk(format , ## args)
52#else
53#define duprintf(format, args...)
54#endif
55
56#ifdef CONFIG_NETFILTER_DEBUG
57#define IP_NF_ASSERT(x) \
58do { \
59 if (!(x)) \
60 printk("IP_NF_ASSERT: %s:%s:%u\n", \
61 __FUNCTION__, __FILE__, __LINE__); \
62} while(0)
63#else
64#define IP_NF_ASSERT(x)
65#endif
1da177e4
LT
66
67#if 0
68/* All the better to debug you with... */
69#define static
70#define inline
71#endif
72
73/*
74 We keep a set of rules for each CPU, so we can avoid write-locking
75 them in the softirq when updating the counters and therefore
76 only need to read-lock in the softirq; doing a write_lock_bh() in user
77 context stops packets coming through and allows user context to read
78 the counters or update the rules.
79
1da177e4
LT
80 Hence the start of any table is given by get_table() below. */
81
1da177e4
LT
82/* Returns whether matches rule or not. */
83static inline int
84ip_packet_match(const struct iphdr *ip,
85 const char *indev,
86 const char *outdev,
87 const struct ipt_ip *ipinfo,
88 int isfrag)
89{
90 size_t i;
91 unsigned long ret;
92
93#define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
94
95 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
96 IPT_INV_SRCIP)
97 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
98 IPT_INV_DSTIP)) {
99 dprintf("Source or dest mismatch.\n");
100
101 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
102 NIPQUAD(ip->saddr),
103 NIPQUAD(ipinfo->smsk.s_addr),
104 NIPQUAD(ipinfo->src.s_addr),
105 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
106 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
107 NIPQUAD(ip->daddr),
108 NIPQUAD(ipinfo->dmsk.s_addr),
109 NIPQUAD(ipinfo->dst.s_addr),
110 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
111 return 0;
112 }
113
114 /* Look for ifname matches; this should unroll nicely. */
115 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
116 ret |= (((const unsigned long *)indev)[i]
117 ^ ((const unsigned long *)ipinfo->iniface)[i])
118 & ((const unsigned long *)ipinfo->iniface_mask)[i];
119 }
120
121 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
122 dprintf("VIA in mismatch (%s vs %s).%s\n",
123 indev, ipinfo->iniface,
124 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
125 return 0;
126 }
127
128 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
129 ret |= (((const unsigned long *)outdev)[i]
130 ^ ((const unsigned long *)ipinfo->outiface)[i])
131 & ((const unsigned long *)ipinfo->outiface_mask)[i];
132 }
133
134 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
135 dprintf("VIA out mismatch (%s vs %s).%s\n",
136 outdev, ipinfo->outiface,
137 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
138 return 0;
139 }
140
141 /* Check specific protocol */
142 if (ipinfo->proto
143 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
144 dprintf("Packet protocol %hi does not match %hi.%s\n",
145 ip->protocol, ipinfo->proto,
146 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
147 return 0;
148 }
149
150 /* If we have a fragment rule but the packet is not a fragment
151 * then we return zero */
152 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
153 dprintf("Fragment rule but not fragment.%s\n",
154 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
155 return 0;
156 }
157
158 return 1;
159}
160
161static inline int
162ip_checkentry(const struct ipt_ip *ip)
163{
164 if (ip->flags & ~IPT_F_MASK) {
165 duprintf("Unknown flag bits set: %08X\n",
166 ip->flags & ~IPT_F_MASK);
167 return 0;
168 }
169 if (ip->invflags & ~IPT_INV_MASK) {
170 duprintf("Unknown invflag bits set: %08X\n",
171 ip->invflags & ~IPT_INV_MASK);
172 return 0;
173 }
174 return 1;
175}
176
177static unsigned int
178ipt_error(struct sk_buff **pskb,
179 const struct net_device *in,
180 const struct net_device *out,
181 unsigned int hooknum,
c4986734 182 const struct xt_target *target,
fe1cb108 183 const void *targinfo)
1da177e4
LT
184{
185 if (net_ratelimit())
186 printk("ip_tables: error: `%s'\n", (char *)targinfo);
187
188 return NF_DROP;
189}
190
191static inline
192int do_match(struct ipt_entry_match *m,
193 const struct sk_buff *skb,
194 const struct net_device *in,
195 const struct net_device *out,
196 int offset,
197 int *hotdrop)
198{
199 /* Stop iteration if it doesn't match */
1c524830
PM
200 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201 offset, skb->nh.iph->ihl*4, hotdrop))
1da177e4
LT
202 return 1;
203 else
204 return 0;
205}
206
207static inline struct ipt_entry *
208get_entry(void *base, unsigned int offset)
209{
210 return (struct ipt_entry *)(base + offset);
211}
212
213/* Returns one of the generic firewall policies, like NF_ACCEPT. */
214unsigned int
215ipt_do_table(struct sk_buff **pskb,
216 unsigned int hook,
217 const struct net_device *in,
218 const struct net_device *out,
fe1cb108 219 struct ipt_table *table)
1da177e4
LT
220{
221 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
222 u_int16_t offset;
223 struct iphdr *ip;
224 u_int16_t datalen;
225 int hotdrop = 0;
226 /* Initializing verdict to NF_DROP keeps gcc happy. */
227 unsigned int verdict = NF_DROP;
228 const char *indev, *outdev;
229 void *table_base;
230 struct ipt_entry *e, *back;
8311731a 231 struct xt_table_info *private;
1da177e4
LT
232
233 /* Initialization */
234 ip = (*pskb)->nh.iph;
235 datalen = (*pskb)->len - ip->ihl * 4;
236 indev = in ? in->name : nulldevname;
237 outdev = out ? out->name : nulldevname;
238 /* We handle fragments by dealing with the first fragment as
239 * if it was a normal packet. All other fragments are treated
240 * normally, except that they will NEVER match rules that ask
241 * things we don't know, ie. tcp syn flag or ports). If the
242 * rule is also a fragment-specific rule, non-fragments won't
243 * match it. */
244 offset = ntohs(ip->frag_off) & IP_OFFSET;
245
246 read_lock_bh(&table->lock);
247 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
8311731a 248 private = table->private;
2e4e6a17
HW
249 table_base = (void *)private->entries[smp_processor_id()];
250 e = get_entry(table_base, private->hook_entry[hook]);
1da177e4
LT
251
252 /* For return from builtin chain */
2e4e6a17 253 back = get_entry(table_base, private->underflow[hook]);
1da177e4
LT
254
255 do {
256 IP_NF_ASSERT(e);
257 IP_NF_ASSERT(back);
1da177e4
LT
258 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
259 struct ipt_entry_target *t;
260
261 if (IPT_MATCH_ITERATE(e, do_match,
262 *pskb, in, out,
263 offset, &hotdrop) != 0)
264 goto no_match;
265
266 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
267
268 t = ipt_get_target(e);
269 IP_NF_ASSERT(t->u.kernel.target);
270 /* Standard target? */
271 if (!t->u.kernel.target->target) {
272 int v;
273
274 v = ((struct ipt_standard_target *)t)->verdict;
275 if (v < 0) {
276 /* Pop from stack? */
277 if (v != IPT_RETURN) {
278 verdict = (unsigned)(-v) - 1;
279 break;
280 }
281 e = back;
282 back = get_entry(table_base,
283 back->comefrom);
284 continue;
285 }
05465343
PM
286 if (table_base + v != (void *)e + e->next_offset
287 && !(e->ip.flags & IPT_F_GOTO)) {
1da177e4
LT
288 /* Save old back ptr in next entry */
289 struct ipt_entry *next
290 = (void *)e + e->next_offset;
291 next->comefrom
292 = (void *)back - table_base;
293 /* set back pointer to next entry */
294 back = next;
295 }
296
297 e = get_entry(table_base, v);
298 } else {
299 /* Targets which reenter must return
300 abs. verdicts */
301#ifdef CONFIG_NETFILTER_DEBUG
302 ((struct ipt_entry *)table_base)->comefrom
303 = 0xeeeeeeec;
304#endif
305 verdict = t->u.kernel.target->target(pskb,
306 in, out,
307 hook,
1c524830 308 t->u.kernel.target,
fe1cb108 309 t->data);
1da177e4
LT
310
311#ifdef CONFIG_NETFILTER_DEBUG
312 if (((struct ipt_entry *)table_base)->comefrom
313 != 0xeeeeeeec
314 && verdict == IPT_CONTINUE) {
315 printk("Target %s reentered!\n",
316 t->u.kernel.target->name);
317 verdict = NF_DROP;
318 }
319 ((struct ipt_entry *)table_base)->comefrom
320 = 0x57acc001;
321#endif
322 /* Target might have changed stuff. */
323 ip = (*pskb)->nh.iph;
324 datalen = (*pskb)->len - ip->ihl * 4;
325
326 if (verdict == IPT_CONTINUE)
327 e = (void *)e + e->next_offset;
328 else
329 /* Verdict */
330 break;
331 }
332 } else {
333
334 no_match:
335 e = (void *)e + e->next_offset;
336 }
337 } while (!hotdrop);
338
1da177e4
LT
339 read_unlock_bh(&table->lock);
340
341#ifdef DEBUG_ALLOW_ALL
342 return NF_ACCEPT;
343#else
344 if (hotdrop)
345 return NF_DROP;
346 else return verdict;
347#endif
348}
349
1da177e4
LT
350/* All zeroes == unconditional rule. */
351static inline int
352unconditional(const struct ipt_ip *ip)
353{
354 unsigned int i;
355
356 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
357 if (((__u32 *)ip)[i])
358 return 0;
359
360 return 1;
361}
362
363/* Figures out from what hook each rule can be called: returns 0 if
364 there are loops. Puts hook bitmask in comefrom. */
365static int
2e4e6a17 366mark_source_chains(struct xt_table_info *newinfo,
31836064 367 unsigned int valid_hooks, void *entry0)
1da177e4
LT
368{
369 unsigned int hook;
370
371 /* No recursion; use packet counter to save back ptrs (reset
372 to 0 as we leave), and comefrom to save source hook bitmask */
373 for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
374 unsigned int pos = newinfo->hook_entry[hook];
375 struct ipt_entry *e
31836064 376 = (struct ipt_entry *)(entry0 + pos);
1da177e4
LT
377
378 if (!(valid_hooks & (1 << hook)))
379 continue;
380
381 /* Set initial back pointer. */
382 e->counters.pcnt = pos;
383
384 for (;;) {
385 struct ipt_standard_target *t
386 = (void *)ipt_get_target(e);
387
388 if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
389 printk("iptables: loop hook %u pos %u %08X.\n",
390 hook, pos, e->comefrom);
391 return 0;
392 }
393 e->comefrom
394 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
395
396 /* Unconditional return/END. */
397 if (e->target_offset == sizeof(struct ipt_entry)
398 && (strcmp(t->target.u.user.name,
399 IPT_STANDARD_TARGET) == 0)
400 && t->verdict < 0
401 && unconditional(&e->ip)) {
402 unsigned int oldpos, size;
403
404 /* Return: backtrack through the last
405 big jump. */
406 do {
407 e->comefrom ^= (1<<NF_IP_NUMHOOKS);
408#ifdef DEBUG_IP_FIREWALL_USER
409 if (e->comefrom
410 & (1 << NF_IP_NUMHOOKS)) {
411 duprintf("Back unset "
412 "on hook %u "
413 "rule %u\n",
414 hook, pos);
415 }
416#endif
417 oldpos = pos;
418 pos = e->counters.pcnt;
419 e->counters.pcnt = 0;
420
421 /* We're at the start. */
422 if (pos == oldpos)
423 goto next;
424
425 e = (struct ipt_entry *)
31836064 426 (entry0 + pos);
1da177e4
LT
427 } while (oldpos == pos + e->next_offset);
428
429 /* Move along one */
430 size = e->next_offset;
431 e = (struct ipt_entry *)
31836064 432 (entry0 + pos + size);
1da177e4
LT
433 e->counters.pcnt = pos;
434 pos += size;
435 } else {
436 int newpos = t->verdict;
437
438 if (strcmp(t->target.u.user.name,
439 IPT_STANDARD_TARGET) == 0
440 && newpos >= 0) {
441 /* This a jump; chase it. */
442 duprintf("Jump rule %u -> %u\n",
443 pos, newpos);
444 } else {
445 /* ... this is a fallthru */
446 newpos = pos + e->next_offset;
447 }
448 e = (struct ipt_entry *)
31836064 449 (entry0 + newpos);
1da177e4
LT
450 e->counters.pcnt = pos;
451 pos = newpos;
452 }
453 }
454 next:
455 duprintf("Finished chain %u\n", hook);
456 }
457 return 1;
458}
459
460static inline int
461cleanup_match(struct ipt_entry_match *m, unsigned int *i)
462{
463 if (i && (*i)-- == 0)
464 return 1;
465
466 if (m->u.kernel.match->destroy)
efa74165 467 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
1da177e4
LT
468 module_put(m->u.kernel.match->me);
469 return 0;
470}
471
472static inline int
473standard_check(const struct ipt_entry_target *t,
474 unsigned int max_offset)
475{
476 struct ipt_standard_target *targ = (void *)t;
477
478 /* Check standard info. */
1da177e4
LT
479 if (targ->verdict >= 0
480 && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
481 duprintf("ipt_standard_check: bad verdict (%i)\n",
482 targ->verdict);
483 return 0;
484 }
1da177e4
LT
485 if (targ->verdict < -NF_MAX_VERDICT - 1) {
486 duprintf("ipt_standard_check: bad negative verdict (%i)\n",
487 targ->verdict);
488 return 0;
489 }
490 return 1;
491}
492
493static inline int
494check_match(struct ipt_entry_match *m,
495 const char *name,
496 const struct ipt_ip *ip,
497 unsigned int hookmask,
498 unsigned int *i)
499{
500 struct ipt_match *match;
3cdc7c95 501 int ret;
1da177e4 502
2e4e6a17 503 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1da177e4
LT
504 m->u.user.revision),
505 "ipt_%s", m->u.user.name);
506 if (IS_ERR(match) || !match) {
507 duprintf("check_match: `%s' not found\n", m->u.user.name);
508 return match ? PTR_ERR(match) : -ENOENT;
509 }
510 m->u.kernel.match = match;
511
3cdc7c95
PM
512 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
513 name, hookmask, ip->proto,
514 ip->invflags & IPT_INV_PROTO);
515 if (ret)
516 goto err;
517
1da177e4 518 if (m->u.kernel.match->checkentry
1c524830 519 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
1da177e4 520 hookmask)) {
1da177e4
LT
521 duprintf("ip_tables: check failed for `%s'.\n",
522 m->u.kernel.match->name);
3cdc7c95
PM
523 ret = -EINVAL;
524 goto err;
1da177e4
LT
525 }
526
527 (*i)++;
528 return 0;
3cdc7c95
PM
529err:
530 module_put(m->u.kernel.match->me);
531 return ret;
1da177e4
LT
532}
533
534static struct ipt_target ipt_standard_target;
535
536static inline int
537check_entry(struct ipt_entry *e, const char *name, unsigned int size,
538 unsigned int *i)
539{
540 struct ipt_entry_target *t;
541 struct ipt_target *target;
542 int ret;
543 unsigned int j;
544
545 if (!ip_checkentry(&e->ip)) {
546 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
547 return -EINVAL;
548 }
549
550 j = 0;
551 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
552 if (ret != 0)
553 goto cleanup_matches;
554
555 t = ipt_get_target(e);
2e4e6a17
HW
556 target = try_then_request_module(xt_find_target(AF_INET,
557 t->u.user.name,
1da177e4
LT
558 t->u.user.revision),
559 "ipt_%s", t->u.user.name);
560 if (IS_ERR(target) || !target) {
561 duprintf("check_entry: `%s' not found\n", t->u.user.name);
562 ret = target ? PTR_ERR(target) : -ENOENT;
563 goto cleanup_matches;
564 }
565 t->u.kernel.target = target;
566
3cdc7c95
PM
567 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
568 name, e->comefrom, e->ip.proto,
569 e->ip.invflags & IPT_INV_PROTO);
570 if (ret)
571 goto err;
572
1da177e4
LT
573 if (t->u.kernel.target == &ipt_standard_target) {
574 if (!standard_check(t, size)) {
575 ret = -EINVAL;
90d47db4 576 goto err;
1da177e4
LT
577 }
578 } else if (t->u.kernel.target->checkentry
1c524830 579 && !t->u.kernel.target->checkentry(name, e, target, t->data,
1da177e4 580 e->comefrom)) {
1da177e4
LT
581 duprintf("ip_tables: check failed for `%s'.\n",
582 t->u.kernel.target->name);
583 ret = -EINVAL;
3cdc7c95 584 goto err;
1da177e4
LT
585 }
586
587 (*i)++;
588 return 0;
3cdc7c95
PM
589 err:
590 module_put(t->u.kernel.target->me);
1da177e4
LT
591 cleanup_matches:
592 IPT_MATCH_ITERATE(e, cleanup_match, &j);
593 return ret;
594}
595
596static inline int
597check_entry_size_and_hooks(struct ipt_entry *e,
2e4e6a17 598 struct xt_table_info *newinfo,
1da177e4
LT
599 unsigned char *base,
600 unsigned char *limit,
601 const unsigned int *hook_entries,
602 const unsigned int *underflows,
603 unsigned int *i)
604{
605 unsigned int h;
606
607 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
608 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
609 duprintf("Bad offset %p\n", e);
610 return -EINVAL;
611 }
612
613 if (e->next_offset
614 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
615 duprintf("checking: element %p size %u\n",
616 e, e->next_offset);
617 return -EINVAL;
618 }
619
620 /* Check hooks & underflows */
621 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
622 if ((unsigned char *)e - base == hook_entries[h])
623 newinfo->hook_entry[h] = hook_entries[h];
624 if ((unsigned char *)e - base == underflows[h])
625 newinfo->underflow[h] = underflows[h];
626 }
627
628 /* FIXME: underflows must be unconditional, standard verdicts
629 < 0 (not IPT_RETURN). --RR */
630
631 /* Clear counters and comefrom */
2e4e6a17 632 e->counters = ((struct xt_counters) { 0, 0 });
1da177e4
LT
633 e->comefrom = 0;
634
635 (*i)++;
636 return 0;
637}
638
639static inline int
640cleanup_entry(struct ipt_entry *e, unsigned int *i)
641{
642 struct ipt_entry_target *t;
643
644 if (i && (*i)-- == 0)
645 return 1;
646
647 /* Cleanup all matches */
648 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
649 t = ipt_get_target(e);
650 if (t->u.kernel.target->destroy)
efa74165 651 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
1da177e4
LT
652 module_put(t->u.kernel.target->me);
653 return 0;
654}
655
656/* Checks and translates the user-supplied table segment (held in
657 newinfo) */
658static int
659translate_table(const char *name,
660 unsigned int valid_hooks,
2e4e6a17 661 struct xt_table_info *newinfo,
31836064 662 void *entry0,
1da177e4
LT
663 unsigned int size,
664 unsigned int number,
665 const unsigned int *hook_entries,
666 const unsigned int *underflows)
667{
668 unsigned int i;
669 int ret;
670
671 newinfo->size = size;
672 newinfo->number = number;
673
674 /* Init all hooks to impossible value. */
675 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
676 newinfo->hook_entry[i] = 0xFFFFFFFF;
677 newinfo->underflow[i] = 0xFFFFFFFF;
678 }
679
680 duprintf("translate_table: size %u\n", newinfo->size);
681 i = 0;
682 /* Walk through entries, checking offsets. */
31836064 683 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
684 check_entry_size_and_hooks,
685 newinfo,
31836064
ED
686 entry0,
687 entry0 + size,
1da177e4
LT
688 hook_entries, underflows, &i);
689 if (ret != 0)
690 return ret;
691
692 if (i != number) {
693 duprintf("translate_table: %u not %u entries\n",
694 i, number);
695 return -EINVAL;
696 }
697
698 /* Check hooks all assigned */
699 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
700 /* Only hooks which are valid */
701 if (!(valid_hooks & (1 << i)))
702 continue;
703 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
704 duprintf("Invalid hook entry %u %u\n",
705 i, hook_entries[i]);
706 return -EINVAL;
707 }
708 if (newinfo->underflow[i] == 0xFFFFFFFF) {
709 duprintf("Invalid underflow %u %u\n",
710 i, underflows[i]);
711 return -EINVAL;
712 }
713 }
714
31836064 715 if (!mark_source_chains(newinfo, valid_hooks, entry0))
1da177e4
LT
716 return -ELOOP;
717
718 /* Finally, each sanity check must pass */
719 i = 0;
31836064 720 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
721 check_entry, name, size, &i);
722
723 if (ret != 0) {
31836064 724 IPT_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
725 cleanup_entry, &i);
726 return ret;
727 }
728
729 /* And one copy for every other CPU */
6f912042 730 for_each_possible_cpu(i) {
31836064
ED
731 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
732 memcpy(newinfo->entries[i], entry0, newinfo->size);
1da177e4
LT
733 }
734
735 return ret;
736}
737
1da177e4
LT
738/* Gets counters. */
739static inline int
740add_entry_to_counter(const struct ipt_entry *e,
2e4e6a17 741 struct xt_counters total[],
1da177e4
LT
742 unsigned int *i)
743{
744 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
745
746 (*i)++;
747 return 0;
748}
749
31836064
ED
750static inline int
751set_entry_to_counter(const struct ipt_entry *e,
752 struct ipt_counters total[],
753 unsigned int *i)
754{
755 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
756
757 (*i)++;
758 return 0;
759}
760
1da177e4 761static void
2e4e6a17
HW
762get_counters(const struct xt_table_info *t,
763 struct xt_counters counters[])
1da177e4
LT
764{
765 unsigned int cpu;
766 unsigned int i;
31836064
ED
767 unsigned int curcpu;
768
769 /* Instead of clearing (by a previous call to memset())
770 * the counters and using adds, we set the counters
771 * with data used by 'current' CPU
772 * We dont care about preemption here.
773 */
774 curcpu = raw_smp_processor_id();
775
776 i = 0;
777 IPT_ENTRY_ITERATE(t->entries[curcpu],
778 t->size,
779 set_entry_to_counter,
780 counters,
781 &i);
1da177e4 782
6f912042 783 for_each_possible_cpu(cpu) {
31836064
ED
784 if (cpu == curcpu)
785 continue;
1da177e4 786 i = 0;
31836064 787 IPT_ENTRY_ITERATE(t->entries[cpu],
1da177e4
LT
788 t->size,
789 add_entry_to_counter,
790 counters,
791 &i);
792 }
793}
794
2722971c 795static inline struct xt_counters * alloc_counters(struct ipt_table *table)
1da177e4 796{
2722971c 797 unsigned int countersize;
2e4e6a17
HW
798 struct xt_counters *counters;
799 struct xt_table_info *private = table->private;
1da177e4
LT
800
801 /* We need atomic snapshot of counters: rest doesn't change
802 (other than comefrom, which userspace doesn't care
803 about). */
2e4e6a17 804 countersize = sizeof(struct xt_counters) * private->number;
31836064 805 counters = vmalloc_node(countersize, numa_node_id());
1da177e4
LT
806
807 if (counters == NULL)
2722971c 808 return ERR_PTR(-ENOMEM);
1da177e4
LT
809
810 /* First, sum counters... */
1da177e4 811 write_lock_bh(&table->lock);
2e4e6a17 812 get_counters(private, counters);
1da177e4
LT
813 write_unlock_bh(&table->lock);
814
2722971c
DM
815 return counters;
816}
817
818static int
819copy_entries_to_user(unsigned int total_size,
820 struct ipt_table *table,
821 void __user *userptr)
822{
823 unsigned int off, num;
824 struct ipt_entry *e;
825 struct xt_counters *counters;
826 struct xt_table_info *private = table->private;
827 int ret = 0;
828 void *loc_cpu_entry;
829
830 counters = alloc_counters(table);
831 if (IS_ERR(counters))
832 return PTR_ERR(counters);
833
31836064
ED
834 /* choose the copy that is on our node/cpu, ...
835 * This choice is lazy (because current thread is
836 * allowed to migrate to another cpu)
837 */
2e4e6a17 838 loc_cpu_entry = private->entries[raw_smp_processor_id()];
31836064
ED
839 /* ... then copy entire thing ... */
840 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1da177e4
LT
841 ret = -EFAULT;
842 goto free_counters;
843 }
844
845 /* FIXME: use iterator macros --RR */
846 /* ... then go back and fix counters and names */
847 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
848 unsigned int i;
849 struct ipt_entry_match *m;
850 struct ipt_entry_target *t;
851
31836064 852 e = (struct ipt_entry *)(loc_cpu_entry + off);
1da177e4
LT
853 if (copy_to_user(userptr + off
854 + offsetof(struct ipt_entry, counters),
855 &counters[num],
856 sizeof(counters[num])) != 0) {
857 ret = -EFAULT;
858 goto free_counters;
859 }
860
861 for (i = sizeof(struct ipt_entry);
862 i < e->target_offset;
863 i += m->u.match_size) {
864 m = (void *)e + i;
865
866 if (copy_to_user(userptr + off + i
867 + offsetof(struct ipt_entry_match,
868 u.user.name),
869 m->u.kernel.match->name,
870 strlen(m->u.kernel.match->name)+1)
871 != 0) {
872 ret = -EFAULT;
873 goto free_counters;
874 }
875 }
876
877 t = ipt_get_target(e);
878 if (copy_to_user(userptr + off + e->target_offset
879 + offsetof(struct ipt_entry_target,
880 u.user.name),
881 t->u.kernel.target->name,
882 strlen(t->u.kernel.target->name)+1) != 0) {
883 ret = -EFAULT;
884 goto free_counters;
885 }
886 }
887
888 free_counters:
889 vfree(counters);
890 return ret;
891}
892
2722971c
DM
893#ifdef CONFIG_COMPAT
894struct compat_delta {
895 struct compat_delta *next;
896 u_int16_t offset;
897 short delta;
898};
899
900static struct compat_delta *compat_offsets = NULL;
901
902static int compat_add_offset(u_int16_t offset, short delta)
903{
904 struct compat_delta *tmp;
905
906 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
907 if (!tmp)
908 return -ENOMEM;
909 tmp->offset = offset;
910 tmp->delta = delta;
911 if (compat_offsets) {
912 tmp->next = compat_offsets->next;
913 compat_offsets->next = tmp;
914 } else {
915 compat_offsets = tmp;
916 tmp->next = NULL;
917 }
918 return 0;
919}
920
921static void compat_flush_offsets(void)
922{
923 struct compat_delta *tmp, *next;
924
925 if (compat_offsets) {
926 for(tmp = compat_offsets; tmp; tmp = next) {
927 next = tmp->next;
928 kfree(tmp);
929 }
930 compat_offsets = NULL;
931 }
932}
933
934static short compat_calc_jump(u_int16_t offset)
935{
936 struct compat_delta *tmp;
937 short delta;
938
939 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
940 if (tmp->offset < offset)
941 delta += tmp->delta;
942 return delta;
943}
944
945struct compat_ipt_standard_target
946{
947 struct compat_xt_entry_target target;
948 compat_int_t verdict;
949};
950
2722971c
DM
951struct compat_ipt_standard
952{
953 struct compat_ipt_entry entry;
954 struct compat_ipt_standard_target target;
955};
956
46c5ea3c
PM
957#define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target))
958#define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target))
959#define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN)
960
2722971c
DM
961static int compat_ipt_standard_fn(void *target,
962 void **dstptr, int *size, int convert)
963{
964 struct compat_ipt_standard_target compat_st, *pcompat_st;
965 struct ipt_standard_target st, *pst;
966 int ret;
967
968 ret = 0;
969 switch (convert) {
970 case COMPAT_TO_USER:
46c5ea3c 971 pst = target;
2722971c 972 memcpy(&compat_st.target, &pst->target,
46c5ea3c 973 sizeof(compat_st.target));
2722971c
DM
974 compat_st.verdict = pst->verdict;
975 if (compat_st.verdict > 0)
976 compat_st.verdict -=
977 compat_calc_jump(compat_st.verdict);
46c5ea3c
PM
978 compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN;
979 if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN))
2722971c
DM
980 ret = -EFAULT;
981 *size -= IPT_ST_OFFSET;
46c5ea3c 982 *dstptr += IPT_ST_COMPAT_LEN;
2722971c
DM
983 break;
984 case COMPAT_FROM_USER:
46c5ea3c
PM
985 pcompat_st = target;
986 memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN);
2722971c
DM
987 st.verdict = pcompat_st->verdict;
988 if (st.verdict > 0)
989 st.verdict += compat_calc_jump(st.verdict);
46c5ea3c
PM
990 st.target.u.user.target_size = IPT_ST_LEN;
991 memcpy(*dstptr, &st, IPT_ST_LEN);
2722971c 992 *size += IPT_ST_OFFSET;
46c5ea3c 993 *dstptr += IPT_ST_LEN;
2722971c
DM
994 break;
995 case COMPAT_CALC_SIZE:
996 *size += IPT_ST_OFFSET;
997 break;
998 default:
999 ret = -ENOPROTOOPT;
1000 break;
1001 }
1002 return ret;
1003}
1004
1005static inline int
1006compat_calc_match(struct ipt_entry_match *m, int * size)
1007{
1008 if (m->u.kernel.match->compat)
1009 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1010 else
1011 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1012 return 0;
1013}
1014
1015static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
1016 void *base, struct xt_table_info *newinfo)
1017{
1018 struct ipt_entry_target *t;
1019 u_int16_t entry_offset;
1020 int off, i, ret;
1021
1022 off = 0;
1023 entry_offset = (void *)e - base;
1024 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1025 t = ipt_get_target(e);
1026 if (t->u.kernel.target->compat)
1027 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1028 else
1029 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1030 newinfo->size -= off;
1031 ret = compat_add_offset(entry_offset, off);
1032 if (ret)
1033 return ret;
1034
1035 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
1036 if (info->hook_entry[i] && (e < (struct ipt_entry *)
1037 (base + info->hook_entry[i])))
1038 newinfo->hook_entry[i] -= off;
1039 if (info->underflow[i] && (e < (struct ipt_entry *)
1040 (base + info->underflow[i])))
1041 newinfo->underflow[i] -= off;
1042 }
1043 return 0;
1044}
1045
1046static int compat_table_info(struct xt_table_info *info,
1047 struct xt_table_info *newinfo)
1048{
1049 void *loc_cpu_entry;
1050 int i;
1051
1052 if (!newinfo || !info)
1053 return -EINVAL;
1054
1055 memset(newinfo, 0, sizeof(struct xt_table_info));
1056 newinfo->size = info->size;
1057 newinfo->number = info->number;
1058 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1059 newinfo->hook_entry[i] = info->hook_entry[i];
1060 newinfo->underflow[i] = info->underflow[i];
1061 }
1062 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1063 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1064 compat_calc_entry, info, loc_cpu_entry, newinfo);
1065}
1066#endif
1067
1068static int get_info(void __user *user, int *len, int compat)
1069{
1070 char name[IPT_TABLE_MAXNAMELEN];
1071 struct ipt_table *t;
1072 int ret;
1073
1074 if (*len != sizeof(struct ipt_getinfo)) {
1075 duprintf("length %u != %u\n", *len,
1076 (unsigned int)sizeof(struct ipt_getinfo));
1077 return -EINVAL;
1078 }
1079
1080 if (copy_from_user(name, user, sizeof(name)) != 0)
1081 return -EFAULT;
1082
1083 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1084#ifdef CONFIG_COMPAT
1085 if (compat)
1086 xt_compat_lock(AF_INET);
1087#endif
1088 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1089 "iptable_%s", name);
1090 if (t && !IS_ERR(t)) {
1091 struct ipt_getinfo info;
1092 struct xt_table_info *private = t->private;
1093
1094#ifdef CONFIG_COMPAT
1095 if (compat) {
1096 struct xt_table_info tmp;
1097 ret = compat_table_info(private, &tmp);
1098 compat_flush_offsets();
1099 private = &tmp;
1100 }
1101#endif
1102 info.valid_hooks = t->valid_hooks;
1103 memcpy(info.hook_entry, private->hook_entry,
1104 sizeof(info.hook_entry));
1105 memcpy(info.underflow, private->underflow,
1106 sizeof(info.underflow));
1107 info.num_entries = private->number;
1108 info.size = private->size;
1109 strcpy(info.name, name);
1110
1111 if (copy_to_user(user, &info, *len) != 0)
1112 ret = -EFAULT;
1113 else
1114 ret = 0;
1115
1116 xt_table_unlock(t);
1117 module_put(t->me);
1118 } else
1119 ret = t ? PTR_ERR(t) : -ENOENT;
1120#ifdef CONFIG_COMPAT
1121 if (compat)
1122 xt_compat_unlock(AF_INET);
1123#endif
1124 return ret;
1125}
1126
1127static int
1128get_entries(struct ipt_get_entries __user *uptr, int *len)
1129{
1130 int ret;
1131 struct ipt_get_entries get;
1132 struct ipt_table *t;
1133
1134 if (*len < sizeof(get)) {
1135 duprintf("get_entries: %u < %d\n", *len,
1136 (unsigned int)sizeof(get));
1137 return -EINVAL;
1138 }
1139 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1140 return -EFAULT;
1141 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1142 duprintf("get_entries: %u != %u\n", *len,
1143 (unsigned int)(sizeof(struct ipt_get_entries) +
1144 get.size));
1145 return -EINVAL;
1146 }
1147
1148 t = xt_find_table_lock(AF_INET, get.name);
1149 if (t && !IS_ERR(t)) {
1150 struct xt_table_info *private = t->private;
1151 duprintf("t->private->number = %u\n",
1152 private->number);
1153 if (get.size == private->size)
1154 ret = copy_entries_to_user(private->size,
1155 t, uptr->entrytable);
1156 else {
1157 duprintf("get_entries: I've got %u not %u!\n",
1158 private->size,
1159 get.size);
1160 ret = -EINVAL;
1161 }
1162 module_put(t->me);
1163 xt_table_unlock(t);
1164 } else
1165 ret = t ? PTR_ERR(t) : -ENOENT;
1166
1167 return ret;
1168}
1169
1170static int
1171__do_replace(const char *name, unsigned int valid_hooks,
1172 struct xt_table_info *newinfo, unsigned int num_counters,
1173 void __user *counters_ptr)
1174{
1175 int ret;
1176 struct ipt_table *t;
1177 struct xt_table_info *oldinfo;
1178 struct xt_counters *counters;
1179 void *loc_cpu_old_entry;
1180
1181 ret = 0;
1182 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1183 if (!counters) {
1184 ret = -ENOMEM;
1185 goto out;
1186 }
1187
1188 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1189 "iptable_%s", name);
1190 if (!t || IS_ERR(t)) {
1191 ret = t ? PTR_ERR(t) : -ENOENT;
1192 goto free_newinfo_counters_untrans;
1193 }
1194
1195 /* You lied! */
1196 if (valid_hooks != t->valid_hooks) {
1197 duprintf("Valid hook crap: %08X vs %08X\n",
1198 valid_hooks, t->valid_hooks);
1199 ret = -EINVAL;
1200 goto put_module;
1201 }
1202
1203 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1204 if (!oldinfo)
1205 goto put_module;
1206
1207 /* Update module usage count based on number of rules */
1208 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1209 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1210 if ((oldinfo->number > oldinfo->initial_entries) ||
1211 (newinfo->number <= oldinfo->initial_entries))
1212 module_put(t->me);
1213 if ((oldinfo->number > oldinfo->initial_entries) &&
1214 (newinfo->number <= oldinfo->initial_entries))
1215 module_put(t->me);
1216
1217 /* Get the old counters. */
1218 get_counters(oldinfo, counters);
1219 /* Decrease module usage counts and free resource */
1220 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1221 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1222 xt_free_table_info(oldinfo);
1223 if (copy_to_user(counters_ptr, counters,
1224 sizeof(struct xt_counters) * num_counters) != 0)
1225 ret = -EFAULT;
1226 vfree(counters);
1227 xt_table_unlock(t);
1228 return ret;
1229
1230 put_module:
1231 module_put(t->me);
1232 xt_table_unlock(t);
1233 free_newinfo_counters_untrans:
1234 vfree(counters);
1235 out:
1236 return ret;
1237}
1238
1239static int
1240do_replace(void __user *user, unsigned int len)
1241{
1242 int ret;
1243 struct ipt_replace tmp;
1244 struct xt_table_info *newinfo;
1245 void *loc_cpu_entry;
1246
1247 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1248 return -EFAULT;
1249
1250 /* Hack: Causes ipchains to give correct error msg --RR */
1251 if (len != sizeof(tmp) + tmp.size)
1252 return -ENOPROTOOPT;
1253
1254 /* overflow check */
1255 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1256 SMP_CACHE_BYTES)
1257 return -ENOMEM;
1258 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1259 return -ENOMEM;
1260
1261 newinfo = xt_alloc_table_info(tmp.size);
1262 if (!newinfo)
1263 return -ENOMEM;
1264
1265 /* choose the copy that is our node/cpu */
1266 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1267 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1268 tmp.size) != 0) {
1269 ret = -EFAULT;
1270 goto free_newinfo;
1271 }
1272
1273 ret = translate_table(tmp.name, tmp.valid_hooks,
1274 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1275 tmp.hook_entry, tmp.underflow);
1276 if (ret != 0)
1277 goto free_newinfo;
1278
1279 duprintf("ip_tables: Translated table\n");
1280
1281 ret = __do_replace(tmp.name, tmp.valid_hooks,
1282 newinfo, tmp.num_counters,
1283 tmp.counters);
1284 if (ret)
1285 goto free_newinfo_untrans;
1286 return 0;
1287
1288 free_newinfo_untrans:
1289 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1290 free_newinfo:
1291 xt_free_table_info(newinfo);
1292 return ret;
1293}
1294
1295/* We're lazy, and add to the first CPU; overflow works its fey magic
1296 * and everything is OK. */
1297static inline int
1298add_counter_to_entry(struct ipt_entry *e,
1299 const struct xt_counters addme[],
1300 unsigned int *i)
1301{
1302#if 0
1303 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1304 *i,
1305 (long unsigned int)e->counters.pcnt,
1306 (long unsigned int)e->counters.bcnt,
1307 (long unsigned int)addme[*i].pcnt,
1308 (long unsigned int)addme[*i].bcnt);
1309#endif
1310
1311 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1312
1313 (*i)++;
1314 return 0;
1315}
1316
1317static int
1318do_add_counters(void __user *user, unsigned int len, int compat)
1319{
1320 unsigned int i;
1321 struct xt_counters_info tmp;
1322 struct xt_counters *paddc;
1323 unsigned int num_counters;
1324 char *name;
1325 int size;
1326 void *ptmp;
1327 struct ipt_table *t;
1328 struct xt_table_info *private;
1329 int ret = 0;
1330 void *loc_cpu_entry;
1331#ifdef CONFIG_COMPAT
1332 struct compat_xt_counters_info compat_tmp;
1333
1334 if (compat) {
1335 ptmp = &compat_tmp;
1336 size = sizeof(struct compat_xt_counters_info);
1337 } else
1338#endif
1339 {
1340 ptmp = &tmp;
1341 size = sizeof(struct xt_counters_info);
1342 }
1343
1344 if (copy_from_user(ptmp, user, size) != 0)
1345 return -EFAULT;
1346
1347#ifdef CONFIG_COMPAT
1348 if (compat) {
1349 num_counters = compat_tmp.num_counters;
1350 name = compat_tmp.name;
1351 } else
1352#endif
1353 {
1354 num_counters = tmp.num_counters;
1355 name = tmp.name;
1356 }
1357
1358 if (len != size + num_counters * sizeof(struct xt_counters))
1359 return -EINVAL;
1360
1361 paddc = vmalloc_node(len - size, numa_node_id());
1362 if (!paddc)
1363 return -ENOMEM;
1364
1365 if (copy_from_user(paddc, user + size, len - size) != 0) {
1366 ret = -EFAULT;
1367 goto free;
1368 }
1369
1370 t = xt_find_table_lock(AF_INET, name);
1371 if (!t || IS_ERR(t)) {
1372 ret = t ? PTR_ERR(t) : -ENOENT;
1373 goto free;
1374 }
1375
1376 write_lock_bh(&t->lock);
1377 private = t->private;
1378 if (private->number != num_counters) {
1379 ret = -EINVAL;
1380 goto unlock_up_free;
1381 }
1382
1383 i = 0;
1384 /* Choose the copy that is on our node */
1385 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1386 IPT_ENTRY_ITERATE(loc_cpu_entry,
1387 private->size,
1388 add_counter_to_entry,
1389 paddc,
1390 &i);
1391 unlock_up_free:
1392 write_unlock_bh(&t->lock);
1393 xt_table_unlock(t);
1394 module_put(t->me);
1395 free:
1396 vfree(paddc);
1397
1398 return ret;
1399}
1400
1401#ifdef CONFIG_COMPAT
1402struct compat_ipt_replace {
1403 char name[IPT_TABLE_MAXNAMELEN];
1404 u32 valid_hooks;
1405 u32 num_entries;
1406 u32 size;
1407 u32 hook_entry[NF_IP_NUMHOOKS];
1408 u32 underflow[NF_IP_NUMHOOKS];
1409 u32 num_counters;
1410 compat_uptr_t counters; /* struct ipt_counters * */
1411 struct compat_ipt_entry entries[0];
1412};
1413
1414static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1415 void __user **dstptr, compat_uint_t *size)
1416{
1417 if (m->u.kernel.match->compat)
1418 return m->u.kernel.match->compat(m, dstptr, size,
1419 COMPAT_TO_USER);
1420 else
1421 return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
1422}
1423
1424static int compat_copy_entry_to_user(struct ipt_entry *e,
1425 void __user **dstptr, compat_uint_t *size)
1426{
1427 struct ipt_entry_target __user *t;
1428 struct compat_ipt_entry __user *ce;
1429 u_int16_t target_offset, next_offset;
1430 compat_uint_t origsize;
1431 int ret;
1432
1433 ret = -EFAULT;
1434 origsize = *size;
1435 ce = (struct compat_ipt_entry __user *)*dstptr;
7800007c 1436 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
2722971c
DM
1437 goto out;
1438
1439 *dstptr += sizeof(struct compat_ipt_entry);
1440 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1441 target_offset = e->target_offset - (origsize - *size);
1442 if (ret)
1443 goto out;
1444 t = ipt_get_target(e);
1445 if (t->u.kernel.target->compat)
1446 ret = t->u.kernel.target->compat(t, dstptr, size,
1447 COMPAT_TO_USER);
1448 else
1449 ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
1450 if (ret)
1451 goto out;
1452 ret = -EFAULT;
1453 next_offset = e->next_offset - (origsize - *size);
7800007c 1454 if (put_user(target_offset, &ce->target_offset))
2722971c 1455 goto out;
7800007c 1456 if (put_user(next_offset, &ce->next_offset))
2722971c
DM
1457 goto out;
1458 return 0;
1459out:
1460 return ret;
1461}
1462
1463static inline int
1464compat_check_calc_match(struct ipt_entry_match *m,
1465 const char *name,
1466 const struct ipt_ip *ip,
1467 unsigned int hookmask,
1468 int *size, int *i)
1469{
1470 struct ipt_match *match;
1471
1472 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1473 m->u.user.revision),
1474 "ipt_%s", m->u.user.name);
1475 if (IS_ERR(match) || !match) {
1476 duprintf("compat_check_calc_match: `%s' not found\n",
1477 m->u.user.name);
1478 return match ? PTR_ERR(match) : -ENOENT;
1479 }
1480 m->u.kernel.match = match;
1481
1482 if (m->u.kernel.match->compat)
1483 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1484 else
1485 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1486
1487 (*i)++;
1488 return 0;
1489}
1490
1491static inline int
1492check_compat_entry_size_and_hooks(struct ipt_entry *e,
1493 struct xt_table_info *newinfo,
1494 unsigned int *size,
1495 unsigned char *base,
1496 unsigned char *limit,
1497 unsigned int *hook_entries,
1498 unsigned int *underflows,
1499 unsigned int *i,
1500 const char *name)
1501{
1502 struct ipt_entry_target *t;
1503 struct ipt_target *target;
1504 u_int16_t entry_offset;
1505 int ret, off, h, j;
1506
1507 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1508 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1509 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1510 duprintf("Bad offset %p, limit = %p\n", e, limit);
1511 return -EINVAL;
1512 }
1513
1514 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1515 sizeof(struct compat_xt_entry_target)) {
1516 duprintf("checking: element %p size %u\n",
1517 e, e->next_offset);
1518 return -EINVAL;
1519 }
1520
1521 if (!ip_checkentry(&e->ip)) {
1522 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1523 return -EINVAL;
1524 }
1525
1526 off = 0;
1527 entry_offset = (void *)e - (void *)base;
1528 j = 0;
1529 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1530 e->comefrom, &off, &j);
1531 if (ret != 0)
1532 goto out;
1533
1534 t = ipt_get_target(e);
1535 target = try_then_request_module(xt_find_target(AF_INET,
1536 t->u.user.name,
1537 t->u.user.revision),
1538 "ipt_%s", t->u.user.name);
1539 if (IS_ERR(target) || !target) {
1540 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1541 ret = target ? PTR_ERR(target) : -ENOENT;
1542 goto out;
1543 }
1544 t->u.kernel.target = target;
1545
1546 if (t->u.kernel.target->compat)
1547 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1548 else
1549 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1550 *size += off;
1551 ret = compat_add_offset(entry_offset, off);
1552 if (ret)
1553 goto out;
1554
1555 /* Check hooks & underflows */
1556 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1557 if ((unsigned char *)e - base == hook_entries[h])
1558 newinfo->hook_entry[h] = hook_entries[h];
1559 if ((unsigned char *)e - base == underflows[h])
1560 newinfo->underflow[h] = underflows[h];
1561 }
1562
1563 /* Clear counters and comefrom */
1564 e->counters = ((struct ipt_counters) { 0, 0 });
1565 e->comefrom = 0;
1566
1567 (*i)++;
1568 return 0;
1569out:
1570 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1571 return ret;
1572}
1573
1574static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1575 void **dstptr, compat_uint_t *size, const char *name,
1576 const struct ipt_ip *ip, unsigned int hookmask)
1577{
1578 struct ipt_entry_match *dm;
1579 struct ipt_match *match;
1580 int ret;
1581
1582 dm = (struct ipt_entry_match *)*dstptr;
1583 match = m->u.kernel.match;
1584 if (match->compat)
1585 match->compat(m, dstptr, size, COMPAT_FROM_USER);
1586 else
1587 xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
1588
1589 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1590 name, hookmask, ip->proto,
1591 ip->invflags & IPT_INV_PROTO);
1592 if (ret)
1593 return ret;
1594
1595 if (m->u.kernel.match->checkentry
1596 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
2722971c
DM
1597 hookmask)) {
1598 duprintf("ip_tables: check failed for `%s'.\n",
1599 m->u.kernel.match->name);
1600 return -EINVAL;
1601 }
1602 return 0;
1603}
1604
1605static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1606 unsigned int *size, const char *name,
1607 struct xt_table_info *newinfo, unsigned char *base)
1608{
1609 struct ipt_entry_target *t;
1610 struct ipt_target *target;
1611 struct ipt_entry *de;
1612 unsigned int origsize;
1613 int ret, h;
1614
1615 ret = 0;
1616 origsize = *size;
1617 de = (struct ipt_entry *)*dstptr;
1618 memcpy(de, e, sizeof(struct ipt_entry));
1619
1620 *dstptr += sizeof(struct compat_ipt_entry);
1621 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1622 name, &de->ip, de->comefrom);
1623 if (ret)
1624 goto out;
1625 de->target_offset = e->target_offset - (origsize - *size);
1626 t = ipt_get_target(e);
1627 target = t->u.kernel.target;
1628 if (target->compat)
1629 target->compat(t, dstptr, size, COMPAT_FROM_USER);
1630 else
1631 xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
1632
1633 de->next_offset = e->next_offset - (origsize - *size);
1634 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1635 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1636 newinfo->hook_entry[h] -= origsize - *size;
1637 if ((unsigned char *)de - base < newinfo->underflow[h])
1638 newinfo->underflow[h] -= origsize - *size;
1639 }
1640
1641 t = ipt_get_target(de);
1642 target = t->u.kernel.target;
1643 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1644 name, e->comefrom, e->ip.proto,
1645 e->ip.invflags & IPT_INV_PROTO);
1646 if (ret)
1647 goto out;
1648
1649 ret = -EINVAL;
1650 if (t->u.kernel.target == &ipt_standard_target) {
1651 if (!standard_check(t, *size))
1652 goto out;
1653 } else if (t->u.kernel.target->checkentry
1654 && !t->u.kernel.target->checkentry(name, de, target,
efa74165 1655 t->data, de->comefrom)) {
2722971c
DM
1656 duprintf("ip_tables: compat: check failed for `%s'.\n",
1657 t->u.kernel.target->name);
1658 goto out;
1659 }
1660 ret = 0;
1661out:
1662 return ret;
1663}
1664
1da177e4 1665static int
2722971c
DM
1666translate_compat_table(const char *name,
1667 unsigned int valid_hooks,
1668 struct xt_table_info **pinfo,
1669 void **pentry0,
1670 unsigned int total_size,
1671 unsigned int number,
1672 unsigned int *hook_entries,
1673 unsigned int *underflows)
1da177e4 1674{
2722971c
DM
1675 unsigned int i;
1676 struct xt_table_info *newinfo, *info;
1677 void *pos, *entry0, *entry1;
1678 unsigned int size;
1da177e4 1679 int ret;
1da177e4 1680
2722971c
DM
1681 info = *pinfo;
1682 entry0 = *pentry0;
1683 size = total_size;
1684 info->number = number;
1685
1686 /* Init all hooks to impossible value. */
1687 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1688 info->hook_entry[i] = 0xFFFFFFFF;
1689 info->underflow[i] = 0xFFFFFFFF;
1690 }
1691
1692 duprintf("translate_compat_table: size %u\n", info->size);
1693 i = 0;
1694 xt_compat_lock(AF_INET);
1695 /* Walk through entries, checking offsets. */
1696 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1697 check_compat_entry_size_and_hooks,
1698 info, &size, entry0,
1699 entry0 + total_size,
1700 hook_entries, underflows, &i, name);
1701 if (ret != 0)
1702 goto out_unlock;
1703
1704 ret = -EINVAL;
1705 if (i != number) {
1706 duprintf("translate_compat_table: %u not %u entries\n",
1707 i, number);
1708 goto out_unlock;
1709 }
1710
1711 /* Check hooks all assigned */
1712 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1713 /* Only hooks which are valid */
1714 if (!(valid_hooks & (1 << i)))
1715 continue;
1716 if (info->hook_entry[i] == 0xFFFFFFFF) {
1717 duprintf("Invalid hook entry %u %u\n",
1718 i, hook_entries[i]);
1719 goto out_unlock;
1da177e4 1720 }
2722971c
DM
1721 if (info->underflow[i] == 0xFFFFFFFF) {
1722 duprintf("Invalid underflow %u %u\n",
1723 i, underflows[i]);
1724 goto out_unlock;
1725 }
1726 }
1727
1728 ret = -ENOMEM;
1729 newinfo = xt_alloc_table_info(size);
1730 if (!newinfo)
1731 goto out_unlock;
1732
1733 newinfo->number = number;
1734 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1735 newinfo->hook_entry[i] = info->hook_entry[i];
1736 newinfo->underflow[i] = info->underflow[i];
1737 }
1738 entry1 = newinfo->entries[raw_smp_processor_id()];
1739 pos = entry1;
1740 size = total_size;
1741 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1742 compat_copy_entry_from_user, &pos, &size,
1743 name, newinfo, entry1);
1744 compat_flush_offsets();
1745 xt_compat_unlock(AF_INET);
1746 if (ret)
1747 goto free_newinfo;
1748
1749 ret = -ELOOP;
1750 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1751 goto free_newinfo;
1752
1753 /* And one copy for every other CPU */
fb1bb34d 1754 for_each_possible_cpu(i)
2722971c
DM
1755 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1756 memcpy(newinfo->entries[i], entry1, newinfo->size);
1757
1758 *pinfo = newinfo;
1759 *pentry0 = entry1;
1760 xt_free_table_info(info);
1761 return 0;
1da177e4 1762
2722971c
DM
1763free_newinfo:
1764 xt_free_table_info(newinfo);
1765out:
1da177e4 1766 return ret;
2722971c
DM
1767out_unlock:
1768 xt_compat_unlock(AF_INET);
1769 goto out;
1da177e4
LT
1770}
1771
1772static int
2722971c 1773compat_do_replace(void __user *user, unsigned int len)
1da177e4
LT
1774{
1775 int ret;
2722971c
DM
1776 struct compat_ipt_replace tmp;
1777 struct xt_table_info *newinfo;
1778 void *loc_cpu_entry;
1da177e4
LT
1779
1780 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1781 return -EFAULT;
1782
1783 /* Hack: Causes ipchains to give correct error msg --RR */
1784 if (len != sizeof(tmp) + tmp.size)
1785 return -ENOPROTOOPT;
1786
ee4bb818
KK
1787 /* overflow check */
1788 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1789 SMP_CACHE_BYTES)
1790 return -ENOMEM;
1791 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1792 return -ENOMEM;
1793
2e4e6a17 1794 newinfo = xt_alloc_table_info(tmp.size);
1da177e4
LT
1795 if (!newinfo)
1796 return -ENOMEM;
1797
31836064
ED
1798 /* choose the copy that is our node/cpu */
1799 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1800 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1da177e4
LT
1801 tmp.size) != 0) {
1802 ret = -EFAULT;
1803 goto free_newinfo;
1804 }
1805
2722971c
DM
1806 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1807 &newinfo, &loc_cpu_entry, tmp.size,
1808 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1809 if (ret != 0)
1da177e4 1810 goto free_newinfo;
1da177e4 1811
2722971c 1812 duprintf("compat_do_replace: Translated table\n");
1da177e4 1813
2722971c
DM
1814 ret = __do_replace(tmp.name, tmp.valid_hooks,
1815 newinfo, tmp.num_counters,
1816 compat_ptr(tmp.counters));
1817 if (ret)
1818 goto free_newinfo_untrans;
1819 return 0;
1da177e4 1820
2722971c
DM
1821 free_newinfo_untrans:
1822 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1823 free_newinfo:
1824 xt_free_table_info(newinfo);
1825 return ret;
1826}
1da177e4 1827
2722971c
DM
1828static int
1829compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1830 unsigned int len)
1831{
1832 int ret;
1da177e4 1833
2722971c
DM
1834 if (!capable(CAP_NET_ADMIN))
1835 return -EPERM;
1da177e4 1836
2722971c
DM
1837 switch (cmd) {
1838 case IPT_SO_SET_REPLACE:
1839 ret = compat_do_replace(user, len);
1840 break;
1da177e4 1841
2722971c
DM
1842 case IPT_SO_SET_ADD_COUNTERS:
1843 ret = do_add_counters(user, len, 1);
1844 break;
1845
1846 default:
1847 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1848 ret = -EINVAL;
1849 }
1da177e4 1850
1da177e4
LT
1851 return ret;
1852}
1853
2722971c 1854struct compat_ipt_get_entries
1da177e4 1855{
2722971c
DM
1856 char name[IPT_TABLE_MAXNAMELEN];
1857 compat_uint_t size;
1858 struct compat_ipt_entry entrytable[0];
1859};
1da177e4 1860
2722971c
DM
1861static int compat_copy_entries_to_user(unsigned int total_size,
1862 struct ipt_table *table, void __user *userptr)
1863{
1864 unsigned int off, num;
1865 struct compat_ipt_entry e;
1866 struct xt_counters *counters;
1867 struct xt_table_info *private = table->private;
1868 void __user *pos;
1869 unsigned int size;
1870 int ret = 0;
1871 void *loc_cpu_entry;
1da177e4 1872
2722971c
DM
1873 counters = alloc_counters(table);
1874 if (IS_ERR(counters))
1875 return PTR_ERR(counters);
1876
1877 /* choose the copy that is on our node/cpu, ...
1878 * This choice is lazy (because current thread is
1879 * allowed to migrate to another cpu)
1880 */
1881 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1882 pos = userptr;
1883 size = total_size;
1884 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1885 compat_copy_entry_to_user, &pos, &size);
1886 if (ret)
1887 goto free_counters;
1888
1889 /* ... then go back and fix counters and names */
1890 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1891 unsigned int i;
1892 struct ipt_entry_match m;
1893 struct ipt_entry_target t;
1894
1895 ret = -EFAULT;
1896 if (copy_from_user(&e, userptr + off,
1897 sizeof(struct compat_ipt_entry)))
1898 goto free_counters;
1899 if (copy_to_user(userptr + off +
1900 offsetof(struct compat_ipt_entry, counters),
1901 &counters[num], sizeof(counters[num])))
1902 goto free_counters;
1903
1904 for (i = sizeof(struct compat_ipt_entry);
1905 i < e.target_offset; i += m.u.match_size) {
1906 if (copy_from_user(&m, userptr + off + i,
1907 sizeof(struct ipt_entry_match)))
1908 goto free_counters;
1909 if (copy_to_user(userptr + off + i +
1910 offsetof(struct ipt_entry_match, u.user.name),
1911 m.u.kernel.match->name,
1912 strlen(m.u.kernel.match->name) + 1))
1913 goto free_counters;
1914 }
1915
1916 if (copy_from_user(&t, userptr + off + e.target_offset,
1917 sizeof(struct ipt_entry_target)))
1918 goto free_counters;
1919 if (copy_to_user(userptr + off + e.target_offset +
1920 offsetof(struct ipt_entry_target, u.user.name),
1921 t.u.kernel.target->name,
1922 strlen(t.u.kernel.target->name) + 1))
1923 goto free_counters;
1924 }
1925 ret = 0;
1926free_counters:
1927 vfree(counters);
1928 return ret;
1da177e4
LT
1929}
1930
1931static int
2722971c 1932compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1da177e4 1933{
2722971c
DM
1934 int ret;
1935 struct compat_ipt_get_entries get;
1da177e4 1936 struct ipt_table *t;
1da177e4 1937
1da177e4 1938
2722971c
DM
1939 if (*len < sizeof(get)) {
1940 duprintf("compat_get_entries: %u < %u\n",
1941 *len, (unsigned int)sizeof(get));
1da177e4 1942 return -EINVAL;
2722971c 1943 }
1da177e4 1944
2722971c
DM
1945 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1946 return -EFAULT;
1da177e4 1947
2722971c
DM
1948 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1949 duprintf("compat_get_entries: %u != %u\n", *len,
1950 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1951 get.size));
1952 return -EINVAL;
1da177e4
LT
1953 }
1954
2722971c
DM
1955 xt_compat_lock(AF_INET);
1956 t = xt_find_table_lock(AF_INET, get.name);
1957 if (t && !IS_ERR(t)) {
1958 struct xt_table_info *private = t->private;
1959 struct xt_table_info info;
1960 duprintf("t->private->number = %u\n",
1961 private->number);
1962 ret = compat_table_info(private, &info);
1963 if (!ret && get.size == info.size) {
1964 ret = compat_copy_entries_to_user(private->size,
1965 t, uptr->entrytable);
1966 } else if (!ret) {
1967 duprintf("compat_get_entries: I've got %u not %u!\n",
1968 private->size,
1969 get.size);
1970 ret = -EINVAL;
1971 }
1972 compat_flush_offsets();
1973 module_put(t->me);
1974 xt_table_unlock(t);
1975 } else
1da177e4 1976 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 1977
2722971c
DM
1978 xt_compat_unlock(AF_INET);
1979 return ret;
1980}
1da177e4 1981
2722971c
DM
1982static int
1983compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1984{
1985 int ret;
1da177e4 1986
2722971c
DM
1987 switch (cmd) {
1988 case IPT_SO_GET_INFO:
1989 ret = get_info(user, len, 1);
1990 break;
1991 case IPT_SO_GET_ENTRIES:
1992 ret = compat_get_entries(user, len);
1993 break;
1994 default:
1995 duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
1996 ret = -EINVAL;
1997 }
1da177e4
LT
1998 return ret;
1999}
2722971c 2000#endif
1da177e4
LT
2001
2002static int
2003do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2004{
2005 int ret;
2006
2007 if (!capable(CAP_NET_ADMIN))
2008 return -EPERM;
2009
2010 switch (cmd) {
2011 case IPT_SO_SET_REPLACE:
2012 ret = do_replace(user, len);
2013 break;
2014
2015 case IPT_SO_SET_ADD_COUNTERS:
2722971c 2016 ret = do_add_counters(user, len, 0);
1da177e4
LT
2017 break;
2018
2019 default:
2020 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
2021 ret = -EINVAL;
2022 }
2023
2024 return ret;
2025}
2026
2027static int
2028do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2029{
2030 int ret;
2031
2032 if (!capable(CAP_NET_ADMIN))
2033 return -EPERM;
2034
2035 switch (cmd) {
2722971c
DM
2036 case IPT_SO_GET_INFO:
2037 ret = get_info(user, len, 0);
2038 break;
1da177e4 2039
2722971c
DM
2040 case IPT_SO_GET_ENTRIES:
2041 ret = get_entries(user, len);
1da177e4 2042 break;
1da177e4
LT
2043
2044 case IPT_SO_GET_REVISION_MATCH:
2045 case IPT_SO_GET_REVISION_TARGET: {
2046 struct ipt_get_revision rev;
2e4e6a17 2047 int target;
1da177e4
LT
2048
2049 if (*len != sizeof(rev)) {
2050 ret = -EINVAL;
2051 break;
2052 }
2053 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2054 ret = -EFAULT;
2055 break;
2056 }
2057
2058 if (cmd == IPT_SO_GET_REVISION_TARGET)
2e4e6a17 2059 target = 1;
1da177e4 2060 else
2e4e6a17 2061 target = 0;
1da177e4 2062
2e4e6a17
HW
2063 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2064 rev.revision,
2065 target, &ret),
1da177e4
LT
2066 "ipt_%s", rev.name);
2067 break;
2068 }
2069
2070 default:
2071 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2072 ret = -EINVAL;
2073 }
2074
2075 return ret;
2076}
2077
2e4e6a17 2078int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
1da177e4
LT
2079{
2080 int ret;
2e4e6a17
HW
2081 struct xt_table_info *newinfo;
2082 static struct xt_table_info bootstrap
1da177e4 2083 = { 0, 0, 0, { 0 }, { 0 }, { } };
31836064 2084 void *loc_cpu_entry;
1da177e4 2085
2e4e6a17 2086 newinfo = xt_alloc_table_info(repl->size);
1da177e4
LT
2087 if (!newinfo)
2088 return -ENOMEM;
2089
31836064
ED
2090 /* choose the copy on our node/cpu
2091 * but dont care of preemption
2092 */
2093 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2094 memcpy(loc_cpu_entry, repl->entries, repl->size);
1da177e4
LT
2095
2096 ret = translate_table(table->name, table->valid_hooks,
31836064 2097 newinfo, loc_cpu_entry, repl->size,
1da177e4
LT
2098 repl->num_entries,
2099 repl->hook_entry,
2100 repl->underflow);
2101 if (ret != 0) {
2e4e6a17 2102 xt_free_table_info(newinfo);
1da177e4
LT
2103 return ret;
2104 }
2105
da298d3a
PM
2106 ret = xt_register_table(table, &bootstrap, newinfo);
2107 if (ret != 0) {
2e4e6a17 2108 xt_free_table_info(newinfo);
1da177e4
LT
2109 return ret;
2110 }
2111
2e4e6a17 2112 return 0;
1da177e4
LT
2113}
2114
2115void ipt_unregister_table(struct ipt_table *table)
2116{
2e4e6a17 2117 struct xt_table_info *private;
31836064
ED
2118 void *loc_cpu_entry;
2119
2e4e6a17 2120 private = xt_unregister_table(table);
1da177e4
LT
2121
2122 /* Decrease module usage counts and free resources */
2e4e6a17
HW
2123 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2124 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2125 xt_free_table_info(private);
1da177e4
LT
2126}
2127
2128/* Returns 1 if the type and code is matched by the range, 0 otherwise */
2129static inline int
2130icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2131 u_int8_t type, u_int8_t code,
2132 int invert)
2133{
2134 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2135 ^ invert;
2136}
2137
2138static int
2139icmp_match(const struct sk_buff *skb,
2140 const struct net_device *in,
2141 const struct net_device *out,
c4986734 2142 const struct xt_match *match,
1da177e4
LT
2143 const void *matchinfo,
2144 int offset,
2e4e6a17 2145 unsigned int protoff,
1da177e4
LT
2146 int *hotdrop)
2147{
2148 struct icmphdr _icmph, *ic;
2149 const struct ipt_icmp *icmpinfo = matchinfo;
2150
2151 /* Must not be a fragment. */
2152 if (offset)
2153 return 0;
2154
2e4e6a17 2155 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
1da177e4
LT
2156 if (ic == NULL) {
2157 /* We've been asked to examine this packet, and we
2158 * can't. Hence, no choice but to drop.
2159 */
2160 duprintf("Dropping evil ICMP tinygram.\n");
2161 *hotdrop = 1;
2162 return 0;
2163 }
2164
2165 return icmp_type_code_match(icmpinfo->type,
2166 icmpinfo->code[0],
2167 icmpinfo->code[1],
2168 ic->type, ic->code,
2169 !!(icmpinfo->invflags&IPT_ICMP_INV));
2170}
2171
2172/* Called when user tries to insert an entry of this type. */
2173static int
2174icmp_checkentry(const char *tablename,
2e4e6a17 2175 const void *info,
c4986734 2176 const struct xt_match *match,
1da177e4 2177 void *matchinfo,
1da177e4
LT
2178 unsigned int hook_mask)
2179{
2180 const struct ipt_icmp *icmpinfo = matchinfo;
2181
1d5cd909
PM
2182 /* Must specify no unknown invflags */
2183 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
1da177e4
LT
2184}
2185
2186/* The built-in targets: standard (NULL) and error. */
2187static struct ipt_target ipt_standard_target = {
2188 .name = IPT_STANDARD_TARGET,
1d5cd909 2189 .targetsize = sizeof(int),
a45049c5 2190 .family = AF_INET,
2722971c
DM
2191#ifdef CONFIG_COMPAT
2192 .compat = &compat_ipt_standard_fn,
2193#endif
1da177e4
LT
2194};
2195
2196static struct ipt_target ipt_error_target = {
2197 .name = IPT_ERROR_TARGET,
2198 .target = ipt_error,
1d5cd909 2199 .targetsize = IPT_FUNCTION_MAXNAMELEN,
a45049c5 2200 .family = AF_INET,
1da177e4
LT
2201};
2202
2203static struct nf_sockopt_ops ipt_sockopts = {
2204 .pf = PF_INET,
2205 .set_optmin = IPT_BASE_CTL,
2206 .set_optmax = IPT_SO_SET_MAX+1,
2207 .set = do_ipt_set_ctl,
2722971c
DM
2208#ifdef CONFIG_COMPAT
2209 .compat_set = compat_do_ipt_set_ctl,
2210#endif
1da177e4
LT
2211 .get_optmin = IPT_BASE_CTL,
2212 .get_optmax = IPT_SO_GET_MAX+1,
2213 .get = do_ipt_get_ctl,
2722971c
DM
2214#ifdef CONFIG_COMPAT
2215 .compat_get = compat_do_ipt_get_ctl,
2216#endif
1da177e4
LT
2217};
2218
1da177e4
LT
2219static struct ipt_match icmp_matchstruct = {
2220 .name = "icmp",
1d5cd909
PM
2221 .match = icmp_match,
2222 .matchsize = sizeof(struct ipt_icmp),
2223 .proto = IPPROTO_ICMP,
a45049c5 2224 .family = AF_INET,
1d5cd909 2225 .checkentry = icmp_checkentry,
1da177e4
LT
2226};
2227
65b4b4e8 2228static int __init ip_tables_init(void)
1da177e4
LT
2229{
2230 int ret;
2231
0eff66e6
PM
2232 ret = xt_proto_init(AF_INET);
2233 if (ret < 0)
2234 goto err1;
2e4e6a17 2235
1da177e4 2236 /* Noone else will be downing sem now, so we won't sleep */
0eff66e6
PM
2237 ret = xt_register_target(&ipt_standard_target);
2238 if (ret < 0)
2239 goto err2;
2240 ret = xt_register_target(&ipt_error_target);
2241 if (ret < 0)
2242 goto err3;
2243 ret = xt_register_match(&icmp_matchstruct);
2244 if (ret < 0)
2245 goto err4;
1da177e4
LT
2246
2247 /* Register setsockopt */
2248 ret = nf_register_sockopt(&ipt_sockopts);
0eff66e6
PM
2249 if (ret < 0)
2250 goto err5;
1da177e4 2251
2e4e6a17 2252 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
1da177e4 2253 return 0;
0eff66e6
PM
2254
2255err5:
2256 xt_unregister_match(&icmp_matchstruct);
2257err4:
2258 xt_unregister_target(&ipt_error_target);
2259err3:
2260 xt_unregister_target(&ipt_standard_target);
2261err2:
2262 xt_proto_fini(AF_INET);
2263err1:
2264 return ret;
1da177e4
LT
2265}
2266
65b4b4e8 2267static void __exit ip_tables_fini(void)
1da177e4
LT
2268{
2269 nf_unregister_sockopt(&ipt_sockopts);
2e4e6a17 2270
a45049c5
PNA
2271 xt_unregister_match(&icmp_matchstruct);
2272 xt_unregister_target(&ipt_error_target);
2273 xt_unregister_target(&ipt_standard_target);
2e4e6a17
HW
2274
2275 xt_proto_fini(AF_INET);
1da177e4
LT
2276}
2277
2278EXPORT_SYMBOL(ipt_register_table);
2279EXPORT_SYMBOL(ipt_unregister_table);
1da177e4 2280EXPORT_SYMBOL(ipt_do_table);
65b4b4e8
AM
2281module_init(ip_tables_init);
2282module_exit(ip_tables_fini);