1 diff -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
5 +#ifndef _IPT_CONNLIMIT_H
6 +#define _IPT_CONNLIMIT_H
8 +struct ipt_connlimit_data;
10 +struct ipt_connlimit_info {
14 + struct ipt_connlimit_data *data;
16 +#endif /* _IPT_CONNLIMIT_H */
17 diff -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
22 Weight of the packet with non-priviliged destination port.
24 +config IP_NF_MATCH_CONNLIMIT
25 + tristate 'Connections/IP limit match support'
26 + depends on IP_NF_IPTABLES
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
34 + # allow 2 telnet connections per client host
35 + iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT
37 + # you can also match the other way around:
38 + iptables -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT
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
47 diff -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
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
58 diff -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
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
71 + * Kernel module to match connection tracking information.
72 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
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>
85 +MODULE_LICENSE("GPL");
87 +/* we'll save the tuples of all connections we care about */
88 +struct ipt_connlimit_conn
90 + struct list_head list;
91 + struct ip_conntrack_tuple tuple;
94 +struct ipt_connlimit_data {
96 + struct list_head iphash[256];
99 +static int ipt_iphash(u_int32_t addr)
103 + hash = addr & 0xff;
104 + hash ^= (addr >> 8) & 0xff;
105 + hash ^= (addr >> 16) & 0xff;
106 + hash ^= (addr >> 24) & 0xff;
110 +static int count_them(struct ipt_connlimit_data *data,
111 + u_int32_t addr, u_int32_t mask,
112 + struct ip_conntrack *ct)
115 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
116 + "fin_wait", "time_wait", "close", "close_wait",
117 + "last_ack", "listen" };
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;
125 + spin_lock(&data->lock);
126 + tuple = ct->tuplehash[0].tuple;
127 + hash = &data->iphash[ipt_iphash(addr & mask)];
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)) &&
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" */
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");
148 + if (NULL == found) {
149 + /* this one is gone */
151 + list_del(lh->next);
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 */
159 + list_del(lh->next);
161 + nf_conntrack_put(&found->ctrack->infos[0]);
164 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
165 + /* same source IP address -> be counted! */
168 + nf_conntrack_put(&found->ctrack->infos[0]);
171 + /* save the new connection in our list */
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));
178 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
181 + memset(conn,0,sizeof(*conn));
182 + INIT_LIST_HEAD(&conn->list);
183 + conn->tuple = tuple;
184 + list_add(&conn->list,hash);
187 + spin_unlock(&data->lock);
192 +match(const struct sk_buff *skb,
193 + const struct net_device *in,
194 + const struct net_device *out,
195 + const void *matchinfo,
201 + const struct ipt_connlimit_info *info = matchinfo;
202 + int connections, match;
203 + struct ip_conntrack *ct;
204 + enum ip_conntrack_info ctinfo;
206 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
208 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
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 :-) */
218 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
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");
229 +static int check(const char *tablename,
230 + const struct ipt_ip *ip,
232 + unsigned int matchsize,
233 + unsigned int hook_mask)
235 + struct ipt_connlimit_info *info = matchinfo;
239 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
242 + /* refuse anything but tcp */
243 + if (ip->proto != IPPROTO_TCP)
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]));
255 +static void destroy(void *matchinfo, unsigned int matchinfosize)
257 + struct ipt_connlimit_info *info = matchinfo;
258 + struct ipt_connlimit_conn *conn;
259 + struct list_head *hash;
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);
274 +static struct ipt_match connlimit_match = {
275 + .name = "connlimit",
277 + .checkentry = &check,
281 +static int __init init(void)
283 + return ipt_register_match(&connlimit_match);
286 +static void __exit fini(void)
288 + ipt_unregister_match(&connlimit_match);