]> git.pld-linux.org Git - packages/kernel.git/blame - 2.6.1-NF-connlimit-20040107.patch
- added description of djurban's branch
[packages/kernel.git] / 2.6.1-NF-connlimit-20040107.patch
CommitLineData
559a2977 1diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_connlimit.h
2--- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-01-14 11:11:52.000000000 +0100
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 */
17diff -Nur linux-2.6.1.org/net/ipv4/netfilter/Kconfig linux-2.6.1/net/ipv4/netfilter/Kconfig
18--- linux-2.6.1.org/net/ipv4/netfilter/Kconfig 2004-01-14 10:35:38.000000000 +0100
19+++ linux-2.6.1/net/ipv4/netfilter/Kconfig 2004-01-14 11:11:52.000000000 +0100
20@@ -688,5 +688,26 @@
21
22 Weight of the packet with non-priviliged destination port.
23
24+config IP_NF_MATCH_CONNLIMIT
25+ tristate 'Connections/IP limit match support'
26+ depends on IP_NF_IPTABLES
27+ help
28+ This adds an iptables match which allows you to restrict the
29+ number of parallel TCP connections to a server per client IP address
30+ (or address block).
31+
32+ Examples:
33+
34+ # allow 2 telnet connections per client host
35+ iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT
36+
37+ # you can also match the other way around:
38+ iptables -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT
39+
40+ # limit the nr of parallel http requests to 16 per class C sized
41+ # network (24 bit netmask)
42+ iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 \
43+ --connlimit-mask 24 -j REJECT
44+
45 endmenu
46
47diff -Nur linux-2.6.1.org/net/ipv4/netfilter/Makefile linux-2.6.1/net/ipv4/netfilter/Makefile
48--- linux-2.6.1.org/net/ipv4/netfilter/Makefile 2004-01-14 10:35:38.000000000 +0100
49+++ linux-2.6.1/net/ipv4/netfilter/Makefile 2004-01-14 11:11:52.000000000 +0100
50@@ -72,6 +72,7 @@
51
52 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
53 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
54+obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
55 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
56 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
57
58diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.1/net/ipv4/netfilter/ipt_connlimit.c
59--- linux-2.6.1.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
60+++ linux-2.6.1/net/ipv4/netfilter/ipt_connlimit.c 2004-01-14 13:07:24.000000000 +0100
61@@ -0,0 +1,232 @@
62+/*
63+ * netfilter module to limit the number of parallel tcp
64+ * connections per IP address.
65+ * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
66+ * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
67+ * only ignore TIME_WAIT or gone connections
68+ *
69+ * based on ...
70+ *
71+ * Kernel module to match connection tracking information.
72+ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
73+ */
74+#include <linux/module.h>
75+#include <linux/skbuff.h>
76+#include <linux/list.h>
77+#include <linux/netfilter_ipv4/ip_conntrack.h>
78+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
79+#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
80+#include <linux/netfilter_ipv4/ip_tables.h>
81+#include <linux/netfilter_ipv4/ipt_connlimit.h>
82+
83+#define DEBUG 0
84+
85+MODULE_LICENSE("GPL");
86+
87+/* we'll save the tuples of all connections we care about */
88+struct ipt_connlimit_conn
89+{
90+ struct list_head list;
91+ struct ip_conntrack_tuple tuple;
92+};
93+
94+struct ipt_connlimit_data {
95+ spinlock_t lock;
96+ struct list_head iphash[256];
97+};
98+
99+static int ipt_iphash(u_int32_t addr)
100+{
101+ int hash;
102+
103+ hash = addr & 0xff;
104+ hash ^= (addr >> 8) & 0xff;
105+ hash ^= (addr >> 16) & 0xff;
106+ hash ^= (addr >> 24) & 0xff;
107+ return hash;
108+}
109+
110+static int count_them(struct ipt_connlimit_data *data,
111+ u_int32_t addr, u_int32_t mask,
112+ struct ip_conntrack *ct)
113+{
114+#if DEBUG
115+ const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
116+ "fin_wait", "time_wait", "close", "close_wait",
117+ "last_ack", "listen" };
118+#endif
119+ int addit = 1, matches = 0;
120+ struct ip_conntrack_tuple tuple;
121+ struct ip_conntrack_tuple_hash *found;
122+ struct ipt_connlimit_conn *conn;
123+ struct list_head *hash,*lh;
124+
125+ spin_lock(&data->lock);
126+ tuple = ct->tuplehash[0].tuple;
127+ hash = &data->iphash[ipt_iphash(addr & mask)];
128+
129+ /* check the saved connections */
130+ for (lh = hash->next; lh != hash; lh = lh->next) {
131+ conn = list_entry(lh,struct ipt_connlimit_conn,list);
132+ found = ip_conntrack_find_get(&conn->tuple,ct);
133+ if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
134+ found != NULL &&
135+ found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
136+ /* Just to be sure we have it only once in the list.
137+ We should'nt see tuples twice unless someone hooks this
138+ into a table without "-p tcp --syn" */
139+ addit = 0;
140+ }
141+#if DEBUG
142+ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
143+ ipt_iphash(addr & mask),
144+ NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
145+ NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
146+ (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
147+#endif
148+ if (NULL == found) {
149+ /* this one is gone */
150+ lh = lh->prev;
151+ list_del(lh->next);
152+ kfree(conn);
153+ continue;
154+ }
155+ if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
156+ /* we don't care about connections which are
157+ closed already -> ditch it */
158+ lh = lh->prev;
159+ list_del(lh->next);
160+ kfree(conn);
161+ nf_conntrack_put(&found->ctrack->infos[0]);
162+ continue;
163+ }
164+ if ((addr & mask) == (conn->tuple.src.ip & mask)) {
165+ /* same source IP address -> be counted! */
166+ matches++;
167+ }
168+ nf_conntrack_put(&found->ctrack->infos[0]);
169+ }
170+ if (addit) {
171+ /* save the new connection in our list */
172+#if DEBUG
173+ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
174+ ipt_iphash(addr & mask),
175+ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
176+ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
177+#endif
178+ conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
179+ if (NULL == conn)
180+ return -1;
181+ memset(conn,0,sizeof(*conn));
182+ INIT_LIST_HEAD(&conn->list);
183+ conn->tuple = tuple;
184+ list_add(&conn->list,hash);
185+ matches++;
186+ }
187+ spin_unlock(&data->lock);
188+ return matches;
189+}
190+
191+static int
192+match(const struct sk_buff *skb,
193+ const struct net_device *in,
194+ const struct net_device *out,
195+ const void *matchinfo,
196+ int offset,
197+ const void *hdr,
198+ u_int16_t datalen,
199+ int *hotdrop)
200+{
201+ const struct ipt_connlimit_info *info = matchinfo;
202+ int connections, match;
203+ struct ip_conntrack *ct;
204+ enum ip_conntrack_info ctinfo;
205+
206+ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
207+ if (NULL == ct) {
208+ printk("ipt_connlimit: Oops: invalid ct state ?\n");
209+ *hotdrop = 1;
210+ return 0;
211+ }
212+ connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
213+ if (-1 == connections) {
214+ printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
215+ *hotdrop = 1; /* let's free some memory :-) */
216+ return 0;
217+ }
218+ match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
219+#if DEBUG
220+ printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
221+ "connections=%d limit=%d match=%s\n",
222+ NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
223+ connections, info->limit, match ? "yes" : "no");
224+#endif
225+
226+ return match;
227+}
228+
229+static int check(const char *tablename,
230+ const struct ipt_ip *ip,
231+ void *matchinfo,
232+ unsigned int matchsize,
233+ unsigned int hook_mask)
234+{
235+ struct ipt_connlimit_info *info = matchinfo;
236+ int i;
237+
238+ /* verify size */
239+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
240+ return 0;
241+
242+ /* refuse anything but tcp */
243+ if (ip->proto != IPPROTO_TCP)
244+ return 0;
245+
246+ /* init private data */
247+ info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
248+ spin_lock_init(&(info->data->lock));
249+ for (i = 0; i < 256; i++)
250+ INIT_LIST_HEAD(&(info->data->iphash[i]));
251+
252+ return 1;
253+}
254+
255+static void destroy(void *matchinfo, unsigned int matchinfosize)
256+{
257+ struct ipt_connlimit_info *info = matchinfo;
258+ struct ipt_connlimit_conn *conn;
259+ struct list_head *hash;
260+ int i;
261+
262+ /* cleanup */
263+ for (i = 0; i < 256; i++) {
264+ hash = &(info->data->iphash[i]);
265+ while (hash != hash->next) {
266+ conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
267+ list_del(hash->next);
268+ kfree(conn);
269+ }
270+ }
271+ kfree(info->data);
272+}
273+
274+static struct ipt_match connlimit_match = {
275+ .name = "connlimit",
276+ .match = &match,
277+ .checkentry = &check,
278+ .me = THIS_MODULE,
279+};
280+
281+static int __init init(void)
282+{
283+ return ipt_register_match(&connlimit_match);
284+}
285+
286+static void __exit fini(void)
287+{
288+ ipt_unregister_match(&connlimit_match);
289+
290+}
291+
292+module_init(init);
293+module_exit(fini);
This page took 3.203557 seconds and 4 git commands to generate.