8a455439b128258de3e42926640834975579d5af
[deliverable/linux.git] / net / ipv4 / netfilter / ip_tables.c
1 /*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 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 * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15 * - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
16 */
17 #include <linux/cache.h>
18 #include <linux/capability.h>
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>
24 #include <linux/icmp.h>
25 #include <net/ip.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
32
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ip_tables.h>
35
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38 MODULE_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) \
58 do { \
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
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
80 Hence the start of any table is given by get_table() below. */
81
82 /* Returns whether matches rule or not. */
83 static inline int
84 ip_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
161 static inline int
162 ip_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
177 static unsigned int
178 ipt_error(struct sk_buff **pskb,
179 const struct net_device *in,
180 const struct net_device *out,
181 unsigned int hooknum,
182 const struct xt_target *target,
183 const void *targinfo)
184 {
185 if (net_ratelimit())
186 printk("ip_tables: error: `%s'\n", (char *)targinfo);
187
188 return NF_DROP;
189 }
190
191 static inline
192 int 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 */
200 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201 offset, skb->nh.iph->ihl*4, hotdrop))
202 return 1;
203 else
204 return 0;
205 }
206
207 static inline struct ipt_entry *
208 get_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. */
214 unsigned int
215 ipt_do_table(struct sk_buff **pskb,
216 unsigned int hook,
217 const struct net_device *in,
218 const struct net_device *out,
219 struct ipt_table *table)
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;
231 struct xt_table_info *private;
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));
248 private = table->private;
249 table_base = (void *)private->entries[smp_processor_id()];
250 e = get_entry(table_base, private->hook_entry[hook]);
251
252 /* For return from builtin chain */
253 back = get_entry(table_base, private->underflow[hook]);
254
255 do {
256 IP_NF_ASSERT(e);
257 IP_NF_ASSERT(back);
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 }
286 if (table_base + v != (void *)e + e->next_offset
287 && !(e->ip.flags & IPT_F_GOTO)) {
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,
308 t->u.kernel.target,
309 t->data);
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
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
350 /* All zeroes == unconditional rule. */
351 static inline int
352 unconditional(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. */
365 static int
366 mark_source_chains(struct xt_table_info *newinfo,
367 unsigned int valid_hooks, void *entry0)
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
376 = (struct ipt_entry *)(entry0 + pos);
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 *)
426 (entry0 + pos);
427 } while (oldpos == pos + e->next_offset);
428
429 /* Move along one */
430 size = e->next_offset;
431 e = (struct ipt_entry *)
432 (entry0 + pos + size);
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 *)
449 (entry0 + newpos);
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
460 static inline int
461 cleanup_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)
467 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
468 module_put(m->u.kernel.match->me);
469 return 0;
470 }
471
472 static inline int
473 standard_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. */
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 }
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
493 static inline int
494 check_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;
501 int ret;
502
503 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
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
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
518 if (m->u.kernel.match->checkentry
519 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
520 hookmask)) {
521 duprintf("ip_tables: check failed for `%s'.\n",
522 m->u.kernel.match->name);
523 ret = -EINVAL;
524 goto err;
525 }
526
527 (*i)++;
528 return 0;
529 err:
530 module_put(m->u.kernel.match->me);
531 return ret;
532 }
533
534 static struct ipt_target ipt_standard_target;
535
536 static inline int
537 check_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 if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
551 return -EINVAL;
552
553 j = 0;
554 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
555 if (ret != 0)
556 goto cleanup_matches;
557
558 t = ipt_get_target(e);
559 ret = -EINVAL;
560 if (e->target_offset + t->u.target_size > e->next_offset)
561 goto cleanup_matches;
562 target = try_then_request_module(xt_find_target(AF_INET,
563 t->u.user.name,
564 t->u.user.revision),
565 "ipt_%s", t->u.user.name);
566 if (IS_ERR(target) || !target) {
567 duprintf("check_entry: `%s' not found\n", t->u.user.name);
568 ret = target ? PTR_ERR(target) : -ENOENT;
569 goto cleanup_matches;
570 }
571 t->u.kernel.target = target;
572
573 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
574 name, e->comefrom, e->ip.proto,
575 e->ip.invflags & IPT_INV_PROTO);
576 if (ret)
577 goto err;
578
579 if (t->u.kernel.target == &ipt_standard_target) {
580 if (!standard_check(t, size)) {
581 ret = -EINVAL;
582 goto err;
583 }
584 } else if (t->u.kernel.target->checkentry
585 && !t->u.kernel.target->checkentry(name, e, target, t->data,
586 e->comefrom)) {
587 duprintf("ip_tables: check failed for `%s'.\n",
588 t->u.kernel.target->name);
589 ret = -EINVAL;
590 goto err;
591 }
592
593 (*i)++;
594 return 0;
595 err:
596 module_put(t->u.kernel.target->me);
597 cleanup_matches:
598 IPT_MATCH_ITERATE(e, cleanup_match, &j);
599 return ret;
600 }
601
602 static inline int
603 check_entry_size_and_hooks(struct ipt_entry *e,
604 struct xt_table_info *newinfo,
605 unsigned char *base,
606 unsigned char *limit,
607 const unsigned int *hook_entries,
608 const unsigned int *underflows,
609 unsigned int *i)
610 {
611 unsigned int h;
612
613 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
614 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
615 duprintf("Bad offset %p\n", e);
616 return -EINVAL;
617 }
618
619 if (e->next_offset
620 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
621 duprintf("checking: element %p size %u\n",
622 e, e->next_offset);
623 return -EINVAL;
624 }
625
626 /* Check hooks & underflows */
627 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
628 if ((unsigned char *)e - base == hook_entries[h])
629 newinfo->hook_entry[h] = hook_entries[h];
630 if ((unsigned char *)e - base == underflows[h])
631 newinfo->underflow[h] = underflows[h];
632 }
633
634 /* FIXME: underflows must be unconditional, standard verdicts
635 < 0 (not IPT_RETURN). --RR */
636
637 /* Clear counters and comefrom */
638 e->counters = ((struct xt_counters) { 0, 0 });
639 e->comefrom = 0;
640
641 (*i)++;
642 return 0;
643 }
644
645 static inline int
646 cleanup_entry(struct ipt_entry *e, unsigned int *i)
647 {
648 struct ipt_entry_target *t;
649
650 if (i && (*i)-- == 0)
651 return 1;
652
653 /* Cleanup all matches */
654 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
655 t = ipt_get_target(e);
656 if (t->u.kernel.target->destroy)
657 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
658 module_put(t->u.kernel.target->me);
659 return 0;
660 }
661
662 /* Checks and translates the user-supplied table segment (held in
663 newinfo) */
664 static int
665 translate_table(const char *name,
666 unsigned int valid_hooks,
667 struct xt_table_info *newinfo,
668 void *entry0,
669 unsigned int size,
670 unsigned int number,
671 const unsigned int *hook_entries,
672 const unsigned int *underflows)
673 {
674 unsigned int i;
675 int ret;
676
677 newinfo->size = size;
678 newinfo->number = number;
679
680 /* Init all hooks to impossible value. */
681 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
682 newinfo->hook_entry[i] = 0xFFFFFFFF;
683 newinfo->underflow[i] = 0xFFFFFFFF;
684 }
685
686 duprintf("translate_table: size %u\n", newinfo->size);
687 i = 0;
688 /* Walk through entries, checking offsets. */
689 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
690 check_entry_size_and_hooks,
691 newinfo,
692 entry0,
693 entry0 + size,
694 hook_entries, underflows, &i);
695 if (ret != 0)
696 return ret;
697
698 if (i != number) {
699 duprintf("translate_table: %u not %u entries\n",
700 i, number);
701 return -EINVAL;
702 }
703
704 /* Check hooks all assigned */
705 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
706 /* Only hooks which are valid */
707 if (!(valid_hooks & (1 << i)))
708 continue;
709 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
710 duprintf("Invalid hook entry %u %u\n",
711 i, hook_entries[i]);
712 return -EINVAL;
713 }
714 if (newinfo->underflow[i] == 0xFFFFFFFF) {
715 duprintf("Invalid underflow %u %u\n",
716 i, underflows[i]);
717 return -EINVAL;
718 }
719 }
720
721 /* Finally, each sanity check must pass */
722 i = 0;
723 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
724 check_entry, name, size, &i);
725
726 if (ret != 0)
727 goto cleanup;
728
729 ret = -ELOOP;
730 if (!mark_source_chains(newinfo, valid_hooks, entry0))
731 goto cleanup;
732
733 /* And one copy for every other CPU */
734 for_each_possible_cpu(i) {
735 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
736 memcpy(newinfo->entries[i], entry0, newinfo->size);
737 }
738
739 return 0;
740 cleanup:
741 IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
742 return ret;
743 }
744
745 /* Gets counters. */
746 static inline int
747 add_entry_to_counter(const struct ipt_entry *e,
748 struct xt_counters total[],
749 unsigned int *i)
750 {
751 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
752
753 (*i)++;
754 return 0;
755 }
756
757 static inline int
758 set_entry_to_counter(const struct ipt_entry *e,
759 struct ipt_counters total[],
760 unsigned int *i)
761 {
762 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
763
764 (*i)++;
765 return 0;
766 }
767
768 static void
769 get_counters(const struct xt_table_info *t,
770 struct xt_counters counters[])
771 {
772 unsigned int cpu;
773 unsigned int i;
774 unsigned int curcpu;
775
776 /* Instead of clearing (by a previous call to memset())
777 * the counters and using adds, we set the counters
778 * with data used by 'current' CPU
779 * We dont care about preemption here.
780 */
781 curcpu = raw_smp_processor_id();
782
783 i = 0;
784 IPT_ENTRY_ITERATE(t->entries[curcpu],
785 t->size,
786 set_entry_to_counter,
787 counters,
788 &i);
789
790 for_each_possible_cpu(cpu) {
791 if (cpu == curcpu)
792 continue;
793 i = 0;
794 IPT_ENTRY_ITERATE(t->entries[cpu],
795 t->size,
796 add_entry_to_counter,
797 counters,
798 &i);
799 }
800 }
801
802 static inline struct xt_counters * alloc_counters(struct ipt_table *table)
803 {
804 unsigned int countersize;
805 struct xt_counters *counters;
806 struct xt_table_info *private = table->private;
807
808 /* We need atomic snapshot of counters: rest doesn't change
809 (other than comefrom, which userspace doesn't care
810 about). */
811 countersize = sizeof(struct xt_counters) * private->number;
812 counters = vmalloc_node(countersize, numa_node_id());
813
814 if (counters == NULL)
815 return ERR_PTR(-ENOMEM);
816
817 /* First, sum counters... */
818 write_lock_bh(&table->lock);
819 get_counters(private, counters);
820 write_unlock_bh(&table->lock);
821
822 return counters;
823 }
824
825 static int
826 copy_entries_to_user(unsigned int total_size,
827 struct ipt_table *table,
828 void __user *userptr)
829 {
830 unsigned int off, num;
831 struct ipt_entry *e;
832 struct xt_counters *counters;
833 struct xt_table_info *private = table->private;
834 int ret = 0;
835 void *loc_cpu_entry;
836
837 counters = alloc_counters(table);
838 if (IS_ERR(counters))
839 return PTR_ERR(counters);
840
841 /* choose the copy that is on our node/cpu, ...
842 * This choice is lazy (because current thread is
843 * allowed to migrate to another cpu)
844 */
845 loc_cpu_entry = private->entries[raw_smp_processor_id()];
846 /* ... then copy entire thing ... */
847 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
848 ret = -EFAULT;
849 goto free_counters;
850 }
851
852 /* FIXME: use iterator macros --RR */
853 /* ... then go back and fix counters and names */
854 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
855 unsigned int i;
856 struct ipt_entry_match *m;
857 struct ipt_entry_target *t;
858
859 e = (struct ipt_entry *)(loc_cpu_entry + off);
860 if (copy_to_user(userptr + off
861 + offsetof(struct ipt_entry, counters),
862 &counters[num],
863 sizeof(counters[num])) != 0) {
864 ret = -EFAULT;
865 goto free_counters;
866 }
867
868 for (i = sizeof(struct ipt_entry);
869 i < e->target_offset;
870 i += m->u.match_size) {
871 m = (void *)e + i;
872
873 if (copy_to_user(userptr + off + i
874 + offsetof(struct ipt_entry_match,
875 u.user.name),
876 m->u.kernel.match->name,
877 strlen(m->u.kernel.match->name)+1)
878 != 0) {
879 ret = -EFAULT;
880 goto free_counters;
881 }
882 }
883
884 t = ipt_get_target(e);
885 if (copy_to_user(userptr + off + e->target_offset
886 + offsetof(struct ipt_entry_target,
887 u.user.name),
888 t->u.kernel.target->name,
889 strlen(t->u.kernel.target->name)+1) != 0) {
890 ret = -EFAULT;
891 goto free_counters;
892 }
893 }
894
895 free_counters:
896 vfree(counters);
897 return ret;
898 }
899
900 #ifdef CONFIG_COMPAT
901 struct compat_delta {
902 struct compat_delta *next;
903 u_int16_t offset;
904 short delta;
905 };
906
907 static struct compat_delta *compat_offsets = NULL;
908
909 static int compat_add_offset(u_int16_t offset, short delta)
910 {
911 struct compat_delta *tmp;
912
913 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
914 if (!tmp)
915 return -ENOMEM;
916 tmp->offset = offset;
917 tmp->delta = delta;
918 if (compat_offsets) {
919 tmp->next = compat_offsets->next;
920 compat_offsets->next = tmp;
921 } else {
922 compat_offsets = tmp;
923 tmp->next = NULL;
924 }
925 return 0;
926 }
927
928 static void compat_flush_offsets(void)
929 {
930 struct compat_delta *tmp, *next;
931
932 if (compat_offsets) {
933 for(tmp = compat_offsets; tmp; tmp = next) {
934 next = tmp->next;
935 kfree(tmp);
936 }
937 compat_offsets = NULL;
938 }
939 }
940
941 static short compat_calc_jump(u_int16_t offset)
942 {
943 struct compat_delta *tmp;
944 short delta;
945
946 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
947 if (tmp->offset < offset)
948 delta += tmp->delta;
949 return delta;
950 }
951
952 static void compat_standard_from_user(void *dst, void *src)
953 {
954 int v = *(compat_int_t *)src;
955
956 if (v > 0)
957 v += compat_calc_jump(v);
958 memcpy(dst, &v, sizeof(v));
959 }
960
961 static int compat_standard_to_user(void __user *dst, void *src)
962 {
963 compat_int_t cv = *(int *)src;
964
965 if (cv > 0)
966 cv -= compat_calc_jump(cv);
967 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
968 }
969
970 static inline int
971 compat_calc_match(struct ipt_entry_match *m, int * size)
972 {
973 *size += xt_compat_match_offset(m->u.kernel.match);
974 return 0;
975 }
976
977 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
978 void *base, struct xt_table_info *newinfo)
979 {
980 struct ipt_entry_target *t;
981 u_int16_t entry_offset;
982 int off, i, ret;
983
984 off = 0;
985 entry_offset = (void *)e - base;
986 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
987 t = ipt_get_target(e);
988 off += xt_compat_target_offset(t->u.kernel.target);
989 newinfo->size -= off;
990 ret = compat_add_offset(entry_offset, off);
991 if (ret)
992 return ret;
993
994 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
995 if (info->hook_entry[i] && (e < (struct ipt_entry *)
996 (base + info->hook_entry[i])))
997 newinfo->hook_entry[i] -= off;
998 if (info->underflow[i] && (e < (struct ipt_entry *)
999 (base + info->underflow[i])))
1000 newinfo->underflow[i] -= off;
1001 }
1002 return 0;
1003 }
1004
1005 static int compat_table_info(struct xt_table_info *info,
1006 struct xt_table_info *newinfo)
1007 {
1008 void *loc_cpu_entry;
1009 int i;
1010
1011 if (!newinfo || !info)
1012 return -EINVAL;
1013
1014 memset(newinfo, 0, sizeof(struct xt_table_info));
1015 newinfo->size = info->size;
1016 newinfo->number = info->number;
1017 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1018 newinfo->hook_entry[i] = info->hook_entry[i];
1019 newinfo->underflow[i] = info->underflow[i];
1020 }
1021 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1022 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1023 compat_calc_entry, info, loc_cpu_entry, newinfo);
1024 }
1025 #endif
1026
1027 static int get_info(void __user *user, int *len, int compat)
1028 {
1029 char name[IPT_TABLE_MAXNAMELEN];
1030 struct ipt_table *t;
1031 int ret;
1032
1033 if (*len != sizeof(struct ipt_getinfo)) {
1034 duprintf("length %u != %u\n", *len,
1035 (unsigned int)sizeof(struct ipt_getinfo));
1036 return -EINVAL;
1037 }
1038
1039 if (copy_from_user(name, user, sizeof(name)) != 0)
1040 return -EFAULT;
1041
1042 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1043 #ifdef CONFIG_COMPAT
1044 if (compat)
1045 xt_compat_lock(AF_INET);
1046 #endif
1047 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1048 "iptable_%s", name);
1049 if (t && !IS_ERR(t)) {
1050 struct ipt_getinfo info;
1051 struct xt_table_info *private = t->private;
1052
1053 #ifdef CONFIG_COMPAT
1054 if (compat) {
1055 struct xt_table_info tmp;
1056 ret = compat_table_info(private, &tmp);
1057 compat_flush_offsets();
1058 private = &tmp;
1059 }
1060 #endif
1061 info.valid_hooks = t->valid_hooks;
1062 memcpy(info.hook_entry, private->hook_entry,
1063 sizeof(info.hook_entry));
1064 memcpy(info.underflow, private->underflow,
1065 sizeof(info.underflow));
1066 info.num_entries = private->number;
1067 info.size = private->size;
1068 strcpy(info.name, name);
1069
1070 if (copy_to_user(user, &info, *len) != 0)
1071 ret = -EFAULT;
1072 else
1073 ret = 0;
1074
1075 xt_table_unlock(t);
1076 module_put(t->me);
1077 } else
1078 ret = t ? PTR_ERR(t) : -ENOENT;
1079 #ifdef CONFIG_COMPAT
1080 if (compat)
1081 xt_compat_unlock(AF_INET);
1082 #endif
1083 return ret;
1084 }
1085
1086 static int
1087 get_entries(struct ipt_get_entries __user *uptr, int *len)
1088 {
1089 int ret;
1090 struct ipt_get_entries get;
1091 struct ipt_table *t;
1092
1093 if (*len < sizeof(get)) {
1094 duprintf("get_entries: %u < %d\n", *len,
1095 (unsigned int)sizeof(get));
1096 return -EINVAL;
1097 }
1098 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1099 return -EFAULT;
1100 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1101 duprintf("get_entries: %u != %u\n", *len,
1102 (unsigned int)(sizeof(struct ipt_get_entries) +
1103 get.size));
1104 return -EINVAL;
1105 }
1106
1107 t = xt_find_table_lock(AF_INET, get.name);
1108 if (t && !IS_ERR(t)) {
1109 struct xt_table_info *private = t->private;
1110 duprintf("t->private->number = %u\n",
1111 private->number);
1112 if (get.size == private->size)
1113 ret = copy_entries_to_user(private->size,
1114 t, uptr->entrytable);
1115 else {
1116 duprintf("get_entries: I've got %u not %u!\n",
1117 private->size,
1118 get.size);
1119 ret = -EINVAL;
1120 }
1121 module_put(t->me);
1122 xt_table_unlock(t);
1123 } else
1124 ret = t ? PTR_ERR(t) : -ENOENT;
1125
1126 return ret;
1127 }
1128
1129 static int
1130 __do_replace(const char *name, unsigned int valid_hooks,
1131 struct xt_table_info *newinfo, unsigned int num_counters,
1132 void __user *counters_ptr)
1133 {
1134 int ret;
1135 struct ipt_table *t;
1136 struct xt_table_info *oldinfo;
1137 struct xt_counters *counters;
1138 void *loc_cpu_old_entry;
1139
1140 ret = 0;
1141 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1142 if (!counters) {
1143 ret = -ENOMEM;
1144 goto out;
1145 }
1146
1147 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1148 "iptable_%s", name);
1149 if (!t || IS_ERR(t)) {
1150 ret = t ? PTR_ERR(t) : -ENOENT;
1151 goto free_newinfo_counters_untrans;
1152 }
1153
1154 /* You lied! */
1155 if (valid_hooks != t->valid_hooks) {
1156 duprintf("Valid hook crap: %08X vs %08X\n",
1157 valid_hooks, t->valid_hooks);
1158 ret = -EINVAL;
1159 goto put_module;
1160 }
1161
1162 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1163 if (!oldinfo)
1164 goto put_module;
1165
1166 /* Update module usage count based on number of rules */
1167 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1168 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1169 if ((oldinfo->number > oldinfo->initial_entries) ||
1170 (newinfo->number <= oldinfo->initial_entries))
1171 module_put(t->me);
1172 if ((oldinfo->number > oldinfo->initial_entries) &&
1173 (newinfo->number <= oldinfo->initial_entries))
1174 module_put(t->me);
1175
1176 /* Get the old counters. */
1177 get_counters(oldinfo, counters);
1178 /* Decrease module usage counts and free resource */
1179 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1180 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1181 xt_free_table_info(oldinfo);
1182 if (copy_to_user(counters_ptr, counters,
1183 sizeof(struct xt_counters) * num_counters) != 0)
1184 ret = -EFAULT;
1185 vfree(counters);
1186 xt_table_unlock(t);
1187 return ret;
1188
1189 put_module:
1190 module_put(t->me);
1191 xt_table_unlock(t);
1192 free_newinfo_counters_untrans:
1193 vfree(counters);
1194 out:
1195 return ret;
1196 }
1197
1198 static int
1199 do_replace(void __user *user, unsigned int len)
1200 {
1201 int ret;
1202 struct ipt_replace tmp;
1203 struct xt_table_info *newinfo;
1204 void *loc_cpu_entry;
1205
1206 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1207 return -EFAULT;
1208
1209 /* Hack: Causes ipchains to give correct error msg --RR */
1210 if (len != sizeof(tmp) + tmp.size)
1211 return -ENOPROTOOPT;
1212
1213 /* overflow check */
1214 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1215 SMP_CACHE_BYTES)
1216 return -ENOMEM;
1217 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1218 return -ENOMEM;
1219
1220 newinfo = xt_alloc_table_info(tmp.size);
1221 if (!newinfo)
1222 return -ENOMEM;
1223
1224 /* choose the copy that is our node/cpu */
1225 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1226 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1227 tmp.size) != 0) {
1228 ret = -EFAULT;
1229 goto free_newinfo;
1230 }
1231
1232 ret = translate_table(tmp.name, tmp.valid_hooks,
1233 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1234 tmp.hook_entry, tmp.underflow);
1235 if (ret != 0)
1236 goto free_newinfo;
1237
1238 duprintf("ip_tables: Translated table\n");
1239
1240 ret = __do_replace(tmp.name, tmp.valid_hooks,
1241 newinfo, tmp.num_counters,
1242 tmp.counters);
1243 if (ret)
1244 goto free_newinfo_untrans;
1245 return 0;
1246
1247 free_newinfo_untrans:
1248 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1249 free_newinfo:
1250 xt_free_table_info(newinfo);
1251 return ret;
1252 }
1253
1254 /* We're lazy, and add to the first CPU; overflow works its fey magic
1255 * and everything is OK. */
1256 static inline int
1257 add_counter_to_entry(struct ipt_entry *e,
1258 const struct xt_counters addme[],
1259 unsigned int *i)
1260 {
1261 #if 0
1262 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1263 *i,
1264 (long unsigned int)e->counters.pcnt,
1265 (long unsigned int)e->counters.bcnt,
1266 (long unsigned int)addme[*i].pcnt,
1267 (long unsigned int)addme[*i].bcnt);
1268 #endif
1269
1270 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1271
1272 (*i)++;
1273 return 0;
1274 }
1275
1276 static int
1277 do_add_counters(void __user *user, unsigned int len, int compat)
1278 {
1279 unsigned int i;
1280 struct xt_counters_info tmp;
1281 struct xt_counters *paddc;
1282 unsigned int num_counters;
1283 char *name;
1284 int size;
1285 void *ptmp;
1286 struct ipt_table *t;
1287 struct xt_table_info *private;
1288 int ret = 0;
1289 void *loc_cpu_entry;
1290 #ifdef CONFIG_COMPAT
1291 struct compat_xt_counters_info compat_tmp;
1292
1293 if (compat) {
1294 ptmp = &compat_tmp;
1295 size = sizeof(struct compat_xt_counters_info);
1296 } else
1297 #endif
1298 {
1299 ptmp = &tmp;
1300 size = sizeof(struct xt_counters_info);
1301 }
1302
1303 if (copy_from_user(ptmp, user, size) != 0)
1304 return -EFAULT;
1305
1306 #ifdef CONFIG_COMPAT
1307 if (compat) {
1308 num_counters = compat_tmp.num_counters;
1309 name = compat_tmp.name;
1310 } else
1311 #endif
1312 {
1313 num_counters = tmp.num_counters;
1314 name = tmp.name;
1315 }
1316
1317 if (len != size + num_counters * sizeof(struct xt_counters))
1318 return -EINVAL;
1319
1320 paddc = vmalloc_node(len - size, numa_node_id());
1321 if (!paddc)
1322 return -ENOMEM;
1323
1324 if (copy_from_user(paddc, user + size, len - size) != 0) {
1325 ret = -EFAULT;
1326 goto free;
1327 }
1328
1329 t = xt_find_table_lock(AF_INET, name);
1330 if (!t || IS_ERR(t)) {
1331 ret = t ? PTR_ERR(t) : -ENOENT;
1332 goto free;
1333 }
1334
1335 write_lock_bh(&t->lock);
1336 private = t->private;
1337 if (private->number != num_counters) {
1338 ret = -EINVAL;
1339 goto unlock_up_free;
1340 }
1341
1342 i = 0;
1343 /* Choose the copy that is on our node */
1344 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1345 IPT_ENTRY_ITERATE(loc_cpu_entry,
1346 private->size,
1347 add_counter_to_entry,
1348 paddc,
1349 &i);
1350 unlock_up_free:
1351 write_unlock_bh(&t->lock);
1352 xt_table_unlock(t);
1353 module_put(t->me);
1354 free:
1355 vfree(paddc);
1356
1357 return ret;
1358 }
1359
1360 #ifdef CONFIG_COMPAT
1361 struct compat_ipt_replace {
1362 char name[IPT_TABLE_MAXNAMELEN];
1363 u32 valid_hooks;
1364 u32 num_entries;
1365 u32 size;
1366 u32 hook_entry[NF_IP_NUMHOOKS];
1367 u32 underflow[NF_IP_NUMHOOKS];
1368 u32 num_counters;
1369 compat_uptr_t counters; /* struct ipt_counters * */
1370 struct compat_ipt_entry entries[0];
1371 };
1372
1373 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1374 void __user **dstptr, compat_uint_t *size)
1375 {
1376 return xt_compat_match_to_user(m, dstptr, size);
1377 }
1378
1379 static int compat_copy_entry_to_user(struct ipt_entry *e,
1380 void __user **dstptr, compat_uint_t *size)
1381 {
1382 struct ipt_entry_target *t;
1383 struct compat_ipt_entry __user *ce;
1384 u_int16_t target_offset, next_offset;
1385 compat_uint_t origsize;
1386 int ret;
1387
1388 ret = -EFAULT;
1389 origsize = *size;
1390 ce = (struct compat_ipt_entry __user *)*dstptr;
1391 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1392 goto out;
1393
1394 *dstptr += sizeof(struct compat_ipt_entry);
1395 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1396 target_offset = e->target_offset - (origsize - *size);
1397 if (ret)
1398 goto out;
1399 t = ipt_get_target(e);
1400 ret = xt_compat_target_to_user(t, dstptr, size);
1401 if (ret)
1402 goto out;
1403 ret = -EFAULT;
1404 next_offset = e->next_offset - (origsize - *size);
1405 if (put_user(target_offset, &ce->target_offset))
1406 goto out;
1407 if (put_user(next_offset, &ce->next_offset))
1408 goto out;
1409 return 0;
1410 out:
1411 return ret;
1412 }
1413
1414 static inline int
1415 compat_check_calc_match(struct ipt_entry_match *m,
1416 const char *name,
1417 const struct ipt_ip *ip,
1418 unsigned int hookmask,
1419 int *size, int *i)
1420 {
1421 struct ipt_match *match;
1422
1423 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1424 m->u.user.revision),
1425 "ipt_%s", m->u.user.name);
1426 if (IS_ERR(match) || !match) {
1427 duprintf("compat_check_calc_match: `%s' not found\n",
1428 m->u.user.name);
1429 return match ? PTR_ERR(match) : -ENOENT;
1430 }
1431 m->u.kernel.match = match;
1432 *size += xt_compat_match_offset(match);
1433
1434 (*i)++;
1435 return 0;
1436 }
1437
1438 static inline int
1439 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1440 struct xt_table_info *newinfo,
1441 unsigned int *size,
1442 unsigned char *base,
1443 unsigned char *limit,
1444 unsigned int *hook_entries,
1445 unsigned int *underflows,
1446 unsigned int *i,
1447 const char *name)
1448 {
1449 struct ipt_entry_target *t;
1450 struct ipt_target *target;
1451 u_int16_t entry_offset;
1452 int ret, off, h, j;
1453
1454 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1455 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1456 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1457 duprintf("Bad offset %p, limit = %p\n", e, limit);
1458 return -EINVAL;
1459 }
1460
1461 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1462 sizeof(struct compat_xt_entry_target)) {
1463 duprintf("checking: element %p size %u\n",
1464 e, e->next_offset);
1465 return -EINVAL;
1466 }
1467
1468 if (!ip_checkentry(&e->ip)) {
1469 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1470 return -EINVAL;
1471 }
1472
1473 if (e->target_offset + sizeof(struct compat_xt_entry_target) >
1474 e->next_offset)
1475 return -EINVAL;
1476
1477 off = 0;
1478 entry_offset = (void *)e - (void *)base;
1479 j = 0;
1480 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1481 e->comefrom, &off, &j);
1482 if (ret != 0)
1483 goto cleanup_matches;
1484
1485 t = ipt_get_target(e);
1486 ret = -EINVAL;
1487 if (e->target_offset + t->u.target_size > e->next_offset)
1488 goto cleanup_matches;
1489 target = try_then_request_module(xt_find_target(AF_INET,
1490 t->u.user.name,
1491 t->u.user.revision),
1492 "ipt_%s", t->u.user.name);
1493 if (IS_ERR(target) || !target) {
1494 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1495 ret = target ? PTR_ERR(target) : -ENOENT;
1496 goto cleanup_matches;
1497 }
1498 t->u.kernel.target = target;
1499
1500 off += xt_compat_target_offset(target);
1501 *size += off;
1502 ret = compat_add_offset(entry_offset, off);
1503 if (ret)
1504 goto out;
1505
1506 /* Check hooks & underflows */
1507 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1508 if ((unsigned char *)e - base == hook_entries[h])
1509 newinfo->hook_entry[h] = hook_entries[h];
1510 if ((unsigned char *)e - base == underflows[h])
1511 newinfo->underflow[h] = underflows[h];
1512 }
1513
1514 /* Clear counters and comefrom */
1515 e->counters = ((struct ipt_counters) { 0, 0 });
1516 e->comefrom = 0;
1517
1518 (*i)++;
1519 return 0;
1520
1521 out:
1522 module_put(t->u.kernel.target->me);
1523 cleanup_matches:
1524 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1525 return ret;
1526 }
1527
1528 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1529 void **dstptr, compat_uint_t *size, const char *name,
1530 const struct ipt_ip *ip, unsigned int hookmask)
1531 {
1532 struct ipt_entry_match *dm;
1533 struct ipt_match *match;
1534 int ret;
1535
1536 dm = (struct ipt_entry_match *)*dstptr;
1537 match = m->u.kernel.match;
1538 xt_compat_match_from_user(m, dstptr, size);
1539
1540 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1541 name, hookmask, ip->proto,
1542 ip->invflags & IPT_INV_PROTO);
1543 if (!ret && m->u.kernel.match->checkentry
1544 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1545 hookmask)) {
1546 duprintf("ip_tables: check failed for `%s'.\n",
1547 m->u.kernel.match->name);
1548 ret = -EINVAL;
1549 }
1550 return ret;
1551 }
1552
1553 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1554 unsigned int *size, const char *name,
1555 struct xt_table_info *newinfo, unsigned char *base)
1556 {
1557 struct ipt_entry_target *t;
1558 struct ipt_target *target;
1559 struct ipt_entry *de;
1560 unsigned int origsize;
1561 int ret, h;
1562
1563 ret = 0;
1564 origsize = *size;
1565 de = (struct ipt_entry *)*dstptr;
1566 memcpy(de, e, sizeof(struct ipt_entry));
1567
1568 *dstptr += sizeof(struct compat_ipt_entry);
1569 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1570 name, &de->ip, de->comefrom);
1571 if (ret)
1572 goto err;
1573 de->target_offset = e->target_offset - (origsize - *size);
1574 t = ipt_get_target(e);
1575 target = t->u.kernel.target;
1576 xt_compat_target_from_user(t, dstptr, size);
1577
1578 de->next_offset = e->next_offset - (origsize - *size);
1579 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1580 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1581 newinfo->hook_entry[h] -= origsize - *size;
1582 if ((unsigned char *)de - base < newinfo->underflow[h])
1583 newinfo->underflow[h] -= origsize - *size;
1584 }
1585
1586 t = ipt_get_target(de);
1587 target = t->u.kernel.target;
1588 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1589 name, e->comefrom, e->ip.proto,
1590 e->ip.invflags & IPT_INV_PROTO);
1591 if (ret)
1592 goto err;
1593
1594 ret = -EINVAL;
1595 if (t->u.kernel.target == &ipt_standard_target) {
1596 if (!standard_check(t, *size))
1597 goto err;
1598 } else if (t->u.kernel.target->checkentry
1599 && !t->u.kernel.target->checkentry(name, de, target,
1600 t->data, de->comefrom)) {
1601 duprintf("ip_tables: compat: check failed for `%s'.\n",
1602 t->u.kernel.target->name);
1603 goto err;
1604 }
1605 ret = 0;
1606 err:
1607 return ret;
1608 }
1609
1610 static int
1611 translate_compat_table(const char *name,
1612 unsigned int valid_hooks,
1613 struct xt_table_info **pinfo,
1614 void **pentry0,
1615 unsigned int total_size,
1616 unsigned int number,
1617 unsigned int *hook_entries,
1618 unsigned int *underflows)
1619 {
1620 unsigned int i, j;
1621 struct xt_table_info *newinfo, *info;
1622 void *pos, *entry0, *entry1;
1623 unsigned int size;
1624 int ret;
1625
1626 info = *pinfo;
1627 entry0 = *pentry0;
1628 size = total_size;
1629 info->number = number;
1630
1631 /* Init all hooks to impossible value. */
1632 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1633 info->hook_entry[i] = 0xFFFFFFFF;
1634 info->underflow[i] = 0xFFFFFFFF;
1635 }
1636
1637 duprintf("translate_compat_table: size %u\n", info->size);
1638 j = 0;
1639 xt_compat_lock(AF_INET);
1640 /* Walk through entries, checking offsets. */
1641 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1642 check_compat_entry_size_and_hooks,
1643 info, &size, entry0,
1644 entry0 + total_size,
1645 hook_entries, underflows, &j, name);
1646 if (ret != 0)
1647 goto out_unlock;
1648
1649 ret = -EINVAL;
1650 if (j != number) {
1651 duprintf("translate_compat_table: %u not %u entries\n",
1652 j, number);
1653 goto out_unlock;
1654 }
1655
1656 /* Check hooks all assigned */
1657 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1658 /* Only hooks which are valid */
1659 if (!(valid_hooks & (1 << i)))
1660 continue;
1661 if (info->hook_entry[i] == 0xFFFFFFFF) {
1662 duprintf("Invalid hook entry %u %u\n",
1663 i, hook_entries[i]);
1664 goto out_unlock;
1665 }
1666 if (info->underflow[i] == 0xFFFFFFFF) {
1667 duprintf("Invalid underflow %u %u\n",
1668 i, underflows[i]);
1669 goto out_unlock;
1670 }
1671 }
1672
1673 ret = -ENOMEM;
1674 newinfo = xt_alloc_table_info(size);
1675 if (!newinfo)
1676 goto out_unlock;
1677
1678 newinfo->number = number;
1679 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1680 newinfo->hook_entry[i] = info->hook_entry[i];
1681 newinfo->underflow[i] = info->underflow[i];
1682 }
1683 entry1 = newinfo->entries[raw_smp_processor_id()];
1684 pos = entry1;
1685 size = total_size;
1686 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1687 compat_copy_entry_from_user, &pos, &size,
1688 name, newinfo, entry1);
1689 compat_flush_offsets();
1690 xt_compat_unlock(AF_INET);
1691 if (ret)
1692 goto free_newinfo;
1693
1694 ret = -ELOOP;
1695 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1696 goto free_newinfo;
1697
1698 /* And one copy for every other CPU */
1699 for_each_possible_cpu(i)
1700 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1701 memcpy(newinfo->entries[i], entry1, newinfo->size);
1702
1703 *pinfo = newinfo;
1704 *pentry0 = entry1;
1705 xt_free_table_info(info);
1706 return 0;
1707
1708 free_newinfo:
1709 xt_free_table_info(newinfo);
1710 out:
1711 IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
1712 return ret;
1713 out_unlock:
1714 compat_flush_offsets();
1715 xt_compat_unlock(AF_INET);
1716 goto out;
1717 }
1718
1719 static int
1720 compat_do_replace(void __user *user, unsigned int len)
1721 {
1722 int ret;
1723 struct compat_ipt_replace tmp;
1724 struct xt_table_info *newinfo;
1725 void *loc_cpu_entry;
1726
1727 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1728 return -EFAULT;
1729
1730 /* Hack: Causes ipchains to give correct error msg --RR */
1731 if (len != sizeof(tmp) + tmp.size)
1732 return -ENOPROTOOPT;
1733
1734 /* overflow check */
1735 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1736 SMP_CACHE_BYTES)
1737 return -ENOMEM;
1738 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1739 return -ENOMEM;
1740
1741 newinfo = xt_alloc_table_info(tmp.size);
1742 if (!newinfo)
1743 return -ENOMEM;
1744
1745 /* choose the copy that is our node/cpu */
1746 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1747 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1748 tmp.size) != 0) {
1749 ret = -EFAULT;
1750 goto free_newinfo;
1751 }
1752
1753 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1754 &newinfo, &loc_cpu_entry, tmp.size,
1755 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1756 if (ret != 0)
1757 goto free_newinfo;
1758
1759 duprintf("compat_do_replace: Translated table\n");
1760
1761 ret = __do_replace(tmp.name, tmp.valid_hooks,
1762 newinfo, tmp.num_counters,
1763 compat_ptr(tmp.counters));
1764 if (ret)
1765 goto free_newinfo_untrans;
1766 return 0;
1767
1768 free_newinfo_untrans:
1769 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1770 free_newinfo:
1771 xt_free_table_info(newinfo);
1772 return ret;
1773 }
1774
1775 static int
1776 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1777 unsigned int len)
1778 {
1779 int ret;
1780
1781 if (!capable(CAP_NET_ADMIN))
1782 return -EPERM;
1783
1784 switch (cmd) {
1785 case IPT_SO_SET_REPLACE:
1786 ret = compat_do_replace(user, len);
1787 break;
1788
1789 case IPT_SO_SET_ADD_COUNTERS:
1790 ret = do_add_counters(user, len, 1);
1791 break;
1792
1793 default:
1794 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1795 ret = -EINVAL;
1796 }
1797
1798 return ret;
1799 }
1800
1801 struct compat_ipt_get_entries
1802 {
1803 char name[IPT_TABLE_MAXNAMELEN];
1804 compat_uint_t size;
1805 struct compat_ipt_entry entrytable[0];
1806 };
1807
1808 static int compat_copy_entries_to_user(unsigned int total_size,
1809 struct ipt_table *table, void __user *userptr)
1810 {
1811 unsigned int off, num;
1812 struct compat_ipt_entry e;
1813 struct xt_counters *counters;
1814 struct xt_table_info *private = table->private;
1815 void __user *pos;
1816 unsigned int size;
1817 int ret = 0;
1818 void *loc_cpu_entry;
1819
1820 counters = alloc_counters(table);
1821 if (IS_ERR(counters))
1822 return PTR_ERR(counters);
1823
1824 /* choose the copy that is on our node/cpu, ...
1825 * This choice is lazy (because current thread is
1826 * allowed to migrate to another cpu)
1827 */
1828 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1829 pos = userptr;
1830 size = total_size;
1831 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1832 compat_copy_entry_to_user, &pos, &size);
1833 if (ret)
1834 goto free_counters;
1835
1836 /* ... then go back and fix counters and names */
1837 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1838 unsigned int i;
1839 struct ipt_entry_match m;
1840 struct ipt_entry_target t;
1841
1842 ret = -EFAULT;
1843 if (copy_from_user(&e, userptr + off,
1844 sizeof(struct compat_ipt_entry)))
1845 goto free_counters;
1846 if (copy_to_user(userptr + off +
1847 offsetof(struct compat_ipt_entry, counters),
1848 &counters[num], sizeof(counters[num])))
1849 goto free_counters;
1850
1851 for (i = sizeof(struct compat_ipt_entry);
1852 i < e.target_offset; i += m.u.match_size) {
1853 if (copy_from_user(&m, userptr + off + i,
1854 sizeof(struct ipt_entry_match)))
1855 goto free_counters;
1856 if (copy_to_user(userptr + off + i +
1857 offsetof(struct ipt_entry_match, u.user.name),
1858 m.u.kernel.match->name,
1859 strlen(m.u.kernel.match->name) + 1))
1860 goto free_counters;
1861 }
1862
1863 if (copy_from_user(&t, userptr + off + e.target_offset,
1864 sizeof(struct ipt_entry_target)))
1865 goto free_counters;
1866 if (copy_to_user(userptr + off + e.target_offset +
1867 offsetof(struct ipt_entry_target, u.user.name),
1868 t.u.kernel.target->name,
1869 strlen(t.u.kernel.target->name) + 1))
1870 goto free_counters;
1871 }
1872 ret = 0;
1873 free_counters:
1874 vfree(counters);
1875 return ret;
1876 }
1877
1878 static int
1879 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1880 {
1881 int ret;
1882 struct compat_ipt_get_entries get;
1883 struct ipt_table *t;
1884
1885
1886 if (*len < sizeof(get)) {
1887 duprintf("compat_get_entries: %u < %u\n",
1888 *len, (unsigned int)sizeof(get));
1889 return -EINVAL;
1890 }
1891
1892 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1893 return -EFAULT;
1894
1895 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1896 duprintf("compat_get_entries: %u != %u\n", *len,
1897 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1898 get.size));
1899 return -EINVAL;
1900 }
1901
1902 xt_compat_lock(AF_INET);
1903 t = xt_find_table_lock(AF_INET, get.name);
1904 if (t && !IS_ERR(t)) {
1905 struct xt_table_info *private = t->private;
1906 struct xt_table_info info;
1907 duprintf("t->private->number = %u\n",
1908 private->number);
1909 ret = compat_table_info(private, &info);
1910 if (!ret && get.size == info.size) {
1911 ret = compat_copy_entries_to_user(private->size,
1912 t, uptr->entrytable);
1913 } else if (!ret) {
1914 duprintf("compat_get_entries: I've got %u not %u!\n",
1915 private->size,
1916 get.size);
1917 ret = -EINVAL;
1918 }
1919 compat_flush_offsets();
1920 module_put(t->me);
1921 xt_table_unlock(t);
1922 } else
1923 ret = t ? PTR_ERR(t) : -ENOENT;
1924
1925 xt_compat_unlock(AF_INET);
1926 return ret;
1927 }
1928
1929 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1930
1931 static int
1932 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1933 {
1934 int ret;
1935
1936 if (!capable(CAP_NET_ADMIN))
1937 return -EPERM;
1938
1939 switch (cmd) {
1940 case IPT_SO_GET_INFO:
1941 ret = get_info(user, len, 1);
1942 break;
1943 case IPT_SO_GET_ENTRIES:
1944 ret = compat_get_entries(user, len);
1945 break;
1946 default:
1947 ret = do_ipt_get_ctl(sk, cmd, user, len);
1948 }
1949 return ret;
1950 }
1951 #endif
1952
1953 static int
1954 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1955 {
1956 int ret;
1957
1958 if (!capable(CAP_NET_ADMIN))
1959 return -EPERM;
1960
1961 switch (cmd) {
1962 case IPT_SO_SET_REPLACE:
1963 ret = do_replace(user, len);
1964 break;
1965
1966 case IPT_SO_SET_ADD_COUNTERS:
1967 ret = do_add_counters(user, len, 0);
1968 break;
1969
1970 default:
1971 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1972 ret = -EINVAL;
1973 }
1974
1975 return ret;
1976 }
1977
1978 static int
1979 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1980 {
1981 int ret;
1982
1983 if (!capable(CAP_NET_ADMIN))
1984 return -EPERM;
1985
1986 switch (cmd) {
1987 case IPT_SO_GET_INFO:
1988 ret = get_info(user, len, 0);
1989 break;
1990
1991 case IPT_SO_GET_ENTRIES:
1992 ret = get_entries(user, len);
1993 break;
1994
1995 case IPT_SO_GET_REVISION_MATCH:
1996 case IPT_SO_GET_REVISION_TARGET: {
1997 struct ipt_get_revision rev;
1998 int target;
1999
2000 if (*len != sizeof(rev)) {
2001 ret = -EINVAL;
2002 break;
2003 }
2004 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2005 ret = -EFAULT;
2006 break;
2007 }
2008
2009 if (cmd == IPT_SO_GET_REVISION_TARGET)
2010 target = 1;
2011 else
2012 target = 0;
2013
2014 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2015 rev.revision,
2016 target, &ret),
2017 "ipt_%s", rev.name);
2018 break;
2019 }
2020
2021 default:
2022 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2023 ret = -EINVAL;
2024 }
2025
2026 return ret;
2027 }
2028
2029 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2030 {
2031 int ret;
2032 struct xt_table_info *newinfo;
2033 static struct xt_table_info bootstrap
2034 = { 0, 0, 0, { 0 }, { 0 }, { } };
2035 void *loc_cpu_entry;
2036
2037 newinfo = xt_alloc_table_info(repl->size);
2038 if (!newinfo)
2039 return -ENOMEM;
2040
2041 /* choose the copy on our node/cpu
2042 * but dont care of preemption
2043 */
2044 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2045 memcpy(loc_cpu_entry, repl->entries, repl->size);
2046
2047 ret = translate_table(table->name, table->valid_hooks,
2048 newinfo, loc_cpu_entry, repl->size,
2049 repl->num_entries,
2050 repl->hook_entry,
2051 repl->underflow);
2052 if (ret != 0) {
2053 xt_free_table_info(newinfo);
2054 return ret;
2055 }
2056
2057 ret = xt_register_table(table, &bootstrap, newinfo);
2058 if (ret != 0) {
2059 xt_free_table_info(newinfo);
2060 return ret;
2061 }
2062
2063 return 0;
2064 }
2065
2066 void ipt_unregister_table(struct ipt_table *table)
2067 {
2068 struct xt_table_info *private;
2069 void *loc_cpu_entry;
2070
2071 private = xt_unregister_table(table);
2072
2073 /* Decrease module usage counts and free resources */
2074 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2075 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2076 xt_free_table_info(private);
2077 }
2078
2079 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2080 static inline int
2081 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2082 u_int8_t type, u_int8_t code,
2083 int invert)
2084 {
2085 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2086 ^ invert;
2087 }
2088
2089 static int
2090 icmp_match(const struct sk_buff *skb,
2091 const struct net_device *in,
2092 const struct net_device *out,
2093 const struct xt_match *match,
2094 const void *matchinfo,
2095 int offset,
2096 unsigned int protoff,
2097 int *hotdrop)
2098 {
2099 struct icmphdr _icmph, *ic;
2100 const struct ipt_icmp *icmpinfo = matchinfo;
2101
2102 /* Must not be a fragment. */
2103 if (offset)
2104 return 0;
2105
2106 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2107 if (ic == NULL) {
2108 /* We've been asked to examine this packet, and we
2109 * can't. Hence, no choice but to drop.
2110 */
2111 duprintf("Dropping evil ICMP tinygram.\n");
2112 *hotdrop = 1;
2113 return 0;
2114 }
2115
2116 return icmp_type_code_match(icmpinfo->type,
2117 icmpinfo->code[0],
2118 icmpinfo->code[1],
2119 ic->type, ic->code,
2120 !!(icmpinfo->invflags&IPT_ICMP_INV));
2121 }
2122
2123 /* Called when user tries to insert an entry of this type. */
2124 static int
2125 icmp_checkentry(const char *tablename,
2126 const void *info,
2127 const struct xt_match *match,
2128 void *matchinfo,
2129 unsigned int hook_mask)
2130 {
2131 const struct ipt_icmp *icmpinfo = matchinfo;
2132
2133 /* Must specify no unknown invflags */
2134 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2135 }
2136
2137 /* The built-in targets: standard (NULL) and error. */
2138 static struct ipt_target ipt_standard_target = {
2139 .name = IPT_STANDARD_TARGET,
2140 .targetsize = sizeof(int),
2141 .family = AF_INET,
2142 #ifdef CONFIG_COMPAT
2143 .compatsize = sizeof(compat_int_t),
2144 .compat_from_user = compat_standard_from_user,
2145 .compat_to_user = compat_standard_to_user,
2146 #endif
2147 };
2148
2149 static struct ipt_target ipt_error_target = {
2150 .name = IPT_ERROR_TARGET,
2151 .target = ipt_error,
2152 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2153 .family = AF_INET,
2154 };
2155
2156 static struct nf_sockopt_ops ipt_sockopts = {
2157 .pf = PF_INET,
2158 .set_optmin = IPT_BASE_CTL,
2159 .set_optmax = IPT_SO_SET_MAX+1,
2160 .set = do_ipt_set_ctl,
2161 #ifdef CONFIG_COMPAT
2162 .compat_set = compat_do_ipt_set_ctl,
2163 #endif
2164 .get_optmin = IPT_BASE_CTL,
2165 .get_optmax = IPT_SO_GET_MAX+1,
2166 .get = do_ipt_get_ctl,
2167 #ifdef CONFIG_COMPAT
2168 .compat_get = compat_do_ipt_get_ctl,
2169 #endif
2170 };
2171
2172 static struct ipt_match icmp_matchstruct = {
2173 .name = "icmp",
2174 .match = icmp_match,
2175 .matchsize = sizeof(struct ipt_icmp),
2176 .proto = IPPROTO_ICMP,
2177 .family = AF_INET,
2178 .checkentry = icmp_checkentry,
2179 };
2180
2181 static int __init ip_tables_init(void)
2182 {
2183 int ret;
2184
2185 ret = xt_proto_init(AF_INET);
2186 if (ret < 0)
2187 goto err1;
2188
2189 /* Noone else will be downing sem now, so we won't sleep */
2190 ret = xt_register_target(&ipt_standard_target);
2191 if (ret < 0)
2192 goto err2;
2193 ret = xt_register_target(&ipt_error_target);
2194 if (ret < 0)
2195 goto err3;
2196 ret = xt_register_match(&icmp_matchstruct);
2197 if (ret < 0)
2198 goto err4;
2199
2200 /* Register setsockopt */
2201 ret = nf_register_sockopt(&ipt_sockopts);
2202 if (ret < 0)
2203 goto err5;
2204
2205 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2206 return 0;
2207
2208 err5:
2209 xt_unregister_match(&icmp_matchstruct);
2210 err4:
2211 xt_unregister_target(&ipt_error_target);
2212 err3:
2213 xt_unregister_target(&ipt_standard_target);
2214 err2:
2215 xt_proto_fini(AF_INET);
2216 err1:
2217 return ret;
2218 }
2219
2220 static void __exit ip_tables_fini(void)
2221 {
2222 nf_unregister_sockopt(&ipt_sockopts);
2223
2224 xt_unregister_match(&icmp_matchstruct);
2225 xt_unregister_target(&ipt_error_target);
2226 xt_unregister_target(&ipt_standard_target);
2227
2228 xt_proto_fini(AF_INET);
2229 }
2230
2231 EXPORT_SYMBOL(ipt_register_table);
2232 EXPORT_SYMBOL(ipt_unregister_table);
2233 EXPORT_SYMBOL(ipt_do_table);
2234 module_init(ip_tables_init);
2235 module_exit(ip_tables_fini);
This page took 0.075957 seconds and 5 git commands to generate.