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 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
15 * - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
17 #include <linux/cache.h>
18 #include <linux/capability.h>
19 #include <linux/skbuff.h>
20 #include <linux/kmod.h>
21 #include <linux/vmalloc.h>
22 #include <linux/netdevice.h>
23 #include <linux/module.h>
24 #include <linux/icmp.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ip_tables.h>
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
38 MODULE_DESCRIPTION("IPv4 packet filter");
40 /*#define DEBUG_IP_FIREWALL*/
41 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
42 /*#define DEBUG_IP_FIREWALL_USER*/
44 #ifdef DEBUG_IP_FIREWALL
45 #define dprintf(format, args...) printk(format , ## args)
47 #define dprintf(format, args...)
50 #ifdef DEBUG_IP_FIREWALL_USER
51 #define duprintf(format, args...) printk(format , ## args)
53 #define duprintf(format, args...)
56 #ifdef CONFIG_NETFILTER_DEBUG
57 #define IP_NF_ASSERT(x) \
60 printk("IP_NF_ASSERT: %s:%s:%u\n", \
61 __FUNCTION__, __FILE__, __LINE__); \
64 #define IP_NF_ASSERT(x)
68 /* All the better to debug you with... */
74 We keep a set of rules for each CPU, so we can avoid write-locking
75 them in the softirq when updating the counters and therefore
76 only need to read-lock in the softirq; doing a write_lock_bh() in user
77 context stops packets coming through and allows user context to read
78 the counters or update the rules.
80 Hence the start of any table is given by get_table() below. */
82 /* Returns whether matches rule or not. */
84 ip_packet_match(const struct iphdr *ip,
87 const struct ipt_ip *ipinfo,
93 #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
95 if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
97 || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
99 dprintf("Source or dest mismatch.\n");
101 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
103 NIPQUAD(ipinfo->smsk.s_addr),
104 NIPQUAD(ipinfo->src.s_addr),
105 ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
106 dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
108 NIPQUAD(ipinfo->dmsk.s_addr),
109 NIPQUAD(ipinfo->dst.s_addr),
110 ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
114 /* Look for ifname matches; this should unroll nicely. */
115 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
116 ret |= (((const unsigned long *)indev)[i]
117 ^ ((const unsigned long *)ipinfo->iniface)[i])
118 & ((const unsigned long *)ipinfo->iniface_mask)[i];
121 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
122 dprintf("VIA in mismatch (%s vs %s).%s\n",
123 indev, ipinfo->iniface,
124 ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
128 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
129 ret |= (((const unsigned long *)outdev)[i]
130 ^ ((const unsigned long *)ipinfo->outiface)[i])
131 & ((const unsigned long *)ipinfo->outiface_mask)[i];
134 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
135 dprintf("VIA out mismatch (%s vs %s).%s\n",
136 outdev, ipinfo->outiface,
137 ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
141 /* Check specific protocol */
143 && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
144 dprintf("Packet protocol %hi does not match %hi.%s\n",
145 ip->protocol, ipinfo->proto,
146 ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
150 /* If we have a fragment rule but the packet is not a fragment
151 * then we return zero */
152 if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
153 dprintf("Fragment rule but not fragment.%s\n",
154 ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
162 ip_checkentry(const struct ipt_ip *ip)
164 if (ip->flags & ~IPT_F_MASK) {
165 duprintf("Unknown flag bits set: %08X\n",
166 ip->flags & ~IPT_F_MASK);
169 if (ip->invflags & ~IPT_INV_MASK) {
170 duprintf("Unknown invflag bits set: %08X\n",
171 ip->invflags & ~IPT_INV_MASK);
178 ipt_error(struct sk_buff **pskb,
179 const struct net_device *in,
180 const struct net_device *out,
181 unsigned int hooknum,
182 const struct xt_target *target,
183 const void *targinfo)
186 printk("ip_tables: error: `%s'\n", (char *)targinfo);
192 int do_match(struct ipt_entry_match *m,
193 const struct sk_buff *skb,
194 const struct net_device *in,
195 const struct net_device *out,
199 /* Stop iteration if it doesn't match */
200 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
201 offset, skb->nh.iph->ihl*4, hotdrop))
207 static inline struct ipt_entry *
208 get_entry(void *base, unsigned int offset)
210 return (struct ipt_entry *)(base + offset);
213 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
215 ipt_do_table(struct sk_buff **pskb,
217 const struct net_device *in,
218 const struct net_device *out,
219 struct ipt_table *table)
221 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
226 /* Initializing verdict to NF_DROP keeps gcc happy. */
227 unsigned int verdict = NF_DROP;
228 const char *indev, *outdev;
230 struct ipt_entry *e, *back;
231 struct xt_table_info *private;
234 ip = (*pskb)->nh.iph;
235 datalen = (*pskb)->len - ip->ihl * 4;
236 indev = in ? in->name : nulldevname;
237 outdev = out ? out->name : nulldevname;
238 /* We handle fragments by dealing with the first fragment as
239 * if it was a normal packet. All other fragments are treated
240 * normally, except that they will NEVER match rules that ask
241 * things we don't know, ie. tcp syn flag or ports). If the
242 * rule is also a fragment-specific rule, non-fragments won't
244 offset = ntohs(ip->frag_off) & IP_OFFSET;
246 read_lock_bh(&table->lock);
247 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
248 private = table->private;
249 table_base = (void *)private->entries[smp_processor_id()];
250 e = get_entry(table_base, private->hook_entry[hook]);
252 /* For return from builtin chain */
253 back = get_entry(table_base, private->underflow[hook]);
258 if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
259 struct ipt_entry_target *t;
261 if (IPT_MATCH_ITERATE(e, do_match,
263 offset, &hotdrop) != 0)
266 ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
268 t = ipt_get_target(e);
269 IP_NF_ASSERT(t->u.kernel.target);
270 /* Standard target? */
271 if (!t->u.kernel.target->target) {
274 v = ((struct ipt_standard_target *)t)->verdict;
276 /* Pop from stack? */
277 if (v != IPT_RETURN) {
278 verdict = (unsigned)(-v) - 1;
282 back = get_entry(table_base,
286 if (table_base + v != (void *)e + e->next_offset
287 && !(e->ip.flags & IPT_F_GOTO)) {
288 /* Save old back ptr in next entry */
289 struct ipt_entry *next
290 = (void *)e + e->next_offset;
292 = (void *)back - table_base;
293 /* set back pointer to next entry */
297 e = get_entry(table_base, v);
299 /* Targets which reenter must return
301 #ifdef CONFIG_NETFILTER_DEBUG
302 ((struct ipt_entry *)table_base)->comefrom
305 verdict = t->u.kernel.target->target(pskb,
311 #ifdef CONFIG_NETFILTER_DEBUG
312 if (((struct ipt_entry *)table_base)->comefrom
314 && verdict == IPT_CONTINUE) {
315 printk("Target %s reentered!\n",
316 t->u.kernel.target->name);
319 ((struct ipt_entry *)table_base)->comefrom
322 /* Target might have changed stuff. */
323 ip = (*pskb)->nh.iph;
324 datalen = (*pskb)->len - ip->ihl * 4;
326 if (verdict == IPT_CONTINUE)
327 e = (void *)e + e->next_offset;
335 e = (void *)e + e->next_offset;
339 read_unlock_bh(&table->lock);
341 #ifdef DEBUG_ALLOW_ALL
350 /* All zeroes == unconditional rule. */
352 unconditional(const struct ipt_ip *ip)
356 for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
357 if (((__u32 *)ip)[i])
363 /* Figures out from what hook each rule can be called: returns 0 if
364 there are loops. Puts hook bitmask in comefrom. */
366 mark_source_chains(struct xt_table_info *newinfo,
367 unsigned int valid_hooks, void *entry0)
371 /* No recursion; use packet counter to save back ptrs (reset
372 to 0 as we leave), and comefrom to save source hook bitmask */
373 for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
374 unsigned int pos = newinfo->hook_entry[hook];
376 = (struct ipt_entry *)(entry0 + pos);
378 if (!(valid_hooks & (1 << hook)))
381 /* Set initial back pointer. */
382 e->counters.pcnt = pos;
385 struct ipt_standard_target *t
386 = (void *)ipt_get_target(e);
388 if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
389 printk("iptables: loop hook %u pos %u %08X.\n",
390 hook, pos, e->comefrom);
394 |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
396 /* Unconditional return/END. */
397 if (e->target_offset == sizeof(struct ipt_entry)
398 && (strcmp(t->target.u.user.name,
399 IPT_STANDARD_TARGET) == 0)
401 && unconditional(&e->ip)) {
402 unsigned int oldpos, size;
404 /* Return: backtrack through the last
407 e->comefrom ^= (1<<NF_IP_NUMHOOKS);
408 #ifdef DEBUG_IP_FIREWALL_USER
410 & (1 << NF_IP_NUMHOOKS)) {
411 duprintf("Back unset "
418 pos = e->counters.pcnt;
419 e->counters.pcnt = 0;
421 /* We're at the start. */
425 e = (struct ipt_entry *)
427 } while (oldpos == pos + e->next_offset);
430 size = e->next_offset;
431 e = (struct ipt_entry *)
432 (entry0 + pos + size);
433 e->counters.pcnt = pos;
436 int newpos = t->verdict;
438 if (strcmp(t->target.u.user.name,
439 IPT_STANDARD_TARGET) == 0
441 /* This a jump; chase it. */
442 duprintf("Jump rule %u -> %u\n",
445 /* ... this is a fallthru */
446 newpos = pos + e->next_offset;
448 e = (struct ipt_entry *)
450 e->counters.pcnt = pos;
455 duprintf("Finished chain %u\n", hook);
461 cleanup_match(struct ipt_entry_match *m, unsigned int *i)
463 if (i && (*i)-- == 0)
466 if (m->u.kernel.match->destroy)
467 m->u.kernel.match->destroy(m->u.kernel.match, m->data);
468 module_put(m->u.kernel.match->me);
473 standard_check(const struct ipt_entry_target *t,
474 unsigned int max_offset)
476 struct ipt_standard_target *targ = (void *)t;
478 /* Check standard info. */
479 if (targ->verdict >= 0
480 && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
481 duprintf("ipt_standard_check: bad verdict (%i)\n",
485 if (targ->verdict < -NF_MAX_VERDICT - 1) {
486 duprintf("ipt_standard_check: bad negative verdict (%i)\n",
494 check_match(struct ipt_entry_match *m,
496 const struct ipt_ip *ip,
497 unsigned int hookmask,
500 struct ipt_match *match;
503 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
505 "ipt_%s", m->u.user.name);
506 if (IS_ERR(match) || !match) {
507 duprintf("check_match: `%s' not found\n", m->u.user.name);
508 return match ? PTR_ERR(match) : -ENOENT;
510 m->u.kernel.match = match;
512 ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
513 name, hookmask, ip->proto,
514 ip->invflags & IPT_INV_PROTO);
518 if (m->u.kernel.match->checkentry
519 && !m->u.kernel.match->checkentry(name, ip, match, m->data,
521 duprintf("ip_tables: check failed for `%s'.\n",
522 m->u.kernel.match->name);
530 module_put(m->u.kernel.match->me);
534 static struct ipt_target ipt_standard_target;
537 check_entry(struct ipt_entry *e, const char *name, unsigned int size,
540 struct ipt_entry_target *t;
541 struct ipt_target *target;
545 if (!ip_checkentry(&e->ip)) {
546 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
551 ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
553 goto cleanup_matches;
555 t = ipt_get_target(e);
556 target = try_then_request_module(xt_find_target(AF_INET,
559 "ipt_%s", t->u.user.name);
560 if (IS_ERR(target) || !target) {
561 duprintf("check_entry: `%s' not found\n", t->u.user.name);
562 ret = target ? PTR_ERR(target) : -ENOENT;
563 goto cleanup_matches;
565 t->u.kernel.target = target;
567 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
568 name, e->comefrom, e->ip.proto,
569 e->ip.invflags & IPT_INV_PROTO);
573 if (t->u.kernel.target == &ipt_standard_target) {
574 if (!standard_check(t, size)) {
578 } else if (t->u.kernel.target->checkentry
579 && !t->u.kernel.target->checkentry(name, e, target, t->data,
581 duprintf("ip_tables: check failed for `%s'.\n",
582 t->u.kernel.target->name);
590 module_put(t->u.kernel.target->me);
592 IPT_MATCH_ITERATE(e, cleanup_match, &j);
597 check_entry_size_and_hooks(struct ipt_entry *e,
598 struct xt_table_info *newinfo,
600 unsigned char *limit,
601 const unsigned int *hook_entries,
602 const unsigned int *underflows,
607 if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
608 || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
609 duprintf("Bad offset %p\n", e);
614 < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
615 duprintf("checking: element %p size %u\n",
620 /* Check hooks & underflows */
621 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
622 if ((unsigned char *)e - base == hook_entries[h])
623 newinfo->hook_entry[h] = hook_entries[h];
624 if ((unsigned char *)e - base == underflows[h])
625 newinfo->underflow[h] = underflows[h];
628 /* FIXME: underflows must be unconditional, standard verdicts
629 < 0 (not IPT_RETURN). --RR */
631 /* Clear counters and comefrom */
632 e->counters = ((struct xt_counters) { 0, 0 });
640 cleanup_entry(struct ipt_entry *e, unsigned int *i)
642 struct ipt_entry_target *t;
644 if (i && (*i)-- == 0)
647 /* Cleanup all matches */
648 IPT_MATCH_ITERATE(e, cleanup_match, NULL);
649 t = ipt_get_target(e);
650 if (t->u.kernel.target->destroy)
651 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
652 module_put(t->u.kernel.target->me);
656 /* Checks and translates the user-supplied table segment (held in
659 translate_table(const char *name,
660 unsigned int valid_hooks,
661 struct xt_table_info *newinfo,
665 const unsigned int *hook_entries,
666 const unsigned int *underflows)
671 newinfo->size = size;
672 newinfo->number = number;
674 /* Init all hooks to impossible value. */
675 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
676 newinfo->hook_entry[i] = 0xFFFFFFFF;
677 newinfo->underflow[i] = 0xFFFFFFFF;
680 duprintf("translate_table: size %u\n", newinfo->size);
682 /* Walk through entries, checking offsets. */
683 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
684 check_entry_size_and_hooks,
688 hook_entries, underflows, &i);
693 duprintf("translate_table: %u not %u entries\n",
698 /* Check hooks all assigned */
699 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
700 /* Only hooks which are valid */
701 if (!(valid_hooks & (1 << i)))
703 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
704 duprintf("Invalid hook entry %u %u\n",
708 if (newinfo->underflow[i] == 0xFFFFFFFF) {
709 duprintf("Invalid underflow %u %u\n",
715 if (!mark_source_chains(newinfo, valid_hooks, entry0))
718 /* Finally, each sanity check must pass */
720 ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
721 check_entry, name, size, &i);
724 IPT_ENTRY_ITERATE(entry0, newinfo->size,
729 /* And one copy for every other CPU */
730 for_each_possible_cpu(i) {
731 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
732 memcpy(newinfo->entries[i], entry0, newinfo->size);
740 add_entry_to_counter(const struct ipt_entry *e,
741 struct xt_counters total[],
744 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
751 set_entry_to_counter(const struct ipt_entry *e,
752 struct ipt_counters total[],
755 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
762 get_counters(const struct xt_table_info *t,
763 struct xt_counters counters[])
769 /* Instead of clearing (by a previous call to memset())
770 * the counters and using adds, we set the counters
771 * with data used by 'current' CPU
772 * We dont care about preemption here.
774 curcpu = raw_smp_processor_id();
777 IPT_ENTRY_ITERATE(t->entries[curcpu],
779 set_entry_to_counter,
783 for_each_possible_cpu(cpu) {
787 IPT_ENTRY_ITERATE(t->entries[cpu],
789 add_entry_to_counter,
795 static inline struct xt_counters * alloc_counters(struct ipt_table *table)
797 unsigned int countersize;
798 struct xt_counters *counters;
799 struct xt_table_info *private = table->private;
801 /* We need atomic snapshot of counters: rest doesn't change
802 (other than comefrom, which userspace doesn't care
804 countersize = sizeof(struct xt_counters) * private->number;
805 counters = vmalloc_node(countersize, numa_node_id());
807 if (counters == NULL)
808 return ERR_PTR(-ENOMEM);
810 /* First, sum counters... */
811 write_lock_bh(&table->lock);
812 get_counters(private, counters);
813 write_unlock_bh(&table->lock);
819 copy_entries_to_user(unsigned int total_size,
820 struct ipt_table *table,
821 void __user *userptr)
823 unsigned int off, num;
825 struct xt_counters *counters;
826 struct xt_table_info *private = table->private;
830 counters = alloc_counters(table);
831 if (IS_ERR(counters))
832 return PTR_ERR(counters);
834 /* choose the copy that is on our node/cpu, ...
835 * This choice is lazy (because current thread is
836 * allowed to migrate to another cpu)
838 loc_cpu_entry = private->entries[raw_smp_processor_id()];
839 /* ... then copy entire thing ... */
840 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
845 /* FIXME: use iterator macros --RR */
846 /* ... then go back and fix counters and names */
847 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
849 struct ipt_entry_match *m;
850 struct ipt_entry_target *t;
852 e = (struct ipt_entry *)(loc_cpu_entry + off);
853 if (copy_to_user(userptr + off
854 + offsetof(struct ipt_entry, counters),
856 sizeof(counters[num])) != 0) {
861 for (i = sizeof(struct ipt_entry);
862 i < e->target_offset;
863 i += m->u.match_size) {
866 if (copy_to_user(userptr + off + i
867 + offsetof(struct ipt_entry_match,
869 m->u.kernel.match->name,
870 strlen(m->u.kernel.match->name)+1)
877 t = ipt_get_target(e);
878 if (copy_to_user(userptr + off + e->target_offset
879 + offsetof(struct ipt_entry_target,
881 t->u.kernel.target->name,
882 strlen(t->u.kernel.target->name)+1) != 0) {
894 struct compat_delta {
895 struct compat_delta *next;
900 static struct compat_delta *compat_offsets = NULL;
902 static int compat_add_offset(u_int16_t offset, short delta)
904 struct compat_delta *tmp;
906 tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
909 tmp->offset = offset;
911 if (compat_offsets) {
912 tmp->next = compat_offsets->next;
913 compat_offsets->next = tmp;
915 compat_offsets = tmp;
921 static void compat_flush_offsets(void)
923 struct compat_delta *tmp, *next;
925 if (compat_offsets) {
926 for(tmp = compat_offsets; tmp; tmp = next) {
930 compat_offsets = NULL;
934 static short compat_calc_jump(u_int16_t offset)
936 struct compat_delta *tmp;
939 for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
940 if (tmp->offset < offset)
945 struct compat_ipt_standard_target
947 struct compat_xt_entry_target target;
948 compat_int_t verdict;
951 struct compat_ipt_standard
953 struct compat_ipt_entry entry;
954 struct compat_ipt_standard_target target;
957 #define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target))
958 #define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target))
959 #define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN)
961 static int compat_ipt_standard_fn(void *target,
962 void **dstptr, int *size, int convert)
964 struct compat_ipt_standard_target compat_st, *pcompat_st;
965 struct ipt_standard_target st, *pst;
972 memcpy(&compat_st.target, &pst->target,
973 sizeof(compat_st.target));
974 compat_st.verdict = pst->verdict;
975 if (compat_st.verdict > 0)
977 compat_calc_jump(compat_st.verdict);
978 compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN;
979 if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN))
981 *size -= IPT_ST_OFFSET;
982 *dstptr += IPT_ST_COMPAT_LEN;
984 case COMPAT_FROM_USER:
986 memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN);
987 st.verdict = pcompat_st->verdict;
989 st.verdict += compat_calc_jump(st.verdict);
990 st.target.u.user.target_size = IPT_ST_LEN;
991 memcpy(*dstptr, &st, IPT_ST_LEN);
992 *size += IPT_ST_OFFSET;
993 *dstptr += IPT_ST_LEN;
995 case COMPAT_CALC_SIZE:
996 *size += IPT_ST_OFFSET;
1006 compat_calc_match(struct ipt_entry_match *m, int * size)
1008 if (m->u.kernel.match->compat)
1009 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1011 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1015 static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
1016 void *base, struct xt_table_info *newinfo)
1018 struct ipt_entry_target *t;
1019 u_int16_t entry_offset;
1023 entry_offset = (void *)e - base;
1024 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1025 t = ipt_get_target(e);
1026 if (t->u.kernel.target->compat)
1027 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1029 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1030 newinfo->size -= off;
1031 ret = compat_add_offset(entry_offset, off);
1035 for (i = 0; i< NF_IP_NUMHOOKS; i++) {
1036 if (info->hook_entry[i] && (e < (struct ipt_entry *)
1037 (base + info->hook_entry[i])))
1038 newinfo->hook_entry[i] -= off;
1039 if (info->underflow[i] && (e < (struct ipt_entry *)
1040 (base + info->underflow[i])))
1041 newinfo->underflow[i] -= off;
1046 static int compat_table_info(struct xt_table_info *info,
1047 struct xt_table_info *newinfo)
1049 void *loc_cpu_entry;
1052 if (!newinfo || !info)
1055 memset(newinfo, 0, sizeof(struct xt_table_info));
1056 newinfo->size = info->size;
1057 newinfo->number = info->number;
1058 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1059 newinfo->hook_entry[i] = info->hook_entry[i];
1060 newinfo->underflow[i] = info->underflow[i];
1062 loc_cpu_entry = info->entries[raw_smp_processor_id()];
1063 return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
1064 compat_calc_entry, info, loc_cpu_entry, newinfo);
1068 static int get_info(void __user *user, int *len, int compat)
1070 char name[IPT_TABLE_MAXNAMELEN];
1071 struct ipt_table *t;
1074 if (*len != sizeof(struct ipt_getinfo)) {
1075 duprintf("length %u != %u\n", *len,
1076 (unsigned int)sizeof(struct ipt_getinfo));
1080 if (copy_from_user(name, user, sizeof(name)) != 0)
1083 name[IPT_TABLE_MAXNAMELEN-1] = '\0';
1084 #ifdef CONFIG_COMPAT
1086 xt_compat_lock(AF_INET);
1088 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1089 "iptable_%s", name);
1090 if (t && !IS_ERR(t)) {
1091 struct ipt_getinfo info;
1092 struct xt_table_info *private = t->private;
1094 #ifdef CONFIG_COMPAT
1096 struct xt_table_info tmp;
1097 ret = compat_table_info(private, &tmp);
1098 compat_flush_offsets();
1102 info.valid_hooks = t->valid_hooks;
1103 memcpy(info.hook_entry, private->hook_entry,
1104 sizeof(info.hook_entry));
1105 memcpy(info.underflow, private->underflow,
1106 sizeof(info.underflow));
1107 info.num_entries = private->number;
1108 info.size = private->size;
1109 strcpy(info.name, name);
1111 if (copy_to_user(user, &info, *len) != 0)
1119 ret = t ? PTR_ERR(t) : -ENOENT;
1120 #ifdef CONFIG_COMPAT
1122 xt_compat_unlock(AF_INET);
1128 get_entries(struct ipt_get_entries __user *uptr, int *len)
1131 struct ipt_get_entries get;
1132 struct ipt_table *t;
1134 if (*len < sizeof(get)) {
1135 duprintf("get_entries: %u < %d\n", *len,
1136 (unsigned int)sizeof(get));
1139 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1141 if (*len != sizeof(struct ipt_get_entries) + get.size) {
1142 duprintf("get_entries: %u != %u\n", *len,
1143 (unsigned int)(sizeof(struct ipt_get_entries) +
1148 t = xt_find_table_lock(AF_INET, get.name);
1149 if (t && !IS_ERR(t)) {
1150 struct xt_table_info *private = t->private;
1151 duprintf("t->private->number = %u\n",
1153 if (get.size == private->size)
1154 ret = copy_entries_to_user(private->size,
1155 t, uptr->entrytable);
1157 duprintf("get_entries: I've got %u not %u!\n",
1165 ret = t ? PTR_ERR(t) : -ENOENT;
1171 __do_replace(const char *name, unsigned int valid_hooks,
1172 struct xt_table_info *newinfo, unsigned int num_counters,
1173 void __user *counters_ptr)
1176 struct ipt_table *t;
1177 struct xt_table_info *oldinfo;
1178 struct xt_counters *counters;
1179 void *loc_cpu_old_entry;
1182 counters = vmalloc(num_counters * sizeof(struct xt_counters));
1188 t = try_then_request_module(xt_find_table_lock(AF_INET, name),
1189 "iptable_%s", name);
1190 if (!t || IS_ERR(t)) {
1191 ret = t ? PTR_ERR(t) : -ENOENT;
1192 goto free_newinfo_counters_untrans;
1196 if (valid_hooks != t->valid_hooks) {
1197 duprintf("Valid hook crap: %08X vs %08X\n",
1198 valid_hooks, t->valid_hooks);
1203 oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1207 /* Update module usage count based on number of rules */
1208 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1209 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1210 if ((oldinfo->number > oldinfo->initial_entries) ||
1211 (newinfo->number <= oldinfo->initial_entries))
1213 if ((oldinfo->number > oldinfo->initial_entries) &&
1214 (newinfo->number <= oldinfo->initial_entries))
1217 /* Get the old counters. */
1218 get_counters(oldinfo, counters);
1219 /* Decrease module usage counts and free resource */
1220 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1221 IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1222 xt_free_table_info(oldinfo);
1223 if (copy_to_user(counters_ptr, counters,
1224 sizeof(struct xt_counters) * num_counters) != 0)
1233 free_newinfo_counters_untrans:
1240 do_replace(void __user *user, unsigned int len)
1243 struct ipt_replace tmp;
1244 struct xt_table_info *newinfo;
1245 void *loc_cpu_entry;
1247 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1250 /* Hack: Causes ipchains to give correct error msg --RR */
1251 if (len != sizeof(tmp) + tmp.size)
1252 return -ENOPROTOOPT;
1254 /* overflow check */
1255 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1258 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1261 newinfo = xt_alloc_table_info(tmp.size);
1265 /* choose the copy that is our node/cpu */
1266 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1267 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1273 ret = translate_table(tmp.name, tmp.valid_hooks,
1274 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1275 tmp.hook_entry, tmp.underflow);
1279 duprintf("ip_tables: Translated table\n");
1281 ret = __do_replace(tmp.name, tmp.valid_hooks,
1282 newinfo, tmp.num_counters,
1285 goto free_newinfo_untrans;
1288 free_newinfo_untrans:
1289 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1291 xt_free_table_info(newinfo);
1295 /* We're lazy, and add to the first CPU; overflow works its fey magic
1296 * and everything is OK. */
1298 add_counter_to_entry(struct ipt_entry *e,
1299 const struct xt_counters addme[],
1303 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1305 (long unsigned int)e->counters.pcnt,
1306 (long unsigned int)e->counters.bcnt,
1307 (long unsigned int)addme[*i].pcnt,
1308 (long unsigned int)addme[*i].bcnt);
1311 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1318 do_add_counters(void __user *user, unsigned int len, int compat)
1321 struct xt_counters_info tmp;
1322 struct xt_counters *paddc;
1323 unsigned int num_counters;
1327 struct ipt_table *t;
1328 struct xt_table_info *private;
1330 void *loc_cpu_entry;
1331 #ifdef CONFIG_COMPAT
1332 struct compat_xt_counters_info compat_tmp;
1336 size = sizeof(struct compat_xt_counters_info);
1341 size = sizeof(struct xt_counters_info);
1344 if (copy_from_user(ptmp, user, size) != 0)
1347 #ifdef CONFIG_COMPAT
1349 num_counters = compat_tmp.num_counters;
1350 name = compat_tmp.name;
1354 num_counters = tmp.num_counters;
1358 if (len != size + num_counters * sizeof(struct xt_counters))
1361 paddc = vmalloc_node(len - size, numa_node_id());
1365 if (copy_from_user(paddc, user + size, len - size) != 0) {
1370 t = xt_find_table_lock(AF_INET, name);
1371 if (!t || IS_ERR(t)) {
1372 ret = t ? PTR_ERR(t) : -ENOENT;
1376 write_lock_bh(&t->lock);
1377 private = t->private;
1378 if (private->number != num_counters) {
1380 goto unlock_up_free;
1384 /* Choose the copy that is on our node */
1385 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1386 IPT_ENTRY_ITERATE(loc_cpu_entry,
1388 add_counter_to_entry,
1392 write_unlock_bh(&t->lock);
1401 #ifdef CONFIG_COMPAT
1402 struct compat_ipt_replace {
1403 char name[IPT_TABLE_MAXNAMELEN];
1407 u32 hook_entry[NF_IP_NUMHOOKS];
1408 u32 underflow[NF_IP_NUMHOOKS];
1410 compat_uptr_t counters; /* struct ipt_counters * */
1411 struct compat_ipt_entry entries[0];
1414 static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1415 void __user **dstptr, compat_uint_t *size)
1417 if (m->u.kernel.match->compat)
1418 return m->u.kernel.match->compat(m, dstptr, size,
1421 return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
1424 static int compat_copy_entry_to_user(struct ipt_entry *e,
1425 void __user **dstptr, compat_uint_t *size)
1427 struct ipt_entry_target __user *t;
1428 struct compat_ipt_entry __user *ce;
1429 u_int16_t target_offset, next_offset;
1430 compat_uint_t origsize;
1435 ce = (struct compat_ipt_entry __user *)*dstptr;
1436 if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
1439 *dstptr += sizeof(struct compat_ipt_entry);
1440 ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
1441 target_offset = e->target_offset - (origsize - *size);
1444 t = ipt_get_target(e);
1445 if (t->u.kernel.target->compat)
1446 ret = t->u.kernel.target->compat(t, dstptr, size,
1449 ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
1453 next_offset = e->next_offset - (origsize - *size);
1454 if (put_user(target_offset, &ce->target_offset))
1456 if (put_user(next_offset, &ce->next_offset))
1464 compat_check_calc_match(struct ipt_entry_match *m,
1466 const struct ipt_ip *ip,
1467 unsigned int hookmask,
1470 struct ipt_match *match;
1472 match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
1473 m->u.user.revision),
1474 "ipt_%s", m->u.user.name);
1475 if (IS_ERR(match) || !match) {
1476 duprintf("compat_check_calc_match: `%s' not found\n",
1478 return match ? PTR_ERR(match) : -ENOENT;
1480 m->u.kernel.match = match;
1482 if (m->u.kernel.match->compat)
1483 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1485 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1492 check_compat_entry_size_and_hooks(struct ipt_entry *e,
1493 struct xt_table_info *newinfo,
1495 unsigned char *base,
1496 unsigned char *limit,
1497 unsigned int *hook_entries,
1498 unsigned int *underflows,
1502 struct ipt_entry_target *t;
1503 struct ipt_target *target;
1504 u_int16_t entry_offset;
1507 duprintf("check_compat_entry_size_and_hooks %p\n", e);
1508 if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
1509 || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
1510 duprintf("Bad offset %p, limit = %p\n", e, limit);
1514 if (e->next_offset < sizeof(struct compat_ipt_entry) +
1515 sizeof(struct compat_xt_entry_target)) {
1516 duprintf("checking: element %p size %u\n",
1521 if (!ip_checkentry(&e->ip)) {
1522 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
1527 entry_offset = (void *)e - (void *)base;
1529 ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
1530 e->comefrom, &off, &j);
1534 t = ipt_get_target(e);
1535 target = try_then_request_module(xt_find_target(AF_INET,
1537 t->u.user.revision),
1538 "ipt_%s", t->u.user.name);
1539 if (IS_ERR(target) || !target) {
1540 duprintf("check_entry: `%s' not found\n", t->u.user.name);
1541 ret = target ? PTR_ERR(target) : -ENOENT;
1544 t->u.kernel.target = target;
1546 if (t->u.kernel.target->compat)
1547 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1549 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1551 ret = compat_add_offset(entry_offset, off);
1555 /* Check hooks & underflows */
1556 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1557 if ((unsigned char *)e - base == hook_entries[h])
1558 newinfo->hook_entry[h] = hook_entries[h];
1559 if ((unsigned char *)e - base == underflows[h])
1560 newinfo->underflow[h] = underflows[h];
1563 /* Clear counters and comefrom */
1564 e->counters = ((struct ipt_counters) { 0, 0 });
1570 IPT_MATCH_ITERATE(e, cleanup_match, &j);
1574 static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1575 void **dstptr, compat_uint_t *size, const char *name,
1576 const struct ipt_ip *ip, unsigned int hookmask)
1578 struct ipt_entry_match *dm;
1579 struct ipt_match *match;
1582 dm = (struct ipt_entry_match *)*dstptr;
1583 match = m->u.kernel.match;
1585 match->compat(m, dstptr, size, COMPAT_FROM_USER);
1587 xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
1589 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1590 name, hookmask, ip->proto,
1591 ip->invflags & IPT_INV_PROTO);
1595 if (m->u.kernel.match->checkentry
1596 && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
1598 duprintf("ip_tables: check failed for `%s'.\n",
1599 m->u.kernel.match->name);
1605 static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1606 unsigned int *size, const char *name,
1607 struct xt_table_info *newinfo, unsigned char *base)
1609 struct ipt_entry_target *t;
1610 struct ipt_target *target;
1611 struct ipt_entry *de;
1612 unsigned int origsize;
1617 de = (struct ipt_entry *)*dstptr;
1618 memcpy(de, e, sizeof(struct ipt_entry));
1620 *dstptr += sizeof(struct compat_ipt_entry);
1621 ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
1622 name, &de->ip, de->comefrom);
1625 de->target_offset = e->target_offset - (origsize - *size);
1626 t = ipt_get_target(e);
1627 target = t->u.kernel.target;
1629 target->compat(t, dstptr, size, COMPAT_FROM_USER);
1631 xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
1633 de->next_offset = e->next_offset - (origsize - *size);
1634 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
1635 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1636 newinfo->hook_entry[h] -= origsize - *size;
1637 if ((unsigned char *)de - base < newinfo->underflow[h])
1638 newinfo->underflow[h] -= origsize - *size;
1641 t = ipt_get_target(de);
1642 target = t->u.kernel.target;
1643 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
1644 name, e->comefrom, e->ip.proto,
1645 e->ip.invflags & IPT_INV_PROTO);
1650 if (t->u.kernel.target == &ipt_standard_target) {
1651 if (!standard_check(t, *size))
1653 } else if (t->u.kernel.target->checkentry
1654 && !t->u.kernel.target->checkentry(name, de, target,
1655 t->data, de->comefrom)) {
1656 duprintf("ip_tables: compat: check failed for `%s'.\n",
1657 t->u.kernel.target->name);
1666 translate_compat_table(const char *name,
1667 unsigned int valid_hooks,
1668 struct xt_table_info **pinfo,
1670 unsigned int total_size,
1671 unsigned int number,
1672 unsigned int *hook_entries,
1673 unsigned int *underflows)
1676 struct xt_table_info *newinfo, *info;
1677 void *pos, *entry0, *entry1;
1684 info->number = number;
1686 /* Init all hooks to impossible value. */
1687 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1688 info->hook_entry[i] = 0xFFFFFFFF;
1689 info->underflow[i] = 0xFFFFFFFF;
1692 duprintf("translate_compat_table: size %u\n", info->size);
1694 xt_compat_lock(AF_INET);
1695 /* Walk through entries, checking offsets. */
1696 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1697 check_compat_entry_size_and_hooks,
1698 info, &size, entry0,
1699 entry0 + total_size,
1700 hook_entries, underflows, &i, name);
1706 duprintf("translate_compat_table: %u not %u entries\n",
1711 /* Check hooks all assigned */
1712 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1713 /* Only hooks which are valid */
1714 if (!(valid_hooks & (1 << i)))
1716 if (info->hook_entry[i] == 0xFFFFFFFF) {
1717 duprintf("Invalid hook entry %u %u\n",
1718 i, hook_entries[i]);
1721 if (info->underflow[i] == 0xFFFFFFFF) {
1722 duprintf("Invalid underflow %u %u\n",
1729 newinfo = xt_alloc_table_info(size);
1733 newinfo->number = number;
1734 for (i = 0; i < NF_IP_NUMHOOKS; i++) {
1735 newinfo->hook_entry[i] = info->hook_entry[i];
1736 newinfo->underflow[i] = info->underflow[i];
1738 entry1 = newinfo->entries[raw_smp_processor_id()];
1741 ret = IPT_ENTRY_ITERATE(entry0, total_size,
1742 compat_copy_entry_from_user, &pos, &size,
1743 name, newinfo, entry1);
1744 compat_flush_offsets();
1745 xt_compat_unlock(AF_INET);
1750 if (!mark_source_chains(newinfo, valid_hooks, entry1))
1753 /* And one copy for every other CPU */
1754 for_each_possible_cpu(i)
1755 if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1756 memcpy(newinfo->entries[i], entry1, newinfo->size);
1760 xt_free_table_info(info);
1764 xt_free_table_info(newinfo);
1768 xt_compat_unlock(AF_INET);
1773 compat_do_replace(void __user *user, unsigned int len)
1776 struct compat_ipt_replace tmp;
1777 struct xt_table_info *newinfo;
1778 void *loc_cpu_entry;
1780 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1783 /* Hack: Causes ipchains to give correct error msg --RR */
1784 if (len != sizeof(tmp) + tmp.size)
1785 return -ENOPROTOOPT;
1787 /* overflow check */
1788 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
1791 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1794 newinfo = xt_alloc_table_info(tmp.size);
1798 /* choose the copy that is our node/cpu */
1799 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1800 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1806 ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1807 &newinfo, &loc_cpu_entry, tmp.size,
1808 tmp.num_entries, tmp.hook_entry, tmp.underflow);
1812 duprintf("compat_do_replace: Translated table\n");
1814 ret = __do_replace(tmp.name, tmp.valid_hooks,
1815 newinfo, tmp.num_counters,
1816 compat_ptr(tmp.counters));
1818 goto free_newinfo_untrans;
1821 free_newinfo_untrans:
1822 IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1824 xt_free_table_info(newinfo);
1829 compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1834 if (!capable(CAP_NET_ADMIN))
1838 case IPT_SO_SET_REPLACE:
1839 ret = compat_do_replace(user, len);
1842 case IPT_SO_SET_ADD_COUNTERS:
1843 ret = do_add_counters(user, len, 1);
1847 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
1854 struct compat_ipt_get_entries
1856 char name[IPT_TABLE_MAXNAMELEN];
1858 struct compat_ipt_entry entrytable[0];
1861 static int compat_copy_entries_to_user(unsigned int total_size,
1862 struct ipt_table *table, void __user *userptr)
1864 unsigned int off, num;
1865 struct compat_ipt_entry e;
1866 struct xt_counters *counters;
1867 struct xt_table_info *private = table->private;
1871 void *loc_cpu_entry;
1873 counters = alloc_counters(table);
1874 if (IS_ERR(counters))
1875 return PTR_ERR(counters);
1877 /* choose the copy that is on our node/cpu, ...
1878 * This choice is lazy (because current thread is
1879 * allowed to migrate to another cpu)
1881 loc_cpu_entry = private->entries[raw_smp_processor_id()];
1884 ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
1885 compat_copy_entry_to_user, &pos, &size);
1889 /* ... then go back and fix counters and names */
1890 for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
1892 struct ipt_entry_match m;
1893 struct ipt_entry_target t;
1896 if (copy_from_user(&e, userptr + off,
1897 sizeof(struct compat_ipt_entry)))
1899 if (copy_to_user(userptr + off +
1900 offsetof(struct compat_ipt_entry, counters),
1901 &counters[num], sizeof(counters[num])))
1904 for (i = sizeof(struct compat_ipt_entry);
1905 i < e.target_offset; i += m.u.match_size) {
1906 if (copy_from_user(&m, userptr + off + i,
1907 sizeof(struct ipt_entry_match)))
1909 if (copy_to_user(userptr + off + i +
1910 offsetof(struct ipt_entry_match, u.user.name),
1911 m.u.kernel.match->name,
1912 strlen(m.u.kernel.match->name) + 1))
1916 if (copy_from_user(&t, userptr + off + e.target_offset,
1917 sizeof(struct ipt_entry_target)))
1919 if (copy_to_user(userptr + off + e.target_offset +
1920 offsetof(struct ipt_entry_target, u.user.name),
1921 t.u.kernel.target->name,
1922 strlen(t.u.kernel.target->name) + 1))
1932 compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
1935 struct compat_ipt_get_entries get;
1936 struct ipt_table *t;
1939 if (*len < sizeof(get)) {
1940 duprintf("compat_get_entries: %u < %u\n",
1941 *len, (unsigned int)sizeof(get));
1945 if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1948 if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
1949 duprintf("compat_get_entries: %u != %u\n", *len,
1950 (unsigned int)(sizeof(struct compat_ipt_get_entries) +
1955 xt_compat_lock(AF_INET);
1956 t = xt_find_table_lock(AF_INET, get.name);
1957 if (t && !IS_ERR(t)) {
1958 struct xt_table_info *private = t->private;
1959 struct xt_table_info info;
1960 duprintf("t->private->number = %u\n",
1962 ret = compat_table_info(private, &info);
1963 if (!ret && get.size == info.size) {
1964 ret = compat_copy_entries_to_user(private->size,
1965 t, uptr->entrytable);
1967 duprintf("compat_get_entries: I've got %u not %u!\n",
1972 compat_flush_offsets();
1976 ret = t ? PTR_ERR(t) : -ENOENT;
1978 xt_compat_unlock(AF_INET);
1983 compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1988 case IPT_SO_GET_INFO:
1989 ret = get_info(user, len, 1);
1991 case IPT_SO_GET_ENTRIES:
1992 ret = compat_get_entries(user, len);
1995 duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
2003 do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2007 if (!capable(CAP_NET_ADMIN))
2011 case IPT_SO_SET_REPLACE:
2012 ret = do_replace(user, len);
2015 case IPT_SO_SET_ADD_COUNTERS:
2016 ret = do_add_counters(user, len, 0);
2020 duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
2028 do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2032 if (!capable(CAP_NET_ADMIN))
2036 case IPT_SO_GET_INFO:
2037 ret = get_info(user, len, 0);
2040 case IPT_SO_GET_ENTRIES:
2041 ret = get_entries(user, len);
2044 case IPT_SO_GET_REVISION_MATCH:
2045 case IPT_SO_GET_REVISION_TARGET: {
2046 struct ipt_get_revision rev;
2049 if (*len != sizeof(rev)) {
2053 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2058 if (cmd == IPT_SO_GET_REVISION_TARGET)
2063 try_then_request_module(xt_find_revision(AF_INET, rev.name,
2066 "ipt_%s", rev.name);
2071 duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
2078 int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
2081 struct xt_table_info *newinfo;
2082 static struct xt_table_info bootstrap
2083 = { 0, 0, 0, { 0 }, { 0 }, { } };
2084 void *loc_cpu_entry;
2086 newinfo = xt_alloc_table_info(repl->size);
2090 /* choose the copy on our node/cpu
2091 * but dont care of preemption
2093 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2094 memcpy(loc_cpu_entry, repl->entries, repl->size);
2096 ret = translate_table(table->name, table->valid_hooks,
2097 newinfo, loc_cpu_entry, repl->size,
2102 xt_free_table_info(newinfo);
2106 ret = xt_register_table(table, &bootstrap, newinfo);
2108 xt_free_table_info(newinfo);
2115 void ipt_unregister_table(struct ipt_table *table)
2117 struct xt_table_info *private;
2118 void *loc_cpu_entry;
2120 private = xt_unregister_table(table);
2122 /* Decrease module usage counts and free resources */
2123 loc_cpu_entry = private->entries[raw_smp_processor_id()];
2124 IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2125 xt_free_table_info(private);
2128 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
2130 icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2131 u_int8_t type, u_int8_t code,
2134 return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
2139 icmp_match(const struct sk_buff *skb,
2140 const struct net_device *in,
2141 const struct net_device *out,
2142 const struct xt_match *match,
2143 const void *matchinfo,
2145 unsigned int protoff,
2148 struct icmphdr _icmph, *ic;
2149 const struct ipt_icmp *icmpinfo = matchinfo;
2151 /* Must not be a fragment. */
2155 ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
2157 /* We've been asked to examine this packet, and we
2158 * can't. Hence, no choice but to drop.
2160 duprintf("Dropping evil ICMP tinygram.\n");
2165 return icmp_type_code_match(icmpinfo->type,
2169 !!(icmpinfo->invflags&IPT_ICMP_INV));
2172 /* Called when user tries to insert an entry of this type. */
2174 icmp_checkentry(const char *tablename,
2176 const struct xt_match *match,
2178 unsigned int hook_mask)
2180 const struct ipt_icmp *icmpinfo = matchinfo;
2182 /* Must specify no unknown invflags */
2183 return !(icmpinfo->invflags & ~IPT_ICMP_INV);
2186 /* The built-in targets: standard (NULL) and error. */
2187 static struct ipt_target ipt_standard_target = {
2188 .name = IPT_STANDARD_TARGET,
2189 .targetsize = sizeof(int),
2191 #ifdef CONFIG_COMPAT
2192 .compat = &compat_ipt_standard_fn,
2196 static struct ipt_target ipt_error_target = {
2197 .name = IPT_ERROR_TARGET,
2198 .target = ipt_error,
2199 .targetsize = IPT_FUNCTION_MAXNAMELEN,
2203 static struct nf_sockopt_ops ipt_sockopts = {
2205 .set_optmin = IPT_BASE_CTL,
2206 .set_optmax = IPT_SO_SET_MAX+1,
2207 .set = do_ipt_set_ctl,
2208 #ifdef CONFIG_COMPAT
2209 .compat_set = compat_do_ipt_set_ctl,
2211 .get_optmin = IPT_BASE_CTL,
2212 .get_optmax = IPT_SO_GET_MAX+1,
2213 .get = do_ipt_get_ctl,
2214 #ifdef CONFIG_COMPAT
2215 .compat_get = compat_do_ipt_get_ctl,
2219 static struct ipt_match icmp_matchstruct = {
2221 .match = icmp_match,
2222 .matchsize = sizeof(struct ipt_icmp),
2223 .proto = IPPROTO_ICMP,
2225 .checkentry = icmp_checkentry,
2228 static int __init ip_tables_init(void)
2232 ret = xt_proto_init(AF_INET);
2236 /* Noone else will be downing sem now, so we won't sleep */
2237 ret = xt_register_target(&ipt_standard_target);
2240 ret = xt_register_target(&ipt_error_target);
2243 ret = xt_register_match(&icmp_matchstruct);
2247 /* Register setsockopt */
2248 ret = nf_register_sockopt(&ipt_sockopts);
2252 printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
2256 xt_unregister_match(&icmp_matchstruct);
2258 xt_unregister_target(&ipt_error_target);
2260 xt_unregister_target(&ipt_standard_target);
2262 xt_proto_fini(AF_INET);
2267 static void __exit ip_tables_fini(void)
2269 nf_unregister_sockopt(&ipt_sockopts);
2271 xt_unregister_match(&icmp_matchstruct);
2272 xt_unregister_target(&ipt_error_target);
2273 xt_unregister_target(&ipt_standard_target);
2275 xt_proto_fini(AF_INET);
2278 EXPORT_SYMBOL(ipt_register_table);
2279 EXPORT_SYMBOL(ipt_unregister_table);
2280 EXPORT_SYMBOL(ipt_do_table);
2281 module_init(ip_tables_init);
2282 module_exit(ip_tables_fini);