]> git.pld-linux.org Git - packages/kernel.git/blame - kernel-pom-ng-geoip.patch
- renamed to kernel-wrr.patch
[packages/kernel.git] / kernel-pom-ng-geoip.patch
CommitLineData
6890440f 1diff -NurpP --minimal linux-2.6.21.a/include/linux/netfilter_ipv4/ipt_geoip.h linux-2.6.21.b/include/linux/netfilter_ipv4/ipt_geoip.h
2--- linux-2.6.21.a/include/linux/netfilter_ipv4/ipt_geoip.h 1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.6.21.b/include/linux/netfilter_ipv4/ipt_geoip.h 2007-05-30 12:08:43.000000000 +0200
1aedc22c 4@@ -0,0 +1,50 @@
5+/* ipt_geoip.h header file for libipt_geoip.c and ipt_geoip.c
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; either version 2 of the License, or
10+ * (at your option) any later version.
11+ *
12+ * Copyright (c) 2004, 2005, 2006 Samuel Jean & Nicolas Bouliane
13+ */
14+#ifndef _IPT_GEOIP_H
15+#define _IPT_GEOIP_H
16+
17+#define IPT_GEOIP_SRC 0x01 /* Perform check on Source IP */
18+#define IPT_GEOIP_DST 0x02 /* Perform check on Destination IP */
19+#define IPT_GEOIP_INV 0x04 /* Negate the condition */
20+
21+#define IPT_GEOIP_MAX 15 /* Maximum of countries */
22+
23+struct geoip_subnet {
24+ u_int32_t begin;
25+ u_int32_t end;
26+};
27+
28+struct geoip_info {
29+ struct geoip_subnet *subnets;
30+ u_int32_t count;
31+ u_int32_t ref;
32+ u_int16_t cc;
33+ struct geoip_info *next;
34+ struct geoip_info *prev;
35+};
36+
37+struct ipt_geoip_info {
38+ u_int8_t flags;
39+ u_int8_t count;
40+ u_int16_t cc[IPT_GEOIP_MAX];
41+
42+ /* Used internally by the kernel */
43+ struct geoip_info *mem[IPT_GEOIP_MAX];
44+ u_int8_t *refcount;
45+
46+ /* not implemented yet:
47+ void *fini;
48+ */
49+};
50+
51+#define COUNTRY(cc) (cc >> 8), (cc & 0x00FF)
52+
53+#endif
54+
6890440f 55diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/Kconfig linux-2.6.21.b/net/ipv4/netfilter/Kconfig
56--- linux-2.6.21.a/net/ipv4/netfilter/Kconfig 2007-05-30 12:07:14.000000000 +0200
57+++ linux-2.6.21.b/net/ipv4/netfilter/Kconfig 2007-05-30 12:08:43.000000000 +0200
06c0c671 58@@ -921,5 +921,21 @@ config IP_NF_MATCH_CONNLIMIT
1aedc22c 59 If you want to compile it as a module, say M here and read
60 Documentation/modules.txt. If unsure, say `N'.
61
62+config IP_NF_MATCH_GEOIP
63+ tristate 'geoip match support'
64+ depends on IP_NF_IPTABLES
65+ help
66+ This option allows you to match a packet by its source or
67+ destination country. Basically, you need a country's
68+ database containing all subnets and associated countries.
69+
70+ For the complete procedure and understanding, read :
71+ http://people.netfilter.org/peejix/geoip/howto/geoip-HOWTO.html
72+
73+ If you want to compile it as a module, say M here and read
74+ <file:Documentation/modules.txt>. The module will be
75+ called `ipt_geoip'. If unsure, say `N'.
76+
77+
78 endmenu
79
6890440f 80diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/Makefile linux-2.6.21.b/net/ipv4/netfilter/Makefile
81--- linux-2.6.21.a/net/ipv4/netfilter/Makefile 2007-05-30 12:07:14.000000000 +0200
82+++ linux-2.6.21.b/net/ipv4/netfilter/Makefile 2007-05-30 12:08:43.000000000 +0200
b1443212 83@@ -0,0 +0,1 @@
1aedc22c 84+obj-$(CONFIG_IP_NF_MATCH_GEOIP) += ipt_geoip.o
6890440f 85diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/ipt_geoip.c linux-2.6.21.b/net/ipv4/netfilter/ipt_geoip.c
86--- linux-2.6.21.a/net/ipv4/netfilter/ipt_geoip.c 1970-01-01 01:00:00.000000000 +0100
87+++ linux-2.6.21.b/net/ipv4/netfilter/ipt_geoip.c 2007-05-30 12:08:43.000000000 +0200
6447fea8 88@@ -0,0 +1,302 @@
1aedc22c 89+/* iptables kernel module for the geoip match
90+ *
91+ * This program is free software; you can redistribute it and/or modify
92+ * it under the terms of the GNU General Public License as published by
93+ * the Free Software Foundation; either version 2 of the License, or
94+ * (at your option) any later version.
95+ *
96+ * Copyright (c) 2004, 2005, 2006 Samuel Jean & Nicolas Bouliane
97+ */
98+#include <linux/module.h>
99+#include <linux/kernel.h>
100+#include <linux/version.h>
101+#include <linux/skbuff.h>
102+#include <linux/netdevice.h>
103+#include <asm/uaccess.h>
104+#include <asm/atomic.h>
6447fea8 105+#include <linux/netfilter/x_tables.h>
1aedc22c 106+#include <linux/netfilter_ipv4/ipt_geoip.h>
107+#include <linux/netfilter_ipv4/ip_tables.h>
108+
109+MODULE_LICENSE("GPL");
110+MODULE_AUTHOR("Samuel Jean, Nicolas Bouliane");
111+MODULE_DESCRIPTION("iptables module for geoip match");
112+
113+struct geoip_info *head = NULL;
114+static spinlock_t geoip_lock = SPIN_LOCK_UNLOCKED;
115+
116+static struct geoip_info *add_node(struct geoip_info *memcpy)
117+{
118+ struct geoip_info *p =
119+ (struct geoip_info *)kmalloc(sizeof(struct geoip_info), GFP_KERNEL);
120+
121+ struct geoip_subnet *s;
122+
123+ if ((p == NULL) || (copy_from_user(p, memcpy, sizeof(struct geoip_info)) != 0))
124+ return NULL;
125+
126+ s = (struct geoip_subnet *)kmalloc(p->count * sizeof(struct geoip_subnet), GFP_KERNEL);
127+ if ((s == NULL) || (copy_from_user(s, p->subnets, p->count * sizeof(struct geoip_subnet)) != 0))
128+ return NULL;
129+
130+ spin_lock_bh(&geoip_lock);
131+
132+ p->subnets = s;
133+ p->ref = 1;
134+ p->next = head;
135+ p->prev = NULL;
136+ if (p->next) p->next->prev = p;
137+ head = p;
138+
139+ spin_unlock_bh(&geoip_lock);
140+ return p;
141+}
142+
143+static void remove_node(struct geoip_info *p)
144+ {
145+ spin_lock_bh(&geoip_lock);
146+
147+ if (p->next) { /* Am I following a node ? */
148+ p->next->prev = p->prev;
149+ if (p->prev) p->prev->next = p->next; /* Is there a node behind me ? */
150+ else head = p->next; /* No? Then I was the head */
151+ }
152+
153+ else
154+ if (p->prev) /* Is there a node behind me ? */
155+ p->prev->next = NULL;
156+ else
157+ head = NULL; /* No, we're alone */
158+
159+ /* So now am unlinked or the only one alive, right ?
160+ * What are you waiting ? Free up some memory!
161+ */
162+
163+ kfree(p->subnets);
164+ kfree(p);
165+
166+ spin_unlock_bh(&geoip_lock);
167+ return;
168+}
169+
170+static struct geoip_info *find_node(u_int16_t cc)
171+{
172+ struct geoip_info *p = head;
173+ spin_lock_bh(&geoip_lock);
174+
175+ while (p) {
176+ if (p->cc == cc) {
177+ spin_unlock_bh(&geoip_lock);
178+ return p;
179+ }
180+ p = p->next;
181+ }
182+ spin_unlock_bh(&geoip_lock);
183+ return NULL;
184+}
185+
186+static int match(const struct sk_buff *skb,
187+ const struct net_device *in,
188+ const struct net_device *out,
189+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
190+ const struct xt_match *match,
191+#endif
192+ const void *matchinfo,
193+ int offset,
194+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
195+ unsigned int protoff,
196+#endif
197+ int *hotdrop)
198+{
199+ const struct ipt_geoip_info *info = matchinfo;
200+ const struct geoip_info *node; /* This keeps the code sexy */
5ce52adc 201+ const struct iphdr *iph = ip_hdr(skb);
1aedc22c 202+ u_int32_t ip, j;
203+ u_int8_t i;
204+
205+ if (info->flags & IPT_GEOIP_SRC)
206+ ip = ntohl(iph->saddr);
207+ else
208+ ip = ntohl(iph->daddr);
209+
210+ spin_lock_bh(&geoip_lock);
211+ for (i = 0; i < info->count; i++) {
212+ if ((node = info->mem[i]) == NULL) {
213+ printk(KERN_ERR "ipt_geoip: what the hell ?? '%c%c' isn't loaded into memory... skip it!\n",
214+ COUNTRY(info->cc[i]));
215+
216+ continue;
217+ }
218+
219+ for (j = 0; j < node->count; j++)
220+ if ((ip > node->subnets[j].begin) && (ip < node->subnets[j].end)) {
221+ spin_unlock_bh(&geoip_lock);
222+ return (info->flags & IPT_GEOIP_INV) ? 0 : 1;
223+ }
224+ }
225+
226+ spin_unlock_bh(&geoip_lock);
227+ return (info->flags & IPT_GEOIP_INV) ? 1 : 0;
228+}
229+
230+static int geoip_checkentry(const char *tablename,
231+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
232+ const void *ip,
233+#else
234+ const struct ipt_ip *ip,
235+#endif
236+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
237+ const struct xt_match *match,
238+#endif
239+ void *matchinfo,
240+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
241+ unsigned int matchsize,
242+#endif
243+ unsigned int hook_mask)
244+{
245+ struct ipt_geoip_info *info = matchinfo;
246+ struct geoip_info *node;
247+ u_int8_t i;
248+
249+ /* FIXME: Call a function to free userspace allocated memory.
250+ * As Martin J. said; this match might eat lot of memory
251+ * if commited with iptables-restore --noflush
252+ void (*gfree)(struct geoip_info *oldmem);
253+ gfree = info->fini;
254+ */
255+
256+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
257+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_geoip_info))) {
258+ printk(KERN_ERR "ipt_geoip: matchsize differ, you may have forgotten to recompile me\n");
259+ return 0;
260+ }
261+#endif
262+
263+ /* If info->refcount isn't NULL, then
264+ * it means that checkentry() already
265+ * initialized this entry. Increase a
266+ * refcount to prevent destroy() of
267+ * this entry. */
268+ if (info->refcount != NULL) {
269+ atomic_inc((atomic_t *)info->refcount);
270+ return 1;
271+ }
272+
273+
274+ for (i = 0; i < info->count; i++) {
275+
276+ if ((node = find_node(info->cc[i])) != NULL)
277+ atomic_inc((atomic_t *)&node->ref); //increase the reference
278+ else
279+ if ((node = add_node(info->mem[i])) == NULL) {
280+ printk(KERN_ERR
281+ "ipt_geoip: unable to load '%c%c' into memory\n",
282+ COUNTRY(info->cc[i]));
283+ return 0;
284+ }
285+
286+ /* Free userspace allocated memory for that country.
287+ * FIXME: It's a bit odd to call this function everytime
288+ * we process a country. Would be nice to call
289+ * it once after all countries've been processed.
290+ * - SJ
291+ * *not implemented for now*
292+ gfree(info->mem[i]);
293+ */
294+
295+ /* Overwrite the now-useless pointer info->mem[i] with
296+ * a pointer to the node's kernelspace structure.
297+ * This avoids searching for a node in the match() and
298+ * destroy() functions.
299+ */
300+ info->mem[i] = node;
301+ }
302+
303+ /* We allocate some memory and give info->refcount a pointer
304+ * to this memory. This prevents checkentry() from increasing a refcount
305+ * different from the one used by destroy().
306+ * For explanation, see http://www.mail-archive.com/netfilter-devel@lists.samba.org/msg00625.html
307+ */
308+ info->refcount = kmalloc(sizeof(u_int8_t), GFP_KERNEL);
309+ if (info->refcount == NULL) {
310+ printk(KERN_ERR "ipt_geoip: failed to allocate `refcount' memory\n");
311+ return 0;
312+ }
313+ *(info->refcount) = 1;
314+
315+ return 1;
316+}
317+
318+static void geoip_destroy(
319+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
320+ const struct xt_match *match, void *matchinfo)
321+#else
322+ void *matchinfo, unsigned int matchsize)
323+#endif
324+{
325+ u_int8_t i;
326+ struct geoip_info *node; /* this keeps the code sexy */
327+
328+ struct ipt_geoip_info *info = matchinfo;
329+ /* Decrease the previously increased refcount in checkentry()
330+ * If it's equal to 1, we know this entry is just moving
331+ * but not removed. We simply return to avoid useless destroy()
332+ * processing.
333+ */
334+ atomic_dec((atomic_t *)info->refcount);
335+ if (*info->refcount)
336+ return;
337+
338+ /* Don't leak my memory, you idiot.
339+ * Bug found with nfsim.. the netfilter's best
340+ * friend. --peejix */
341+ kfree(info->refcount);
342+
343+ /* This entry has been removed from the table so
344+ * decrease the refcount of all countries it is
345+ * using.
346+ */
347+
348+ for (i = 0; i < info->count; i++)
349+ if ((node = info->mem[i]) != NULL) {
350+ atomic_dec((atomic_t *)&node->ref);
351+
352+ /* Free up some memory if that node isn't used
353+ * anymore. */
354+ if (node->ref < 1)
355+ remove_node(node);
356+ }
357+ else
358+ /* Something strange happened. There's no memory allocated for this
359+ * country. Please send this bug to the mailing list. */
360+ printk(KERN_ERR
361+ "ipt_geoip: What happened peejix ? What happened acidmen ?\n"
362+ "ipt_geoip: please report this bug to the maintainers\n");
363+ return;
364+}
365+
6447fea8 366+static struct xt_match geoip_match = {
1aedc22c 367+ .name = "geoip",
6447fea8 368+ .family = AF_INET,
1aedc22c 369+ .match = &match,
370+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
371+ .matchsize = sizeof (struct ipt_geoip_info),
372+#endif
373+ .checkentry = &geoip_checkentry,
374+ .destroy = &geoip_destroy,
375+ .me = THIS_MODULE
376+};
377+
378+static int __init init(void)
379+{
6447fea8 380+ return xt_register_match(&geoip_match);
1aedc22c 381+}
382+
383+static void __exit fini(void)
384+{
6447fea8 385+ xt_unregister_match(&geoip_match);
1aedc22c 386+ return;
387+}
388+
389+module_init(init);
390+module_exit(fini);
This page took 0.101791 seconds and 4 git commands to generate.