powerpc/fsl-booke: Fix problem with _tlbil_va being interrupted
[linux-ginger.git] / net / ipv4 / netfilter / ip_tables.c
blob213fb27debc1e583adb548b4628ad0ac782d3492
1 /*
2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
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.
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>
27 #include <linux/netfilter/x_tables.h>
28 #include <linux/netfilter_ipv4/ip_tables.h>
29 #include <net/netfilter/nf_log.h>
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
33 MODULE_DESCRIPTION("IPv4 packet filter");
35 /*#define DEBUG_IP_FIREWALL*/
36 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
37 /*#define DEBUG_IP_FIREWALL_USER*/
39 #ifdef DEBUG_IP_FIREWALL
40 #define dprintf(format, args...) printk(format , ## args)
41 #else
42 #define dprintf(format, args...)
43 #endif
45 #ifdef DEBUG_IP_FIREWALL_USER
46 #define duprintf(format, args...) printk(format , ## args)
47 #else
48 #define duprintf(format, args...)
49 #endif
51 #ifdef CONFIG_NETFILTER_DEBUG
52 #define IP_NF_ASSERT(x) \
53 do { \
54 if (!(x)) \
55 printk("IP_NF_ASSERT: %s:%s:%u\n", \
56 __func__, __FILE__, __LINE__); \
57 } while(0)
58 #else
59 #define IP_NF_ASSERT(x)
60 #endif
62 #if 0
63 /* All the better to debug you with... */
64 #define static
65 #define inline
66 #endif
69 We keep a set of rules for each CPU, so we can avoid write-locking
70 them in the softirq when updating the counters and therefore
71 only need to read-lock in the softirq; doing a write_lock_bh() in user
72 context stops packets coming through and allows user context to read
73 the counters or update the rules.
75 Hence the start of any table is given by get_table() below. */
77 /* Returns whether matches rule or not. */
78 /* Performance critical - called for every packet */
79 static inline bool
80 ip_packet_match(const struct iphdr *ip,
81 const char *indev,
82 const char *outdev,
83 const struct ipt_ip *ipinfo,
84 int isfrag)
86 size_t i;
87 unsigned long ret;
89 #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
91 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
92 IPT_INV_SRCIP)
93 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
94 IPT_INV_DSTIP)) {
95 dprintf("Source or dest mismatch.\n");
97 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
98 NIPQUAD(ip->saddr),
99 NIPQUAD(ipinfo->smsk.s_addr),
100 NIPQUAD(ipinfo->src.s_addr),
101 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
102 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
103 NIPQUAD(ip->daddr),
104 NIPQUAD(ipinfo->dmsk.s_addr),
105 NIPQUAD(ipinfo->dst.s_addr),
106 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
107 return false;
110 /* Look for ifname matches; this should unroll nicely. */
111 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
112 ret |= (((const unsigned long *)indev)[i]
113 ^ ((const unsigned long *)ipinfo->iniface)[i])
114 & ((const unsigned long *)ipinfo->iniface_mask)[i];
117 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
118 dprintf("VIA in mismatch (%s vs %s).%s\n",
119 indev, ipinfo->iniface,
120 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
121 return false;
124 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
125 ret |= (((const unsigned long *)outdev)[i]
126 ^ ((const unsigned long *)ipinfo->outiface)[i])
127 & ((const unsigned long *)ipinfo->outiface_mask)[i];
130 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
131 dprintf("VIA out mismatch (%s vs %s).%s\n",
132 outdev, ipinfo->outiface,
133 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
134 return false;
137 /* Check specific protocol */
138 if (ipinfo->proto
139 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
140 dprintf("Packet protocol %hi does not match %hi.%s\n",
141 ip->protocol, ipinfo->proto,
142 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
143 return false;
146 /* If we have a fragment rule but the packet is not a fragment
147 * then we return zero */
148 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
149 dprintf("Fragment rule but not fragment.%s\n",
150 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
151 return false;
154 return true;
157 static bool
158 ip_checkentry(const struct ipt_ip *ip)
160 if (ip->flags & ~IPT_F_MASK) {
161 duprintf("Unknown flag bits set: %08X\n",
162 ip->flags & ~IPT_F_MASK);
163 return false;
165 if (ip->invflags & ~IPT_INV_MASK) {
166 duprintf("Unknown invflag bits set: %08X\n",
167 ip->invflags & ~IPT_INV_MASK);
168 return false;
170 return true;
173 static unsigned int
174 ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
176 if (net_ratelimit())
177 printk("ip_tables: error: `%s'\n",
178 (const char *)par->targinfo);
180 return NF_DROP;
183 /* Performance critical - called for every packet */
184 static inline bool
185 do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
186 struct xt_match_param *par)
188 par->match = m->u.kernel.match;
189 par->matchinfo = m->data;
191 /* Stop iteration if it doesn't match */
192 if (!m->u.kernel.match->match(skb, par))
193 return true;
194 else
195 return false;
198 /* Performance critical */
199 static inline struct ipt_entry *
200 get_entry(void *base, unsigned int offset)
202 return (struct ipt_entry *)(base + offset);
205 /* All zeroes == unconditional rule. */
206 /* Mildly perf critical (only if packet tracing is on) */
207 static inline int
208 unconditional(const struct ipt_ip *ip)
210 unsigned int i;
212 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
213 if (((__u32 *)ip)[i])
214 return 0;
216 return 1;
217 #undef FWINV
220 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
221 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
222 static const char *const 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",
230 enum nf_ip_trace_comments {
231 NF_IP_TRACE_COMMENT_RULE,
232 NF_IP_TRACE_COMMENT_RETURN,
233 NF_IP_TRACE_COMMENT_POLICY,
236 static const char *const comments[] = {
237 [NF_IP_TRACE_COMMENT_RULE] = "rule",
238 [NF_IP_TRACE_COMMENT_RETURN] = "return",
239 [NF_IP_TRACE_COMMENT_POLICY] = "policy",
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,
252 /* Mildly perf critical (only if packet tracing is on) */
253 static inline int
254 get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
255 char *hookname, char **chainname,
256 char **comment, unsigned int *rulenum)
258 struct ipt_standard_target *t = (void *)ipt_get_target(s);
260 if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
261 /* Head of user chain: ERROR target with chainname */
262 *chainname = t->target.data;
263 (*rulenum) = 0;
264 } else if (s == e) {
265 (*rulenum)++;
267 if (s->target_offset == sizeof(struct ipt_entry)
268 && strcmp(t->target.u.kernel.target->name,
269 IPT_STANDARD_TARGET) == 0
270 && t->verdict < 0
271 && unconditional(&s->ip)) {
272 /* Tail of chains: STANDARD target (return/policy) */
273 *comment = *chainname == hookname
274 ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY]
275 : (char *)comments[NF_IP_TRACE_COMMENT_RETURN];
277 return 1;
278 } else
279 (*rulenum)++;
281 return 0;
284 static void trace_packet(struct sk_buff *skb,
285 unsigned int hook,
286 const struct net_device *in,
287 const struct net_device *out,
288 const char *tablename,
289 struct xt_table_info *private,
290 struct ipt_entry *e)
292 void *table_base;
293 const struct ipt_entry *root;
294 char *hookname, *chainname, *comment;
295 unsigned int rulenum = 0;
297 table_base = (void *)private->entries[smp_processor_id()];
298 root = get_entry(table_base, private->hook_entry[hook]);
300 hookname = chainname = (char *)hooknames[hook];
301 comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE];
303 IPT_ENTRY_ITERATE(root,
304 private->size - private->hook_entry[hook],
305 get_chainname_rulenum,
306 e, hookname, &chainname, &comment, &rulenum);
308 nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo,
309 "TRACE: %s:%s:%s:%u ",
310 tablename, chainname, comment, rulenum);
312 #endif
314 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
315 unsigned int
316 ipt_do_table(struct sk_buff *skb,
317 unsigned int hook,
318 const struct net_device *in,
319 const struct net_device *out,
320 struct xt_table *table)
322 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
323 const 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 struct xt_match_param mtpar;
333 struct xt_target_param tgpar;
335 /* Initialization */
336 ip = ip_hdr(skb);
337 datalen = skb->len - ip->ihl * 4;
338 indev = in ? in->name : nulldevname;
339 outdev = out ? out->name : nulldevname;
340 /* We handle fragments by dealing with the first fragment as
341 * if it was a normal packet. All other fragments are treated
342 * normally, except that they will NEVER match rules that ask
343 * things we don't know, ie. tcp syn flag or ports). If the
344 * rule is also a fragment-specific rule, non-fragments won't
345 * match it. */
346 mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
347 mtpar.thoff = ip_hdrlen(skb);
348 mtpar.hotdrop = &hotdrop;
349 mtpar.in = tgpar.in = in;
350 mtpar.out = tgpar.out = out;
351 mtpar.family = tgpar.family = NFPROTO_IPV4;
352 tgpar.hooknum = hook;
354 read_lock_bh(&table->lock);
355 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
356 private = table->private;
357 table_base = (void *)private->entries[smp_processor_id()];
358 e = get_entry(table_base, private->hook_entry[hook]);
360 /* For return from builtin chain */
361 back = get_entry(table_base, private->underflow[hook]);
363 do {
364 IP_NF_ASSERT(e);
365 IP_NF_ASSERT(back);
366 if (ip_packet_match(ip, indev, outdev,
367 &e->ip, mtpar.fragoff)) {
368 struct ipt_entry_target *t;
370 if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)
371 goto no_match;
373 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
375 t = ipt_get_target(e);
376 IP_NF_ASSERT(t->u.kernel.target);
378 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
379 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
380 /* The packet is traced: log it */
381 if (unlikely(skb->nf_trace))
382 trace_packet(skb, hook, in, out,
383 table->name, private, e);
384 #endif
385 /* Standard target? */
386 if (!t->u.kernel.target->target) {
387 int v;
389 v = ((struct ipt_standard_target *)t)->verdict;
390 if (v < 0) {
391 /* Pop from stack? */
392 if (v != IPT_RETURN) {
393 verdict = (unsigned)(-v) - 1;
394 break;
396 e = back;
397 back = get_entry(table_base,
398 back->comefrom);
399 continue;
401 if (table_base + v != (void *)e + e->next_offset
402 && !(e->ip.flags & IPT_F_GOTO)) {
403 /* Save old back ptr in next entry */
404 struct ipt_entry *next
405 = (void *)e + e->next_offset;
406 next->comefrom
407 = (void *)back - table_base;
408 /* set back pointer to next entry */
409 back = next;
412 e = get_entry(table_base, v);
413 } else {
414 /* Targets which reenter must return
415 abs. verdicts */
416 tgpar.target = t->u.kernel.target;
417 tgpar.targinfo = t->data;
418 #ifdef CONFIG_NETFILTER_DEBUG
419 ((struct ipt_entry *)table_base)->comefrom
420 = 0xeeeeeeec;
421 #endif
422 verdict = t->u.kernel.target->target(skb,
423 &tgpar);
424 #ifdef CONFIG_NETFILTER_DEBUG
425 if (((struct ipt_entry *)table_base)->comefrom
426 != 0xeeeeeeec
427 && verdict == IPT_CONTINUE) {
428 printk("Target %s reentered!\n",
429 t->u.kernel.target->name);
430 verdict = NF_DROP;
432 ((struct ipt_entry *)table_base)->comefrom
433 = 0x57acc001;
434 #endif
435 /* Target might have changed stuff. */
436 ip = ip_hdr(skb);
437 datalen = skb->len - ip->ihl * 4;
439 if (verdict == IPT_CONTINUE)
440 e = (void *)e + e->next_offset;
441 else
442 /* Verdict */
443 break;
445 } else {
447 no_match:
448 e = (void *)e + e->next_offset;
450 } while (!hotdrop);
452 read_unlock_bh(&table->lock);
454 #ifdef DEBUG_ALLOW_ALL
455 return NF_ACCEPT;
456 #else
457 if (hotdrop)
458 return NF_DROP;
459 else return verdict;
460 #endif
463 /* Figures out from what hook each rule can be called: returns 0 if
464 there are loops. Puts hook bitmask in comefrom. */
465 static int
466 mark_source_chains(struct xt_table_info *newinfo,
467 unsigned int valid_hooks, void *entry0)
469 unsigned int hook;
471 /* No recursion; use packet counter to save back ptrs (reset
472 to 0 as we leave), and comefrom to save source hook bitmask */
473 for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
474 unsigned int pos = newinfo->hook_entry[hook];
475 struct ipt_entry *e = (struct ipt_entry *)(entry0 + pos);
477 if (!(valid_hooks & (1 << hook)))
478 continue;
480 /* Set initial back pointer. */
481 e->counters.pcnt = pos;
483 for (;;) {
484 struct ipt_standard_target *t
485 = (void *)ipt_get_target(e);
486 int visited = e->comefrom & (1 << hook);
488 if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
489 printk("iptables: loop hook %u pos %u %08X.\n",
490 hook, pos, e->comefrom);
491 return 0;
493 e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
495 /* Unconditional return/END. */
496 if ((e->target_offset == sizeof(struct ipt_entry)
497 && (strcmp(t->target.u.user.name,
498 IPT_STANDARD_TARGET) == 0)
499 && t->verdict < 0
500 && unconditional(&e->ip)) || visited) {
501 unsigned int oldpos, size;
503 if (t->verdict < -NF_MAX_VERDICT - 1) {
504 duprintf("mark_source_chains: bad "
505 "negative verdict (%i)\n",
506 t->verdict);
507 return 0;
510 /* Return: backtrack through the last
511 big jump. */
512 do {
513 e->comefrom ^= (1<<NF_INET_NUMHOOKS);
514 #ifdef DEBUG_IP_FIREWALL_USER
515 if (e->comefrom
516 & (1 << NF_INET_NUMHOOKS)) {
517 duprintf("Back unset "
518 "on hook %u "
519 "rule %u\n",
520 hook, pos);
522 #endif
523 oldpos = pos;
524 pos = e->counters.pcnt;
525 e->counters.pcnt = 0;
527 /* We're at the start. */
528 if (pos == oldpos)
529 goto next;
531 e = (struct ipt_entry *)
532 (entry0 + pos);
533 } while (oldpos == pos + e->next_offset);
535 /* Move along one */
536 size = e->next_offset;
537 e = (struct ipt_entry *)
538 (entry0 + pos + size);
539 e->counters.pcnt = pos;
540 pos += size;
541 } else {
542 int newpos = t->verdict;
544 if (strcmp(t->target.u.user.name,
545 IPT_STANDARD_TARGET) == 0
546 && newpos >= 0) {
547 if (newpos > newinfo->size -
548 sizeof(struct ipt_entry)) {
549 duprintf("mark_source_chains: "
550 "bad verdict (%i)\n",
551 newpos);
552 return 0;
554 /* This a jump; chase it. */
555 duprintf("Jump rule %u -> %u\n",
556 pos, newpos);
557 } else {
558 /* ... this is a fallthru */
559 newpos = pos + e->next_offset;
561 e = (struct ipt_entry *)
562 (entry0 + newpos);
563 e->counters.pcnt = pos;
564 pos = newpos;
567 next:
568 duprintf("Finished chain %u\n", hook);
570 return 1;
573 static int
574 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
576 struct xt_mtdtor_param par;
578 if (i && (*i)-- == 0)
579 return 1;
581 par.match = m->u.kernel.match;
582 par.matchinfo = m->data;
583 par.family = NFPROTO_IPV4;
584 if (par.match->destroy != NULL)
585 par.match->destroy(&par);
586 module_put(par.match->me);
587 return 0;
590 static int
591 check_entry(struct ipt_entry *e, const char *name)
593 struct ipt_entry_target *t;
595 if (!ip_checkentry(&e->ip)) {
596 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
597 return -EINVAL;
600 if (e->target_offset + sizeof(struct ipt_entry_target) >
601 e->next_offset)
602 return -EINVAL;
604 t = ipt_get_target(e);
605 if (e->target_offset + t->u.target_size > e->next_offset)
606 return -EINVAL;
608 return 0;
611 static int
612 check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par,
613 unsigned int *i)
615 const struct ipt_ip *ip = par->entryinfo;
616 int ret;
618 par->match = m->u.kernel.match;
619 par->matchinfo = m->data;
621 ret = xt_check_match(par, m->u.match_size - sizeof(*m),
622 ip->proto, ip->invflags & IPT_INV_PROTO);
623 if (ret < 0) {
624 duprintf("ip_tables: check failed for `%s'.\n",
625 par.match->name);
626 return ret;
628 ++*i;
629 return 0;
632 static int
633 find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par,
634 unsigned int *i)
636 struct xt_match *match;
637 int ret;
639 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
640 m->u.user.revision),
641 "ipt_%s", m->u.user.name);
642 if (IS_ERR(match) || !match) {
643 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
644 return match ? PTR_ERR(match) : -ENOENT;
646 m->u.kernel.match = match;
648 ret = check_match(m, par, i);
649 if (ret)
650 goto err;
652 return 0;
653 err:
654 module_put(m->u.kernel.match->me);
655 return ret;
658 static int check_target(struct ipt_entry *e, const char *name)
660 struct ipt_entry_target *t = ipt_get_target(e);
661 struct xt_tgchk_param par = {
662 .table = name,
663 .entryinfo = e,
664 .target = t->u.kernel.target,
665 .targinfo = t->data,
666 .hook_mask = e->comefrom,
667 .family = NFPROTO_IPV4,
669 int ret;
671 ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
672 e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
673 if (ret < 0) {
674 duprintf("ip_tables: check failed for `%s'.\n",
675 t->u.kernel.target->name);
676 return ret;
678 return 0;
681 static int
682 find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
683 unsigned int *i)
685 struct ipt_entry_target *t;
686 struct xt_target *target;
687 int ret;
688 unsigned int j;
689 struct xt_mtchk_param mtpar;
691 ret = check_entry(e, name);
692 if (ret)
693 return ret;
695 j = 0;
696 mtpar.table = name;
697 mtpar.entryinfo = &e->ip;
698 mtpar.hook_mask = e->comefrom;
699 mtpar.family = NFPROTO_IPV4;
700 ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
701 if (ret != 0)
702 goto cleanup_matches;
704 t = ipt_get_target(e);
705 target = try_then_request_module(xt_find_target(AF_INET,
706 t->u.user.name,
707 t->u.user.revision),
708 "ipt_%s", t->u.user.name);
709 if (IS_ERR(target) || !target) {
710 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
711 ret = target ? PTR_ERR(target) : -ENOENT;
712 goto cleanup_matches;
714 t->u.kernel.target = target;
716 ret = check_target(e, name);
717 if (ret)
718 goto err;
720 (*i)++;
721 return 0;
722 err:
723 module_put(t->u.kernel.target->me);
724 cleanup_matches:
725 IPT_MATCH_ITERATE(e, cleanup_match, &j);
726 return ret;
729 static int
730 check_entry_size_and_hooks(struct ipt_entry *e,
731 struct xt_table_info *newinfo,
732 unsigned char *base,
733 unsigned char *limit,
734 const unsigned int *hook_entries,
735 const unsigned int *underflows,
736 unsigned int *i)
738 unsigned int h;
740 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
741 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
742 duprintf("Bad offset %p\n", e);
743 return -EINVAL;
746 if (e->next_offset
747 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
748 duprintf("checking: element %p size %u\n",
749 e, e->next_offset);
750 return -EINVAL;
753 /* Check hooks & underflows */
754 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
755 if ((unsigned char *)e - base == hook_entries[h])
756 newinfo->hook_entry[h] = hook_entries[h];
757 if ((unsigned char *)e - base == underflows[h])
758 newinfo->underflow[h] = underflows[h];
761 /* FIXME: underflows must be unconditional, standard verdicts
762 < 0 (not IPT_RETURN). --RR */
764 /* Clear counters and comefrom */
765 e->counters = ((struct xt_counters) { 0, 0 });
766 e->comefrom = 0;
768 (*i)++;
769 return 0;
772 static int
773 cleanup_entry(struct ipt_entry *e, unsigned int *i)
775 struct xt_tgdtor_param par;
776 struct ipt_entry_target *t;
778 if (i && (*i)-- == 0)
779 return 1;
781 /* Cleanup all matches */
782 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
783 t = ipt_get_target(e);
785 par.target = t->u.kernel.target;
786 par.targinfo = t->data;
787 par.family = NFPROTO_IPV4;
788 if (par.target->destroy != NULL)
789 par.target->destroy(&par);
790 module_put(par.target->me);
791 return 0;
794 /* Checks and translates the user-supplied table segment (held in
795 newinfo) */
796 static int
797 translate_table(const char *name,
798 unsigned int valid_hooks,
799 struct xt_table_info *newinfo,
800 void *entry0,
801 unsigned int size,
802 unsigned int number,
803 const unsigned int *hook_entries,
804 const unsigned int *underflows)
806 unsigned int i;
807 int ret;
809 newinfo->size = size;
810 newinfo->number = number;
812 /* Init all hooks to impossible value. */
813 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
814 newinfo->hook_entry[i] = 0xFFFFFFFF;
815 newinfo->underflow[i] = 0xFFFFFFFF;
818 duprintf("translate_table: size %u\n", newinfo->size);
819 i = 0;
820 /* Walk through entries, checking offsets. */
821 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
822 check_entry_size_and_hooks,
823 newinfo,
824 entry0,
825 entry0 + size,
826 hook_entries, underflows, &i);
827 if (ret != 0)
828 return ret;
830 if (i != number) {
831 duprintf("translate_table: %u not %u entries\n",
832 i, number);
833 return -EINVAL;
836 /* Check hooks all assigned */
837 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
838 /* Only hooks which are valid */
839 if (!(valid_hooks & (1 << i)))
840 continue;
841 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
842 duprintf("Invalid hook entry %u %u\n",
843 i, hook_entries[i]);
844 return -EINVAL;
846 if (newinfo->underflow[i] == 0xFFFFFFFF) {
847 duprintf("Invalid underflow %u %u\n",
848 i, underflows[i]);
849 return -EINVAL;
853 if (!mark_source_chains(newinfo, valid_hooks, entry0))
854 return -ELOOP;
856 /* Finally, each sanity check must pass */
857 i = 0;
858 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
859 find_check_entry, name, size, &i);
861 if (ret != 0) {
862 IPT_ENTRY_ITERATE(entry0, newinfo->size,
863 cleanup_entry, &i);
864 return ret;
867 /* And one copy for every other CPU */
868 for_each_possible_cpu(i) {
869 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
870 memcpy(newinfo->entries[i], entry0, newinfo->size);
873 return ret;
876 /* Gets counters. */
877 static inline int
878 add_entry_to_counter(const struct ipt_entry *e,
879 struct xt_counters total[],
880 unsigned int *i)
882 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
884 (*i)++;
885 return 0;
888 static inline int
889 set_entry_to_counter(const struct ipt_entry *e,
890 struct ipt_counters total[],
891 unsigned int *i)
893 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
895 (*i)++;
896 return 0;
899 static void
900 get_counters(const struct xt_table_info *t,
901 struct xt_counters counters[])
903 unsigned int cpu;
904 unsigned int i;
905 unsigned int curcpu;
907 /* Instead of clearing (by a previous call to memset())
908 * the counters and using adds, we set the counters
909 * with data used by 'current' CPU
910 * We dont care about preemption here.
912 curcpu = raw_smp_processor_id();
914 i = 0;
915 IPT_ENTRY_ITERATE(t->entries[curcpu],
916 t->size,
917 set_entry_to_counter,
918 counters,
919 &i);
921 for_each_possible_cpu(cpu) {
922 if (cpu == curcpu)
923 continue;
924 i = 0;
925 IPT_ENTRY_ITERATE(t->entries[cpu],
926 t->size,
927 add_entry_to_counter,
928 counters,
929 &i);
933 static struct xt_counters * alloc_counters(struct xt_table *table)
935 unsigned int countersize;
936 struct xt_counters *counters;
937 const struct xt_table_info *private = table->private;
939 /* We need atomic snapshot of counters: rest doesn't change
940 (other than comefrom, which userspace doesn't care
941 about). */
942 countersize = sizeof(struct xt_counters) * private->number;
943 counters = vmalloc_node(countersize, numa_node_id());
945 if (counters == NULL)
946 return ERR_PTR(-ENOMEM);
948 /* First, sum counters... */
949 write_lock_bh(&table->lock);
950 get_counters(private, counters);
951 write_unlock_bh(&table->lock);
953 return counters;
956 static int
957 copy_entries_to_user(unsigned int total_size,
958 struct xt_table *table,
959 void __user *userptr)
961 unsigned int off, num;
962 struct ipt_entry *e;
963 struct xt_counters *counters;
964 const struct xt_table_info *private = table->private;
965 int ret = 0;
966 const void *loc_cpu_entry;
968 counters = alloc_counters(table);
969 if (IS_ERR(counters))
970 return PTR_ERR(counters);
972 /* choose the copy that is on our node/cpu, ...
973 * This choice is lazy (because current thread is
974 * allowed to migrate to another cpu)
976 loc_cpu_entry = private->entries[raw_smp_processor_id()];
977 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
978 ret = -EFAULT;
979 goto free_counters;
982 /* FIXME: use iterator macros --RR */
983 /* ... then go back and fix counters and names */
984 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
985 unsigned int i;
986 const struct ipt_entry_match *m;
987 const struct ipt_entry_target *t;
989 e = (struct ipt_entry *)(loc_cpu_entry + off);
990 if (copy_to_user(userptr + off
991 + offsetof(struct ipt_entry, counters),
992 &counters[num],
993 sizeof(counters[num])) != 0) {
994 ret = -EFAULT;
995 goto free_counters;
998 for (i = sizeof(struct ipt_entry);
999 i < e->target_offset;
1000 i += m->u.match_size) {
1001 m = (void *)e + i;
1003 if (copy_to_user(userptr + off + i
1004 + offsetof(struct ipt_entry_match,
1005 u.user.name),
1006 m->u.kernel.match->name,
1007 strlen(m->u.kernel.match->name)+1)
1008 != 0) {
1009 ret = -EFAULT;
1010 goto free_counters;
1014 t = ipt_get_target(e);
1015 if (copy_to_user(userptr + off + e->target_offset
1016 + offsetof(struct ipt_entry_target,
1017 u.user.name),
1018 t->u.kernel.target->name,
1019 strlen(t->u.kernel.target->name)+1) != 0) {
1020 ret = -EFAULT;
1021 goto free_counters;
1025 free_counters:
1026 vfree(counters);
1027 return ret;
1030 #ifdef CONFIG_COMPAT
1031 static void compat_standard_from_user(void *dst, void *src)
1033 int v = *(compat_int_t *)src;
1035 if (v > 0)
1036 v += xt_compat_calc_jump(AF_INET, v);
1037 memcpy(dst, &v, sizeof(v));
1040 static int compat_standard_to_user(void __user *dst, void *src)
1042 compat_int_t cv = *(int *)src;
1044 if (cv > 0)
1045 cv -= xt_compat_calc_jump(AF_INET, cv);
1046 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1049 static inline int
1050 compat_calc_match(struct ipt_entry_match *m, int *size)
1052 *size += xt_compat_match_offset(m->u.kernel.match);
1053 return 0;
1056 static int compat_calc_entry(struct ipt_entry *e,
1057 const struct xt_table_info *info,
1058 void *base, struct xt_table_info *newinfo)
1060 struct ipt_entry_target *t;
1061 unsigned int entry_offset;
1062 int off, i, ret;
1064 off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1065 entry_offset = (void *)e - base;
1066 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1067 t = ipt_get_target(e);
1068 off += xt_compat_target_offset(t->u.kernel.target);
1069 newinfo->size -= off;
1070 ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1071 if (ret)
1072 return ret;
1074 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1075 if (info->hook_entry[i] &&
1076 (e < (struct ipt_entry *)(base + info->hook_entry[i])))
1077 newinfo->hook_entry[i] -= off;
1078 if (info->underflow[i] &&
1079 (e < (struct ipt_entry *)(base + info->underflow[i])))
1080 newinfo->underflow[i] -= off;
1082 return 0;
1085 static int compat_table_info(const struct xt_table_info *info,
1086 struct xt_table_info *newinfo)
1088 void *loc_cpu_entry;
1090 if (!newinfo || !info)
1091 return -EINVAL;
1093 /* we dont care about newinfo->entries[] */
1094 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1095 newinfo->initial_entries = 0;
1096 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1097 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1098 compat_calc_entry, info, loc_cpu_entry,
1099 newinfo);
1101 #endif
1103 static int get_info(struct net *net, void __user *user, int *len, int compat)
1105 char name[IPT_TABLE_MAXNAMELEN];
1106 struct xt_table *t;
1107 int ret;
1109 if (*len != sizeof(struct ipt_getinfo)) {
1110 duprintf("length %u != %zu\n", *len,
1111 sizeof(struct ipt_getinfo));
1112 return -EINVAL;
1115 if (copy_from_user(name, user, sizeof(name)) != 0)
1116 return -EFAULT;
1118 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1119 #ifdef CONFIG_COMPAT
1120 if (compat)
1121 xt_compat_lock(AF_INET);
1122 #endif
1123 t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
1124 "iptable_%s", name);
1125 if (t && !IS_ERR(t)) {
1126 struct ipt_getinfo info;
1127 const struct xt_table_info *private = t->private;
1129 #ifdef CONFIG_COMPAT
1130 if (compat) {
1131 struct xt_table_info tmp;
1132 ret = compat_table_info(private, &tmp);
1133 xt_compat_flush_offsets(AF_INET);
1134 private = &tmp;
1136 #endif
1137 info.valid_hooks = t->valid_hooks;
1138 memcpy(info.hook_entry, private->hook_entry,
1139 sizeof(info.hook_entry));
1140 memcpy(info.underflow, private->underflow,
1141 sizeof(info.underflow));
1142 info.num_entries = private->number;
1143 info.size = private->size;
1144 strcpy(info.name, name);
1146 if (copy_to_user(user, &info, *len) != 0)
1147 ret = -EFAULT;
1148 else
1149 ret = 0;
1151 xt_table_unlock(t);
1152 module_put(t->me);
1153 } else
1154 ret = t ? PTR_ERR(t) : -ENOENT;
1155 #ifdef CONFIG_COMPAT
1156 if (compat)
1157 xt_compat_unlock(AF_INET);
1158 #endif
1159 return ret;
1162 static int
1163 get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
1165 int ret;
1166 struct ipt_get_entries get;
1167 struct xt_table *t;
1169 if (*len < sizeof(get)) {
1170 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1171 return -EINVAL;
1173 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1174 return -EFAULT;
1175 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1176 duprintf("get_entries: %u != %zu\n",
1177 *len, sizeof(get) + get.size);
1178 return -EINVAL;
1181 t = xt_find_table_lock(net, AF_INET, get.name);
1182 if (t && !IS_ERR(t)) {
1183 const struct xt_table_info *private = t->private;
1184 duprintf("t->private->number = %u\n", private->number);
1185 if (get.size == private->size)
1186 ret = copy_entries_to_user(private->size,
1187 t, uptr->entrytable);
1188 else {
1189 duprintf("get_entries: I've got %u not %u!\n",
1190 private->size, get.size);
1191 ret = -EAGAIN;
1193 module_put(t->me);
1194 xt_table_unlock(t);
1195 } else
1196 ret = t ? PTR_ERR(t) : -ENOENT;
1198 return ret;
1201 static int
1202 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1203 struct xt_table_info *newinfo, unsigned int num_counters,
1204 void __user *counters_ptr)
1206 int ret;
1207 struct xt_table *t;
1208 struct xt_table_info *oldinfo;
1209 struct xt_counters *counters;
1210 void *loc_cpu_old_entry;
1212 ret = 0;
1213 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1214 if (!counters) {
1215 ret = -ENOMEM;
1216 goto out;
1219 t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
1220 "iptable_%s", name);
1221 if (!t || IS_ERR(t)) {
1222 ret = t ? PTR_ERR(t) : -ENOENT;
1223 goto free_newinfo_counters_untrans;
1226 /* You lied! */
1227 if (valid_hooks != t->valid_hooks) {
1228 duprintf("Valid hook crap: %08X vs %08X\n",
1229 valid_hooks, t->valid_hooks);
1230 ret = -EINVAL;
1231 goto put_module;
1234 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1235 if (!oldinfo)
1236 goto put_module;
1238 /* Update module usage count based on number of rules */
1239 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1240 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1241 if ((oldinfo->number > oldinfo->initial_entries) ||
1242 (newinfo->number <= oldinfo->initial_entries))
1243 module_put(t->me);
1244 if ((oldinfo->number > oldinfo->initial_entries) &&
1245 (newinfo->number <= oldinfo->initial_entries))
1246 module_put(t->me);
1248 /* Get the old counters. */
1249 get_counters(oldinfo, counters);
1250 /* Decrease module usage counts and free resource */
1251 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1252 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1253 NULL);
1254 xt_free_table_info(oldinfo);
1255 if (copy_to_user(counters_ptr, counters,
1256 sizeof(struct xt_counters) * num_counters) != 0)
1257 ret = -EFAULT;
1258 vfree(counters);
1259 xt_table_unlock(t);
1260 return ret;
1262 put_module:
1263 module_put(t->me);
1264 xt_table_unlock(t);
1265 free_newinfo_counters_untrans:
1266 vfree(counters);
1267 out:
1268 return ret;
1271 static int
1272 do_replace(struct net *net, void __user *user, unsigned int len)
1274 int ret;
1275 struct ipt_replace tmp;
1276 struct xt_table_info *newinfo;
1277 void *loc_cpu_entry;
1279 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1280 return -EFAULT;
1282 /* overflow check */
1283 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1284 return -ENOMEM;
1286 newinfo = xt_alloc_table_info(tmp.size);
1287 if (!newinfo)
1288 return -ENOMEM;
1290 /* choose the copy that is on our node/cpu */
1291 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1292 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1293 tmp.size) != 0) {
1294 ret = -EFAULT;
1295 goto free_newinfo;
1298 ret = translate_table(tmp.name, tmp.valid_hooks,
1299 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1300 tmp.hook_entry, tmp.underflow);
1301 if (ret != 0)
1302 goto free_newinfo;
1304 duprintf("ip_tables: Translated table\n");
1306 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1307 tmp.num_counters, tmp.counters);
1308 if (ret)
1309 goto free_newinfo_untrans;
1310 return 0;
1312 free_newinfo_untrans:
1313 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1314 free_newinfo:
1315 xt_free_table_info(newinfo);
1316 return ret;
1319 /* We're lazy, and add to the first CPU; overflow works its fey magic
1320 * and everything is OK. */
1321 static int
1322 add_counter_to_entry(struct ipt_entry *e,
1323 const struct xt_counters addme[],
1324 unsigned int *i)
1326 #if 0
1327 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1329 (long unsigned int)e->counters.pcnt,
1330 (long unsigned int)e->counters.bcnt,
1331 (long unsigned int)addme[*i].pcnt,
1332 (long unsigned int)addme[*i].bcnt);
1333 #endif
1335 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1337 (*i)++;
1338 return 0;
1341 static int
1342 do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
1344 unsigned int i;
1345 struct xt_counters_info tmp;
1346 struct xt_counters *paddc;
1347 unsigned int num_counters;
1348 const char *name;
1349 int size;
1350 void *ptmp;
1351 struct xt_table *t;
1352 const struct xt_table_info *private;
1353 int ret = 0;
1354 void *loc_cpu_entry;
1355 #ifdef CONFIG_COMPAT
1356 struct compat_xt_counters_info compat_tmp;
1358 if (compat) {
1359 ptmp = &compat_tmp;
1360 size = sizeof(struct compat_xt_counters_info);
1361 } else
1362 #endif
1364 ptmp = &tmp;
1365 size = sizeof(struct xt_counters_info);
1368 if (copy_from_user(ptmp, user, size) != 0)
1369 return -EFAULT;
1371 #ifdef CONFIG_COMPAT
1372 if (compat) {
1373 num_counters = compat_tmp.num_counters;
1374 name = compat_tmp.name;
1375 } else
1376 #endif
1378 num_counters = tmp.num_counters;
1379 name = tmp.name;
1382 if (len != size + num_counters * sizeof(struct xt_counters))
1383 return -EINVAL;
1385 paddc = vmalloc_node(len - size, numa_node_id());
1386 if (!paddc)
1387 return -ENOMEM;
1389 if (copy_from_user(paddc, user + size, len - size) != 0) {
1390 ret = -EFAULT;
1391 goto free;
1394 t = xt_find_table_lock(net, AF_INET, name);
1395 if (!t || IS_ERR(t)) {
1396 ret = t ? PTR_ERR(t) : -ENOENT;
1397 goto free;
1400 write_lock_bh(&t->lock);
1401 private = t->private;
1402 if (private->number != num_counters) {
1403 ret = -EINVAL;
1404 goto unlock_up_free;
1407 i = 0;
1408 /* Choose the copy that is on our node */
1409 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1410 IPT_ENTRY_ITERATE(loc_cpu_entry,
1411 private->size,
1412 add_counter_to_entry,
1413 paddc,
1414 &i);
1415 unlock_up_free:
1416 write_unlock_bh(&t->lock);
1417 xt_table_unlock(t);
1418 module_put(t->me);
1419 free:
1420 vfree(paddc);
1422 return ret;
1425 #ifdef CONFIG_COMPAT
1426 struct compat_ipt_replace {
1427 char name[IPT_TABLE_MAXNAMELEN];
1428 u32 valid_hooks;
1429 u32 num_entries;
1430 u32 size;
1431 u32 hook_entry[NF_INET_NUMHOOKS];
1432 u32 underflow[NF_INET_NUMHOOKS];
1433 u32 num_counters;
1434 compat_uptr_t counters; /* struct ipt_counters * */
1435 struct compat_ipt_entry entries[0];
1438 static int
1439 compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1440 unsigned int *size, struct xt_counters *counters,
1441 unsigned int *i)
1443 struct ipt_entry_target *t;
1444 struct compat_ipt_entry __user *ce;
1445 u_int16_t target_offset, next_offset;
1446 compat_uint_t origsize;
1447 int ret;
1449 ret = -EFAULT;
1450 origsize = *size;
1451 ce = (struct compat_ipt_entry __user *)*dstptr;
1452 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1453 goto out;
1455 if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1456 goto out;
1458 *dstptr += sizeof(struct compat_ipt_entry);
1459 *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1461 ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1462 target_offset = e->target_offset - (origsize - *size);
1463 if (ret)
1464 goto out;
1465 t = ipt_get_target(e);
1466 ret = xt_compat_target_to_user(t, dstptr, size);
1467 if (ret)
1468 goto out;
1469 ret = -EFAULT;
1470 next_offset = e->next_offset - (origsize - *size);
1471 if (put_user(target_offset, &ce->target_offset))
1472 goto out;
1473 if (put_user(next_offset, &ce->next_offset))
1474 goto out;
1476 (*i)++;
1477 return 0;
1478 out:
1479 return ret;
1482 static int
1483 compat_find_calc_match(struct ipt_entry_match *m,
1484 const char *name,
1485 const struct ipt_ip *ip,
1486 unsigned int hookmask,
1487 int *size, unsigned int *i)
1489 struct xt_match *match;
1491 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1492 m->u.user.revision),
1493 "ipt_%s", m->u.user.name);
1494 if (IS_ERR(match) || !match) {
1495 duprintf("compat_check_calc_match: `%s' not found\n",
1496 m->u.user.name);
1497 return match ? PTR_ERR(match) : -ENOENT;
1499 m->u.kernel.match = match;
1500 *size += xt_compat_match_offset(match);
1502 (*i)++;
1503 return 0;
1506 static int
1507 compat_release_match(struct ipt_entry_match *m, unsigned int *i)
1509 if (i && (*i)-- == 0)
1510 return 1;
1512 module_put(m->u.kernel.match->me);
1513 return 0;
1516 static int
1517 compat_release_entry(struct compat_ipt_entry *e, unsigned int *i)
1519 struct ipt_entry_target *t;
1521 if (i && (*i)-- == 0)
1522 return 1;
1524 /* Cleanup all matches */
1525 COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL);
1526 t = compat_ipt_get_target(e);
1527 module_put(t->u.kernel.target->me);
1528 return 0;
1531 static int
1532 check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1533 struct xt_table_info *newinfo,
1534 unsigned int *size,
1535 unsigned char *base,
1536 unsigned char *limit,
1537 unsigned int *hook_entries,
1538 unsigned int *underflows,
1539 unsigned int *i,
1540 const char *name)
1542 struct ipt_entry_target *t;
1543 struct xt_target *target;
1544 unsigned int entry_offset;
1545 unsigned int j;
1546 int ret, off, h;
1548 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1549 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1550 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1551 duprintf("Bad offset %p, limit = %p\n", e, limit);
1552 return -EINVAL;
1555 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1556 sizeof(struct compat_xt_entry_target)) {
1557 duprintf("checking: element %p size %u\n",
1558 e, e->next_offset);
1559 return -EINVAL;
1562 /* For purposes of check_entry casting the compat entry is fine */
1563 ret = check_entry((struct ipt_entry *)e, name);
1564 if (ret)
1565 return ret;
1567 off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1568 entry_offset = (void *)e - (void *)base;
1569 j = 0;
1570 ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name,
1571 &e->ip, e->comefrom, &off, &j);
1572 if (ret != 0)
1573 goto release_matches;
1575 t = compat_ipt_get_target(e);
1576 target = try_then_request_module(xt_find_target(AF_INET,
1577 t->u.user.name,
1578 t->u.user.revision),
1579 "ipt_%s", t->u.user.name);
1580 if (IS_ERR(target) || !target) {
1581 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1582 t->u.user.name);
1583 ret = target ? PTR_ERR(target) : -ENOENT;
1584 goto release_matches;
1586 t->u.kernel.target = target;
1588 off += xt_compat_target_offset(target);
1589 *size += off;
1590 ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1591 if (ret)
1592 goto out;
1594 /* Check hooks & underflows */
1595 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1596 if ((unsigned char *)e - base == hook_entries[h])
1597 newinfo->hook_entry[h] = hook_entries[h];
1598 if ((unsigned char *)e - base == underflows[h])
1599 newinfo->underflow[h] = underflows[h];
1602 /* Clear counters and comefrom */
1603 memset(&e->counters, 0, sizeof(e->counters));
1604 e->comefrom = 0;
1606 (*i)++;
1607 return 0;
1609 out:
1610 module_put(t->u.kernel.target->me);
1611 release_matches:
1612 IPT_MATCH_ITERATE(e, compat_release_match, &j);
1613 return ret;
1616 static int
1617 compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
1618 unsigned int *size, const char *name,
1619 struct xt_table_info *newinfo, unsigned char *base)
1621 struct ipt_entry_target *t;
1622 struct xt_target *target;
1623 struct ipt_entry *de;
1624 unsigned int origsize;
1625 int ret, h;
1627 ret = 0;
1628 origsize = *size;
1629 de = (struct ipt_entry *)*dstptr;
1630 memcpy(de, e, sizeof(struct ipt_entry));
1631 memcpy(&de->counters, &e->counters, sizeof(e->counters));
1633 *dstptr += sizeof(struct ipt_entry);
1634 *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1636 ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user,
1637 dstptr, size);
1638 if (ret)
1639 return ret;
1640 de->target_offset = e->target_offset - (origsize - *size);
1641 t = compat_ipt_get_target(e);
1642 target = t->u.kernel.target;
1643 xt_compat_target_from_user(t, dstptr, size);
1645 de->next_offset = e->next_offset - (origsize - *size);
1646 for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1647 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1648 newinfo->hook_entry[h] -= origsize - *size;
1649 if ((unsigned char *)de - base < newinfo->underflow[h])
1650 newinfo->underflow[h] -= origsize - *size;
1652 return ret;
1655 static int
1656 compat_check_entry(struct ipt_entry *e, const char *name,
1657 unsigned int *i)
1659 struct xt_mtchk_param mtpar;
1660 unsigned int j;
1661 int ret;
1663 j = 0;
1664 mtpar.table = name;
1665 mtpar.entryinfo = &e->ip;
1666 mtpar.hook_mask = e->comefrom;
1667 mtpar.family = NFPROTO_IPV4;
1668 ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j);
1669 if (ret)
1670 goto cleanup_matches;
1672 ret = check_target(e, name);
1673 if (ret)
1674 goto cleanup_matches;
1676 (*i)++;
1677 return 0;
1679 cleanup_matches:
1680 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1681 return ret;
1684 static int
1685 translate_compat_table(const char *name,
1686 unsigned int valid_hooks,
1687 struct xt_table_info **pinfo,
1688 void **pentry0,
1689 unsigned int total_size,
1690 unsigned int number,
1691 unsigned int *hook_entries,
1692 unsigned int *underflows)
1694 unsigned int i, j;
1695 struct xt_table_info *newinfo, *info;
1696 void *pos, *entry0, *entry1;
1697 unsigned int size;
1698 int ret;
1700 info = *pinfo;
1701 entry0 = *pentry0;
1702 size = total_size;
1703 info->number = number;
1705 /* Init all hooks to impossible value. */
1706 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1707 info->hook_entry[i] = 0xFFFFFFFF;
1708 info->underflow[i] = 0xFFFFFFFF;
1711 duprintf("translate_compat_table: size %u\n", info->size);
1712 j = 0;
1713 xt_compat_lock(AF_INET);
1714 /* Walk through entries, checking offsets. */
1715 ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1716 check_compat_entry_size_and_hooks,
1717 info, &size, entry0,
1718 entry0 + total_size,
1719 hook_entries, underflows, &j, name);
1720 if (ret != 0)
1721 goto out_unlock;
1723 ret = -EINVAL;
1724 if (j != number) {
1725 duprintf("translate_compat_table: %u not %u entries\n",
1726 j, number);
1727 goto out_unlock;
1730 /* Check hooks all assigned */
1731 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1732 /* Only hooks which are valid */
1733 if (!(valid_hooks & (1 << i)))
1734 continue;
1735 if (info->hook_entry[i] == 0xFFFFFFFF) {
1736 duprintf("Invalid hook entry %u %u\n",
1737 i, hook_entries[i]);
1738 goto out_unlock;
1740 if (info->underflow[i] == 0xFFFFFFFF) {
1741 duprintf("Invalid underflow %u %u\n",
1742 i, underflows[i]);
1743 goto out_unlock;
1747 ret = -ENOMEM;
1748 newinfo = xt_alloc_table_info(size);
1749 if (!newinfo)
1750 goto out_unlock;
1752 newinfo->number = number;
1753 for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1754 newinfo->hook_entry[i] = info->hook_entry[i];
1755 newinfo->underflow[i] = info->underflow[i];
1757 entry1 = newinfo->entries[raw_smp_processor_id()];
1758 pos = entry1;
1759 size = total_size;
1760 ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size,
1761 compat_copy_entry_from_user,
1762 &pos, &size, name, newinfo, entry1);
1763 xt_compat_flush_offsets(AF_INET);
1764 xt_compat_unlock(AF_INET);
1765 if (ret)
1766 goto free_newinfo;
1768 ret = -ELOOP;
1769 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1770 goto free_newinfo;
1772 i = 0;
1773 ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1774 name, &i);
1775 if (ret) {
1776 j -= i;
1777 COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1778 compat_release_entry, &j);
1779 IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1780 xt_free_table_info(newinfo);
1781 return ret;
1784 /* And one copy for every other CPU */
1785 for_each_possible_cpu(i)
1786 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1787 memcpy(newinfo->entries[i], entry1, newinfo->size);
1789 *pinfo = newinfo;
1790 *pentry0 = entry1;
1791 xt_free_table_info(info);
1792 return 0;
1794 free_newinfo:
1795 xt_free_table_info(newinfo);
1796 out:
1797 COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1798 return ret;
1799 out_unlock:
1800 xt_compat_flush_offsets(AF_INET);
1801 xt_compat_unlock(AF_INET);
1802 goto out;
1805 static int
1806 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1808 int ret;
1809 struct compat_ipt_replace tmp;
1810 struct xt_table_info *newinfo;
1811 void *loc_cpu_entry;
1813 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1814 return -EFAULT;
1816 /* overflow check */
1817 if (tmp.size >= INT_MAX / num_possible_cpus())
1818 return -ENOMEM;
1819 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1820 return -ENOMEM;
1822 newinfo = xt_alloc_table_info(tmp.size);
1823 if (!newinfo)
1824 return -ENOMEM;
1826 /* choose the copy that is on our node/cpu */
1827 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1828 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1829 tmp.size) != 0) {
1830 ret = -EFAULT;
1831 goto free_newinfo;
1834 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1835 &newinfo, &loc_cpu_entry, tmp.size,
1836 tmp.num_entries, tmp.hook_entry,
1837 tmp.underflow);
1838 if (ret != 0)
1839 goto free_newinfo;
1841 duprintf("compat_do_replace: Translated table\n");
1843 ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1844 tmp.num_counters, compat_ptr(tmp.counters));
1845 if (ret)
1846 goto free_newinfo_untrans;
1847 return 0;
1849 free_newinfo_untrans:
1850 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1851 free_newinfo:
1852 xt_free_table_info(newinfo);
1853 return ret;
1856 static int
1857 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1858 unsigned int len)
1860 int ret;
1862 if (!capable(CAP_NET_ADMIN))
1863 return -EPERM;
1865 switch (cmd) {
1866 case IPT_SO_SET_REPLACE:
1867 ret = compat_do_replace(sock_net(sk), user, len);
1868 break;
1870 case IPT_SO_SET_ADD_COUNTERS:
1871 ret = do_add_counters(sock_net(sk), user, len, 1);
1872 break;
1874 default:
1875 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1876 ret = -EINVAL;
1879 return ret;
1882 struct compat_ipt_get_entries {
1883 char name[IPT_TABLE_MAXNAMELEN];
1884 compat_uint_t size;
1885 struct compat_ipt_entry entrytable[0];
1888 static int
1889 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1890 void __user *userptr)
1892 struct xt_counters *counters;
1893 const struct xt_table_info *private = table->private;
1894 void __user *pos;
1895 unsigned int size;
1896 int ret = 0;
1897 const void *loc_cpu_entry;
1898 unsigned int i = 0;
1900 counters = alloc_counters(table);
1901 if (IS_ERR(counters))
1902 return PTR_ERR(counters);
1904 /* choose the copy that is on our node/cpu, ...
1905 * This choice is lazy (because current thread is
1906 * allowed to migrate to another cpu)
1908 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1909 pos = userptr;
1910 size = total_size;
1911 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1912 compat_copy_entry_to_user,
1913 &pos, &size, counters, &i);
1915 vfree(counters);
1916 return ret;
1919 static int
1920 compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
1921 int *len)
1923 int ret;
1924 struct compat_ipt_get_entries get;
1925 struct xt_table *t;
1927 if (*len < sizeof(get)) {
1928 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1929 return -EINVAL;
1932 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1933 return -EFAULT;
1935 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1936 duprintf("compat_get_entries: %u != %zu\n",
1937 *len, sizeof(get) + get.size);
1938 return -EINVAL;
1941 xt_compat_lock(AF_INET);
1942 t = xt_find_table_lock(net, AF_INET, get.name);
1943 if (t && !IS_ERR(t)) {
1944 const struct xt_table_info *private = t->private;
1945 struct xt_table_info info;
1946 duprintf("t->private->number = %u\n", private->number);
1947 ret = compat_table_info(private, &info);
1948 if (!ret && get.size == info.size) {
1949 ret = compat_copy_entries_to_user(private->size,
1950 t, uptr->entrytable);
1951 } else if (!ret) {
1952 duprintf("compat_get_entries: I've got %u not %u!\n",
1953 private->size, get.size);
1954 ret = -EAGAIN;
1956 xt_compat_flush_offsets(AF_INET);
1957 module_put(t->me);
1958 xt_table_unlock(t);
1959 } else
1960 ret = t ? PTR_ERR(t) : -ENOENT;
1962 xt_compat_unlock(AF_INET);
1963 return ret;
1966 static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1968 static int
1969 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1971 int ret;
1973 if (!capable(CAP_NET_ADMIN))
1974 return -EPERM;
1976 switch (cmd) {
1977 case IPT_SO_GET_INFO:
1978 ret = get_info(sock_net(sk), user, len, 1);
1979 break;
1980 case IPT_SO_GET_ENTRIES:
1981 ret = compat_get_entries(sock_net(sk), user, len);
1982 break;
1983 default:
1984 ret = do_ipt_get_ctl(sk, cmd, user, len);
1986 return ret;
1988 #endif
1990 static int
1991 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1993 int ret;
1995 if (!capable(CAP_NET_ADMIN))
1996 return -EPERM;
1998 switch (cmd) {
1999 case IPT_SO_SET_REPLACE:
2000 ret = do_replace(sock_net(sk), user, len);
2001 break;
2003 case IPT_SO_SET_ADD_COUNTERS:
2004 ret = do_add_counters(sock_net(sk), user, len, 0);
2005 break;
2007 default:
2008 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
2009 ret = -EINVAL;
2012 return ret;
2015 static int
2016 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2018 int ret;
2020 if (!capable(CAP_NET_ADMIN))
2021 return -EPERM;
2023 switch (cmd) {
2024 case IPT_SO_GET_INFO:
2025 ret = get_info(sock_net(sk), user, len, 0);
2026 break;
2028 case IPT_SO_GET_ENTRIES:
2029 ret = get_entries(sock_net(sk), user, len);
2030 break;
2032 case IPT_SO_GET_REVISION_MATCH:
2033 case IPT_SO_GET_REVISION_TARGET: {
2034 struct ipt_get_revision rev;
2035 int target;
2037 if (*len != sizeof(rev)) {
2038 ret = -EINVAL;
2039 break;
2041 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2042 ret = -EFAULT;
2043 break;
2046 if (cmd == IPT_SO_GET_REVISION_TARGET)
2047 target = 1;
2048 else
2049 target = 0;
2051 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2052 rev.revision,
2053 target, &ret),
2054 "ipt_%s", rev.name);
2055 break;
2058 default:
2059 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2060 ret = -EINVAL;
2063 return ret;
2066 struct xt_table *ipt_register_table(struct net *net, struct xt_table *table,
2067 const struct ipt_replace *repl)
2069 int ret;
2070 struct xt_table_info *newinfo;
2071 struct xt_table_info bootstrap
2072 = { 0, 0, 0, { 0 }, { 0 }, { } };
2073 void *loc_cpu_entry;
2074 struct xt_table *new_table;
2076 newinfo = xt_alloc_table_info(repl->size);
2077 if (!newinfo) {
2078 ret = -ENOMEM;
2079 goto out;
2082 /* choose the copy on our node/cpu, but dont care about preemption */
2083 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2084 memcpy(loc_cpu_entry, repl->entries, repl->size);
2086 ret = translate_table(table->name, table->valid_hooks,
2087 newinfo, loc_cpu_entry, repl->size,
2088 repl->num_entries,
2089 repl->hook_entry,
2090 repl->underflow);
2091 if (ret != 0)
2092 goto out_free;
2094 new_table = xt_register_table(net, table, &bootstrap, newinfo);
2095 if (IS_ERR(new_table)) {
2096 ret = PTR_ERR(new_table);
2097 goto out_free;
2100 return new_table;
2102 out_free:
2103 xt_free_table_info(newinfo);
2104 out:
2105 return ERR_PTR(ret);
2108 void ipt_unregister_table(struct xt_table *table)
2110 struct xt_table_info *private;
2111 void *loc_cpu_entry;
2112 struct module *table_owner = table->me;
2114 private = xt_unregister_table(table);
2116 /* Decrease module usage counts and free resources */
2117 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2118 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2119 if (private->number > private->initial_entries)
2120 module_put(table_owner);
2121 xt_free_table_info(private);
2124 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2125 static inline bool
2126 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2127 u_int8_t type, u_int8_t code,
2128 bool invert)
2130 return ((test_type == 0xFF) ||
2131 (type == test_type && code >= min_code && code <= max_code))
2132 ^ invert;
2135 static bool
2136 icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
2138 const struct icmphdr *ic;
2139 struct icmphdr _icmph;
2140 const struct ipt_icmp *icmpinfo = par->matchinfo;
2142 /* Must not be a fragment. */
2143 if (par->fragoff != 0)
2144 return false;
2146 ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2147 if (ic == NULL) {
2148 /* We've been asked to examine this packet, and we
2149 * can't. Hence, no choice but to drop.
2151 duprintf("Dropping evil ICMP tinygram.\n");
2152 *par->hotdrop = true;
2153 return false;
2156 return icmp_type_code_match(icmpinfo->type,
2157 icmpinfo->code[0],
2158 icmpinfo->code[1],
2159 ic->type, ic->code,
2160 !!(icmpinfo->invflags&IPT_ICMP_INV));
2163 static bool icmp_checkentry(const struct xt_mtchk_param *par)
2165 const struct ipt_icmp *icmpinfo = par->matchinfo;
2167 /* Must specify no unknown invflags */
2168 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2171 /* The built-in targets: standard (NULL) and error. */
2172 static struct xt_target ipt_standard_target __read_mostly = {
2173 .name = IPT_STANDARD_TARGET,
2174 .targetsize = sizeof(int),
2175 .family = AF_INET,
2176 #ifdef CONFIG_COMPAT
2177 .compatsize = sizeof(compat_int_t),
2178 .compat_from_user = compat_standard_from_user,
2179 .compat_to_user = compat_standard_to_user,
2180 #endif
2183 static struct xt_target ipt_error_target __read_mostly = {
2184 .name = IPT_ERROR_TARGET,
2185 .target = ipt_error,
2186 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2187 .family = AF_INET,
2190 static struct nf_sockopt_ops ipt_sockopts = {
2191 .pf = PF_INET,
2192 .set_optmin = IPT_BASE_CTL,
2193 .set_optmax = IPT_SO_SET_MAX+1,
2194 .set = do_ipt_set_ctl,
2195 #ifdef CONFIG_COMPAT
2196 .compat_set = compat_do_ipt_set_ctl,
2197 #endif
2198 .get_optmin = IPT_BASE_CTL,
2199 .get_optmax = IPT_SO_GET_MAX+1,
2200 .get = do_ipt_get_ctl,
2201 #ifdef CONFIG_COMPAT
2202 .compat_get = compat_do_ipt_get_ctl,
2203 #endif
2204 .owner = THIS_MODULE,
2207 static struct xt_match icmp_matchstruct __read_mostly = {
2208 .name = "icmp",
2209 .match = icmp_match,
2210 .matchsize = sizeof(struct ipt_icmp),
2211 .checkentry = icmp_checkentry,
2212 .proto = IPPROTO_ICMP,
2213 .family = AF_INET,
2216 static int __net_init ip_tables_net_init(struct net *net)
2218 return xt_proto_init(net, AF_INET);
2221 static void __net_exit ip_tables_net_exit(struct net *net)
2223 xt_proto_fini(net, AF_INET);
2226 static struct pernet_operations ip_tables_net_ops = {
2227 .init = ip_tables_net_init,
2228 .exit = ip_tables_net_exit,
2231 static int __init ip_tables_init(void)
2233 int ret;
2235 ret = register_pernet_subsys(&ip_tables_net_ops);
2236 if (ret < 0)
2237 goto err1;
2239 /* Noone else will be downing sem now, so we won't sleep */
2240 ret = xt_register_target(&ipt_standard_target);
2241 if (ret < 0)
2242 goto err2;
2243 ret = xt_register_target(&ipt_error_target);
2244 if (ret < 0)
2245 goto err3;
2246 ret = xt_register_match(&icmp_matchstruct);
2247 if (ret < 0)
2248 goto err4;
2250 /* Register setsockopt */
2251 ret = nf_register_sockopt(&ipt_sockopts);
2252 if (ret < 0)
2253 goto err5;
2255 printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2256 return 0;
2258 err5:
2259 xt_unregister_match(&icmp_matchstruct);
2260 err4:
2261 xt_unregister_target(&ipt_error_target);
2262 err3:
2263 xt_unregister_target(&ipt_standard_target);
2264 err2:
2265 unregister_pernet_subsys(&ip_tables_net_ops);
2266 err1:
2267 return ret;
2270 static void __exit ip_tables_fini(void)
2272 nf_unregister_sockopt(&ipt_sockopts);
2274 xt_unregister_match(&icmp_matchstruct);
2275 xt_unregister_target(&ipt_error_target);
2276 xt_unregister_target(&ipt_standard_target);
2278 unregister_pernet_subsys(&ip_tables_net_ops);
2281 EXPORT_SYMBOL(ipt_register_table);
2282 EXPORT_SYMBOL(ipt_unregister_table);
2283 EXPORT_SYMBOL(ipt_do_table);
2284 module_init(ip_tables_init);
2285 module_exit(ip_tables_fini);