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