]>
Commit | Line | Data |
---|---|---|
7f651772 | 1 | diff -Nru linux-2.6.22/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.22-pom2patch/include/linux/netfilter_ipv4/ipt_connlimit.h |
2 | --- linux-2.6.22/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ linux-2.6.22-pom2patch/include/linux/netfilter_ipv4/ipt_connlimit.h 2007-08-07 18:38:25.000000000 +0200 | |
4 | @@ -0,0 +1,12 @@ | |
5 | +#ifndef _IPT_CONNLIMIT_H | |
6 | +#define _IPT_CONNLIMIT_H | |
7 | + | |
8 | +struct ipt_connlimit_data; | |
9 | + | |
10 | +struct ipt_connlimit_info { | |
11 | + int limit; | |
12 | + int inverse; | |
13 | + u_int32_t mask; | |
14 | + struct ipt_connlimit_data *data; | |
15 | +}; | |
16 | +#endif /* _IPT_CONNLIMIT_H */ | |
17 | diff -Nru linux-2.6.22/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.22-pom2patch/net/ipv4/netfilter/ipt_connlimit.c | |
18 | --- linux-2.6.22/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100 | |
19 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/ipt_connlimit.c 2007-08-07 18:38:25.000000000 +0200 | |
20 | @@ -0,0 +1,340 @@ | |
21 | +/* | |
22 | + * netfilter module to limit the number of parallel tcp | |
23 | + * connections per IP address. | |
24 | + * (c) 2000 Gerd Knorr <kraxel@bytesex.org> | |
25 | + * Nov 2002: Martin Bene <martin.bene@icomedias.com>: | |
26 | + * only ignore TIME_WAIT or gone connections | |
27 | + * | |
28 | + * based on ... | |
29 | + * | |
30 | + * Kernel module to match connection tracking information. | |
31 | + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). | |
32 | + */ | |
33 | +#include <linux/module.h> | |
34 | +#include <linux/skbuff.h> | |
35 | +#include <linux/version.h> | |
36 | +#include <linux/list.h> | |
37 | + | |
38 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) | |
39 | +#define CONFIG_NF_CONNTRACK_SUPPORT | |
40 | +#endif | |
41 | + | |
42 | +#ifdef CONFIG_NF_CONNTRACK_SUPPORT | |
43 | +#include <net/netfilter/nf_conntrack.h> | |
44 | +#include <net/netfilter/nf_conntrack_core.h> | |
45 | +#include <linux/netfilter/nf_conntrack_tcp.h> | |
46 | +#else | |
47 | +#include <linux/netfilter_ipv4/ip_conntrack.h> | |
48 | +#include <linux/netfilter_ipv4/ip_conntrack_core.h> | |
49 | +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h> | |
50 | +#endif | |
51 | + | |
52 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
53 | +#include <linux/netfilter_ipv4/ipt_connlimit.h> | |
54 | + | |
55 | +#define DEBUG 0 | |
56 | + | |
57 | +MODULE_LICENSE("GPL"); | |
58 | + | |
59 | +/* we'll save the tuples of all connections we care about */ | |
60 | +struct ipt_connlimit_conn | |
61 | +{ | |
62 | + struct list_head list; | |
63 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
64 | + struct ip_conntrack_tuple tuple; | |
65 | +#else | |
66 | + struct nf_conntrack_tuple tuple; | |
67 | +#endif | |
68 | +}; | |
69 | + | |
70 | +struct ipt_connlimit_data { | |
71 | + spinlock_t lock; | |
72 | + struct list_head iphash[256]; | |
73 | +}; | |
74 | + | |
75 | +static inline unsigned ipt_iphash(const unsigned addr) | |
76 | +{ | |
77 | + return ((addr ^ (addr >> 8) ^ (addr >> 16) ^ (addr >> 24)) & 0xff); | |
78 | +} | |
79 | + | |
80 | +static int count_them(struct ipt_connlimit_data *data, | |
81 | + u_int32_t addr, u_int32_t mask, | |
82 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
83 | + struct ip_conntrack *ct) | |
84 | +#else | |
85 | + struct nf_conn *ct) | |
86 | +#endif | |
87 | + | |
88 | +{ | |
89 | +#if DEBUG | |
90 | + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", | |
91 | + "fin_wait", "time_wait", "close", "close_wait", | |
92 | + "last_ack", "listen" }; | |
93 | +#endif | |
94 | + int addit = 1, matches = 0; | |
95 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
96 | + struct ip_conntrack_tuple tuple; | |
97 | + struct ip_conntrack_tuple_hash *found; | |
98 | +#else | |
99 | + struct nf_conntrack_tuple tuple; | |
100 | + struct nf_conntrack_tuple_hash *found; | |
101 | +#endif | |
102 | + struct ipt_connlimit_conn *conn; | |
103 | + struct list_head *hash,*lh; | |
104 | + | |
105 | + spin_lock_bh(&data->lock); | |
106 | + tuple = ct->tuplehash[0].tuple; | |
107 | + hash = &data->iphash[ipt_iphash(addr & mask)]; | |
108 | + | |
109 | + /* check the saved connections */ | |
110 | + for (lh = hash->next; lh != hash; lh = lh->next) { | |
111 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
112 | + struct ip_conntrack *found_ct = NULL; | |
113 | + conn = list_entry(lh, struct ipt_connlimit_conn, list); | |
114 | + found = ip_conntrack_find_get(&conn->tuple, ct); | |
115 | +#else | |
116 | + struct nf_conn *found_ct = NULL; | |
117 | + conn = list_entry(lh, struct ipt_connlimit_conn, list); | |
118 | + found = nf_conntrack_find_get(&conn->tuple, ct); | |
119 | +#endif | |
120 | + | |
121 | + if (found != NULL | |
122 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
123 | + && (found_ct = tuplehash_to_ctrack(found)) != NULL | |
124 | +#else | |
125 | + && (found_ct = nf_ct_tuplehash_to_ctrack(found)) != NULL | |
126 | +#endif | |
127 | + && 0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) | |
128 | + && found_ct->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { | |
129 | + /* Just to be sure we have it only once in the list. | |
130 | + We should'nt see tuples twice unless someone hooks this | |
131 | + into a table without "-p tcp --syn" */ | |
132 | + addit = 0; | |
133 | + } | |
134 | +#if DEBUG | |
135 | + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", | |
136 | + ipt_iphash(addr & mask), | |
137 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
138 | + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), | |
139 | + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), | |
140 | +#else | |
141 | + NIPQUAD(conn->tuple.src.u3.ip), ntohs(conn->tuple.src.u.tcp.port), | |
142 | + NIPQUAD(conn->tuple.dst.u3.ip), ntohs(conn->tuple.dst.u.tcp.port), | |
143 | +#endif | |
144 | + (NULL != found) ? tcp[found_ct->proto.tcp.state] : "gone"); | |
145 | +#endif | |
146 | + if (NULL == found) { | |
147 | + /* this one is gone */ | |
148 | + lh = lh->prev; | |
149 | + list_del(lh->next); | |
150 | + kfree(conn); | |
151 | + continue; | |
152 | + } | |
153 | + if (found_ct->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { | |
154 | + /* we don't care about connections which are | |
155 | + closed already -> ditch it */ | |
156 | + lh = lh->prev; | |
157 | + list_del(lh->next); | |
158 | + kfree(conn); | |
159 | + nf_conntrack_put(&found_ct->ct_general); | |
160 | + continue; | |
161 | + } | |
162 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
163 | + if ((addr & mask) == (conn->tuple.src.ip & mask)) { | |
164 | +#else | |
165 | + if ((addr & mask) == (conn->tuple.src.u3.ip & mask)) { | |
166 | +#endif | |
167 | + /* same source IP address -> be counted! */ | |
168 | + matches++; | |
169 | + } | |
170 | + nf_conntrack_put(&found_ct->ct_general); | |
171 | + } | |
172 | + if (addit) { | |
173 | + /* save the new connection in our list */ | |
174 | +#if DEBUG | |
175 | + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", | |
176 | + ipt_iphash(addr & mask), | |
177 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
178 | + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), | |
179 | + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); | |
180 | +#else | |
181 | + NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port), | |
182 | + NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port)); | |
183 | +#endif | |
184 | + | |
185 | +#endif | |
186 | + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); | |
187 | + if (NULL == conn) { | |
188 | + spin_unlock_bh(&data->lock); | |
189 | + return -1; | |
190 | + } | |
191 | + memset(conn,0,sizeof(*conn)); | |
192 | + INIT_LIST_HEAD(&conn->list); | |
193 | + conn->tuple = tuple; | |
194 | + list_add(&conn->list,hash); | |
195 | + matches++; | |
196 | + } | |
197 | + spin_unlock_bh(&data->lock); | |
198 | + return matches; | |
199 | +} | |
200 | + | |
201 | +static int | |
202 | +match(const struct sk_buff *skb, | |
203 | + const struct net_device *in, | |
204 | + const struct net_device *out, | |
205 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) | |
206 | + const struct xt_match *match, | |
207 | +#endif | |
208 | + const void *matchinfo, | |
209 | + int offset, | |
210 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) | |
211 | + unsigned int protoff, | |
212 | +#endif | |
213 | + int *hotdrop) | |
214 | +{ | |
215 | + const struct ipt_connlimit_info *info = matchinfo; | |
216 | + int connections, rv; | |
217 | +#ifndef CONFIG_NF_CONNTRACK_SUPPORT | |
218 | + struct ip_conntrack *ct; | |
219 | + enum ip_conntrack_info ctinfo; | |
220 | + | |
221 | + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | |
222 | +#else | |
223 | + struct nf_conn *ct; | |
224 | + enum ip_conntrack_info ctinfo; | |
225 | + | |
226 | + ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); | |
227 | +#endif | |
228 | + if (NULL == ct) { | |
229 | + printk("ipt_connlimit: Oops: invalid ct state ?\n"); | |
230 | + *hotdrop = 1; | |
231 | + return 0; | |
232 | + } | |
233 | + | |
234 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) | |
235 | + connections = count_them(info->data, ip_hdr(skb)->saddr, info->mask, ct); | |
236 | +#else | |
237 | + connections = count_them(info->data, skb->nh.iph->saddr, info->mask, ct); | |
238 | +#endif | |
239 | + if (-1 == connections) { | |
240 | + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); | |
241 | + *hotdrop = 1; /* let's free some memory :-) */ | |
242 | + return 0; | |
243 | + } | |
244 | + rv = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); | |
245 | +#if DEBUG | |
246 | + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " | |
247 | + "connections=%d limit=%d match=%s\n", | |
248 | + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), | |
249 | + connections, info->limit, rv?"yes":"no"); | |
250 | +#endif | |
251 | + | |
252 | + return rv; | |
253 | +} | |
254 | + | |
255 | +static int checkentry(const char *tablename, | |
256 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) | |
257 | + const void *ip_void, | |
258 | +#else | |
259 | + const struct ipt_ip *ip, | |
260 | +#endif | |
261 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) | |
262 | + const struct xt_match *match, | |
263 | +#endif | |
264 | + void *matchinfo, | |
265 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) | |
266 | + unsigned int matchsize, | |
267 | +#endif | |
268 | + unsigned int hook_mask) | |
269 | +{ | |
270 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) | |
271 | + const struct ipt_ip *ip = ip_void; | |
272 | +#endif | |
273 | + | |
274 | + struct ipt_connlimit_info *info = matchinfo; | |
275 | + int i; | |
276 | + | |
277 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) | |
278 | + /* verify size */ | |
279 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) | |
280 | + return 0; | |
281 | +#endif | |
282 | + | |
283 | + /* refuse anything but tcp */ | |
284 | + if (ip->proto != IPPROTO_TCP) | |
285 | + return 0; | |
286 | + | |
287 | + /* init private data */ | |
288 | + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); | |
289 | + spin_lock_init(&(info->data->lock)); | |
290 | + for (i = 0; i < 256; i++) | |
291 | + INIT_LIST_HEAD(&(info->data->iphash[i])); | |
292 | + | |
293 | + return 1; | |
294 | +} | |
295 | + | |
296 | +static void destroy( | |
297 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) | |
298 | + const struct xt_match *match, | |
299 | +#endif | |
300 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) | |
301 | + void *matchinfo, unsigned int matchsize) | |
302 | +#else | |
303 | + void *matchinfo) | |
304 | +#endif | |
305 | +{ | |
306 | + struct ipt_connlimit_info *info = matchinfo; | |
307 | + struct ipt_connlimit_conn *conn; | |
308 | + struct list_head *hash; | |
309 | + int i; | |
310 | + | |
311 | + /* cleanup */ | |
312 | + for (i = 0; i < 256; i++) { | |
313 | + hash = &(info->data->iphash[i]); | |
314 | + while (hash != hash->next) { | |
315 | + conn = list_entry(hash->next,struct ipt_connlimit_conn,list); | |
316 | + list_del(hash->next); | |
317 | + kfree(conn); | |
318 | + } | |
319 | + } | |
320 | + kfree(info->data); | |
321 | +} | |
322 | + | |
323 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) | |
324 | +static struct xt_match connlimit_match = { | |
325 | +#else | |
326 | +static struct ipt_match connlimit_match = { | |
327 | +#endif | |
328 | + .name = "connlimit", | |
329 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) | |
330 | + .family = AF_INET, | |
331 | +#endif | |
332 | + .match = &match, | |
333 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) | |
334 | + .matchsize = sizeof(struct ipt_connlimit_info), | |
335 | +#endif | |
336 | + .checkentry = &checkentry, | |
337 | + .destroy = &destroy, | |
338 | + .me = THIS_MODULE | |
339 | +}; | |
340 | + | |
341 | +static int __init init(void) | |
342 | +{ | |
343 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) | |
344 | + return xt_register_match(&connlimit_match); | |
345 | +#else | |
346 | + return ipt_register_match(&connlimit_match); | |
347 | +#endif | |
348 | +} | |
349 | + | |
350 | +static void __exit fini(void) | |
351 | +{ | |
352 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) | |
353 | + xt_unregister_match(&connlimit_match); | |
354 | +#else | |
355 | + ipt_unregister_match(&connlimit_match); | |
356 | +#endif | |
357 | +} | |
358 | + | |
359 | +module_init(init); | |
360 | +module_exit(fini); | |
361 | diff -Nru linux-2.6.22/net/ipv4/netfilter/Kconfig linux-2.6.22-pom2patch/net/ipv4/netfilter/Kconfig | |
362 | --- linux-2.6.22/net/ipv4/netfilter/Kconfig 2007-07-09 01:32:17.000000000 +0200 | |
363 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/Kconfig 2007-08-07 18:38:25.000000000 +0200 | |
364 | @@ -402,5 +402,15 @@ | |
365 | Allows altering the ARP packet payload: source and destination | |
366 | hardware and network addresses. | |
367 | ||
368 | +config IP_NF_MATCH_CONNLIMIT | |
369 | + tristate 'Connections/IP limit match support' | |
370 | + depends on IP_NF_IPTABLES | |
371 | + help | |
372 | + This match allows you to restrict the number of parallel TCP | |
373 | + connections to a server per client IP address (or address block). | |
374 | + | |
375 | + If you want to compile it as a module, say M here and read | |
376 | + Documentation/modules.txt. If unsure, say `N'. | |
377 | + | |
378 | endmenu | |
379 | ||
380 | diff -Nru linux-2.6.22/net/ipv4/netfilter/Makefile linux-2.6.22-pom2patch/net/ipv4/netfilter/Makefile | |
381 | --- linux-2.6.22/net/ipv4/netfilter/Makefile 2007-07-09 01:32:17.000000000 +0200 | |
382 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/Makefile 2007-08-07 18:38:25.000000000 +0200 | |
383 | @@ -44,6 +44,7 @@ | |
384 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o | |
385 | ||
386 | obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o | |
387 | +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o | |
388 | ||
389 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o | |
390 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o |