GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / net / netfilter / xt_geoip.c
blob9eb6f87115ac1a18969af04c918e6b1100b73197
1 /* iptables kernel module for the geoip match
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * Copyright (c) 2004, 2005, 2006, 2007, 2008
9 * Samuel Jean & Nicolas Bouliane
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/version.h>
14 #include <linux/skbuff.h>
15 #include <linux/ip.h>
16 #include <linux/netdevice.h>
17 #include <asm/uaccess.h>
18 #include <asm/atomic.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter/xt_geoip.h>
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Nicolas Bouliane");
25 MODULE_AUTHOR("Samuel Jean");
26 MODULE_DESCRIPTION("xtables module for geoip match");
27 MODULE_ALIAS("ipt_geoip");
29 struct geoip_info *head = NULL;
30 static DEFINE_SPINLOCK(geoip_lock);
32 static struct geoip_info *add_node(struct geoip_info *memcpy)
34 struct geoip_info *p =
35 (struct geoip_info *)kmalloc(sizeof(struct geoip_info), GFP_KERNEL);
37 struct geoip_subnet *s;
39 if ((p == NULL) || (copy_from_user(p, memcpy, sizeof(struct geoip_info)) != 0))
40 return NULL;
42 s = (struct geoip_subnet *)kmalloc(p->count * sizeof(struct geoip_subnet), GFP_KERNEL);
43 if ((s == NULL) || (copy_from_user(s, p->subnets, p->count * sizeof(struct geoip_subnet)) != 0))
44 return NULL;
46 spin_lock_bh(&geoip_lock);
48 p->subnets = s;
49 p->ref = 1;
50 p->next = head;
51 p->prev = NULL;
52 if (p->next) p->next->prev = p;
53 head = p;
55 spin_unlock_bh(&geoip_lock);
56 return p;
59 static void remove_node(struct geoip_info *p)
61 spin_lock_bh(&geoip_lock);
63 if (p->next) { /* Am I following a node ? */
64 p->next->prev = p->prev;
65 if (p->prev) p->prev->next = p->next; /* Is there a node behind me ? */
66 else head = p->next; /* No? Then I was the head */
69 else
70 if (p->prev) /* Is there a node behind me ? */
71 p->prev->next = NULL;
72 else
73 head = NULL; /* No, we're alone */
75 /* So now am unlinked or the only one alive, right ?
76 * What are you waiting ? Free up some memory!
79 kfree(p->subnets);
80 kfree(p);
82 spin_unlock_bh(&geoip_lock);
83 return;
86 static struct geoip_info *find_node(u_int16_t cc)
88 struct geoip_info *p = head;
89 spin_lock_bh(&geoip_lock);
91 while (p) {
92 if (p->cc == cc) {
93 spin_unlock_bh(&geoip_lock);
94 return p;
96 p = p->next;
98 spin_unlock_bh(&geoip_lock);
99 return NULL;
102 static bool xt_geoip_mt(const struct sk_buff *skb, struct xt_action_param *par)
104 const struct xt_geoip_match_info *info = par->matchinfo;
105 const struct geoip_info *node; /* This keeps the code sexy */
106 const struct iphdr *iph = ip_hdr(skb);
107 u_int32_t ip, i, j;
109 if (info->flags & XT_GEOIP_SRC)
110 ip = ntohl(iph->saddr);
111 else
112 ip = ntohl(iph->daddr);
114 spin_lock_bh(&geoip_lock);
115 for (i = 0; i < info->count; i++) {
116 if ((node = info->mem[i]) == NULL) {
117 printk(KERN_ERR "xt_geoip: what the hell ?? '%c%c' isn't loaded into memory... skip it!\n",
118 COUNTRY(info->cc[i]));
120 continue;
123 for (j = 0; j < node->count; j++)
124 if ((ip > node->subnets[j].begin) && (ip < node->subnets[j].end)) {
125 spin_unlock_bh(&geoip_lock);
126 return (info->flags & XT_GEOIP_INV) ? 0 : 1;
130 spin_unlock_bh(&geoip_lock);
131 return (info->flags & XT_GEOIP_INV) ? 1 : 0;
134 static int xt_geoip_mt_checkentry(const struct xt_mtchk_param *par)
137 struct xt_geoip_match_info *info = par->matchinfo;
138 struct geoip_info *node;
139 u_int8_t i;
141 /* FIXME: Call a function to free userspace allocated memory.
142 * As Martin J. said; this match might eat lot of memory
143 * if commited with iptables-restore --noflush
144 void (*gfree)(struct geoip_info *oldmem);
145 gfree = info->fini;
148 /* If info->refcount isn't NULL, then
149 * it means that checkentry() already
150 * initialized this entry. Increase a
151 * refcount to prevent destroy() of
152 * this entry. */
153 if (info->refcount != NULL) {
154 atomic_inc((atomic_t *)info->refcount);
155 return 0;
159 for (i = 0; i < info->count; i++) {
161 if ((node = find_node(info->cc[i])) != NULL)
162 atomic_inc((atomic_t *)&node->ref); //increase the reference
163 else
164 if ((node = add_node(info->mem[i])) == NULL) {
165 printk(KERN_ERR
166 "xt_geoip: unable to load '%c%c' into memory\n",
167 COUNTRY(info->cc[i]));
168 return -ENOMEM;
171 /* Free userspace allocated memory for that country.
172 * FIXME: It's a bit odd to call this function everytime
173 * we process a country. Would be nice to call
174 * it once after all countries've been processed.
175 * - SJ
176 * *not implemented for now*
177 gfree(info->mem[i]);
180 /* Overwrite the now-useless pointer info->mem[i] with
181 * a pointer to the node's kernelspace structure.
182 * This avoids searching for a node in the match() and
183 * destroy() functions.
185 info->mem[i] = node;
188 /* We allocate some memory and give info->refcount a pointer
189 * to this memory. This prevents checkentry() from increasing a refcount
190 * different from the one used by destroy().
191 * For explanation, see http://www.mail-archive.com/netfilter-devel@lists.samba.org/msg00625.html
193 info->refcount = kmalloc(sizeof(u_int8_t), GFP_KERNEL);
194 if (info->refcount == NULL) {
195 printk(KERN_ERR "xt_geoip: failed to allocate `refcount' memory\n");
196 return -ENOMEM;
198 *(info->refcount) = 1;
200 return 0;
203 static void xt_geoip_mt_destroy(const struct xt_mtdtor_param *par)
205 struct xt_geoip_match_info *info = par->matchinfo;
206 struct geoip_info *node; /* this keeps the code sexy */
207 u_int8_t i;
209 /* Decrease the previously increased refcount in checkentry()
210 * If it's equal to 1, we know this entry is just moving
211 * but not removed. We simply return to avoid useless destroy()
212 * proce ssing.
214 atomic_dec((atomic_t *)info->refcount);
215 if (*info->refcount)
216 return;
218 /* Don't leak my memory, you idiot.
219 * Bug found with nfsim.. the netfilter's best
220 * friend. --peejix */
221 kfree(info->refcount);
223 /* This entry has been removed from the table so
224 * decrease the refcount of all countries it is
225 * using.
228 for (i = 0; i < info->count; i++)
229 if ((node = info->mem[i]) != NULL) {
230 atomic_dec((atomic_t *)&node->ref);
232 /* Free up some memory if that node isn't used
233 * anymore. */
234 if (node->ref < 1)
235 remove_node(node);
237 else
238 /* Something strange happened. There's no memory allocated for this
239 * country. Please send this bug to the mailing list. */
240 printk(KERN_ERR
241 "xt_geoip: What happened peejix ? What happened acidfu ?\n"
242 "xt_geoip: please report this bug to the maintainers\n");
243 return;
246 static struct xt_match xt_geoip_match __read_mostly = {
247 .family = NFPROTO_IPV4,
248 .name = "geoip",
249 .match = xt_geoip_mt,
250 .checkentry = xt_geoip_mt_checkentry,
251 .destroy = xt_geoip_mt_destroy,
252 .matchsize = sizeof(struct xt_geoip_match_info),
253 .me = THIS_MODULE,
256 static int __init xt_geoip_mt_init(void)
258 return xt_register_match(&xt_geoip_match);
261 static void __exit xt_geoip_mt_fini(void)
263 xt_unregister_match(&xt_geoip_match);
266 module_init(xt_geoip_mt_init);
267 module_exit(xt_geoip_mt_fini);