1 include/linux/netfilter_ipv4/ipt_connlimit.h | 12 +
2 net/ipv4/netfilter/Kconfig | 10 +
3 net/ipv4/netfilter/Makefile | 1
4 net/ipv4/netfilter/ipt_connlimit.c | 255 +++++++++++++++++++++++++++
5 4 files changed, 278 insertions(+)
7 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux/include/linux/netfilter_ipv4/ipt_connlimit.h
8 --- linux.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 00:00:00.000000000 +0000
9 +++ linux/include/linux/netfilter_ipv4/ipt_connlimit.h 2006-08-29 12:32:46.000000000 +0000
11 +#ifndef _IPT_CONNLIMIT_H
12 +#define _IPT_CONNLIMIT_H
14 +struct ipt_connlimit_data;
16 +struct ipt_connlimit_info {
20 + struct ipt_connlimit_data *data;
22 +#endif /* _IPT_CONNLIMIT_H */
23 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_connlimit.c linux/net/ipv4/netfilter/ipt_connlimit.c
24 --- linux.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 00:00:00.000000000 +0000
25 +++ linux/net/ipv4/netfilter/ipt_connlimit.c 2006-08-29 12:32:46.000000000 +0000
28 + * netfilter module to limit the number of parallel tcp
29 + * connections per IP address.
30 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
31 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
32 + * only ignore TIME_WAIT or gone connections
36 + * Kernel module to match connection tracking information.
37 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
39 +#include <linux/module.h>
40 +#include <linux/skbuff.h>
41 +#include <linux/version.h>
42 +#include <linux/list.h>
43 +#include <linux/netfilter_ipv4/ip_conntrack.h>
44 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
45 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
46 +#include <linux/netfilter_ipv4/ip_tables.h>
47 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
51 +MODULE_LICENSE("GPL");
53 +/* we'll save the tuples of all connections we care about */
54 +struct ipt_connlimit_conn
56 + struct list_head list;
57 + struct ip_conntrack_tuple tuple;
60 +struct ipt_connlimit_data {
62 + struct list_head iphash[256];
65 +static inline unsigned ipt_iphash(const unsigned addr)
67 + return ((addr ^ (addr >> 8) ^ (addr >> 16) ^ (addr >> 24)) & 0xff);
70 +static int count_them(struct ipt_connlimit_data *data,
71 + u_int32_t addr, u_int32_t mask,
72 + struct ip_conntrack *ct)
75 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
76 + "fin_wait", "time_wait", "close", "close_wait",
77 + "last_ack", "listen" };
79 + int addit = 1, matches = 0;
80 + struct ip_conntrack_tuple tuple;
81 + struct ip_conntrack_tuple_hash *found;
82 + struct ipt_connlimit_conn *conn;
83 + struct list_head *hash,*lh;
85 + spin_lock_bh(&data->lock);
86 + tuple = ct->tuplehash[0].tuple;
87 + hash = &data->iphash[ipt_iphash(addr & mask)];
89 + /* check the saved connections */
90 + for (lh = hash->next; lh != hash; lh = lh->next) {
91 + struct ip_conntrack *found_ct = NULL;
92 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
93 + found = ip_conntrack_find_get(&conn->tuple,ct);
95 + && (found_ct = tuplehash_to_ctrack(found)) != NULL
96 + && 0 == memcmp(&conn->tuple,&tuple,sizeof(tuple))
97 + && found_ct->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
98 + /* Just to be sure we have it only once in the list.
99 + We should'nt see tuples twice unless someone hooks this
100 + into a table without "-p tcp --syn" */
104 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
105 + ipt_iphash(addr & mask),
106 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
107 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
108 + (NULL != found) ? tcp[found_ct->proto.tcp.state] : "gone");
110 + if (NULL == found) {
111 + /* this one is gone */
113 + list_del(lh->next);
117 + if (found_ct->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
118 + /* we don't care about connections which are
119 + closed already -> ditch it */
121 + list_del(lh->next);
123 + nf_conntrack_put(&found_ct->ct_general);
126 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
127 + /* same source IP address -> be counted! */
130 + nf_conntrack_put(&found_ct->ct_general);
133 + /* save the new connection in our list */
135 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
136 + ipt_iphash(addr & mask),
137 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
138 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
140 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
141 + if (NULL == conn) {
142 + spin_unlock_bh(&data->lock);
145 + memset(conn,0,sizeof(*conn));
146 + INIT_LIST_HEAD(&conn->list);
147 + conn->tuple = tuple;
148 + list_add(&conn->list,hash);
151 + spin_unlock_bh(&data->lock);
156 +match(const struct sk_buff *skb,
157 + const struct net_device *in,
158 + const struct net_device *out,
159 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
160 + const struct xt_match *match,
162 + const void *matchinfo,
164 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
165 + unsigned int protoff,
169 + const struct ipt_connlimit_info *info = matchinfo;
170 + int connections, rv;
171 + struct ip_conntrack *ct;
172 + enum ip_conntrack_info ctinfo;
174 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
176 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
180 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
181 + if (-1 == connections) {
182 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
183 + *hotdrop = 1; /* let's free some memory :-) */
186 + rv = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
188 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
189 + "connections=%d limit=%d match=%s\n",
190 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
191 + connections, info->limit, rv?"yes":"no");
197 +static int check(const char *tablename,
198 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
199 + const void *ip_void,
201 + const struct ipt_ip *ip,
203 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
204 + const struct xt_match *match,
207 + unsigned int matchsize,
208 + unsigned int hook_mask)
210 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
211 + const struct ipt_ip *ip = ip_void;
214 + struct ipt_connlimit_info *info = matchinfo;
217 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
219 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
223 + /* refuse anything but tcp */
224 + if (ip->proto != IPPROTO_TCP)
227 + /* init private data */
228 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
229 + spin_lock_init(&(info->data->lock));
230 + for (i = 0; i < 256; i++)
231 + INIT_LIST_HEAD(&(info->data->iphash[i]));
236 +static void destroy(
237 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
238 + const struct xt_match *match,
240 + void *matchinfo, unsigned int matchsize)
242 + struct ipt_connlimit_info *info = matchinfo;
243 + struct ipt_connlimit_conn *conn;
244 + struct list_head *hash;
248 + for (i = 0; i < 256; i++) {
249 + hash = &(info->data->iphash[i]);
250 + while (hash != hash->next) {
251 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
252 + list_del(hash->next);
259 +static struct ipt_match connlimit_match = {
260 + .name = "connlimit",
262 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
263 + .matchsize = sizeof(struct ipt_connlimit_info),
265 + .checkentry = &check,
266 + .destroy = &destroy,
270 +static int __init init(void)
272 + return ipt_register_match(&connlimit_match);
275 +static void __exit fini(void)
277 + ipt_unregister_match(&connlimit_match);
282 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
283 --- linux.org/net/ipv4/netfilter/Kconfig 2006-06-18 01:49:35.000000000 +0000
284 +++ linux/net/ipv4/netfilter/Kconfig 2006-08-29 12:32:46.000000000 +0000
286 Allows altering the ARP packet payload: source and destination
287 hardware and network addresses.
289 +config IP_NF_MATCH_CONNLIMIT
290 + tristate 'Connections/IP limit match support'
291 + depends on IP_NF_IPTABLES
293 + This match allows you to restrict the number of parallel TCP
294 + connections to a server per client IP address (or address block).
296 + If you want to compile it as a module, say M here and read
297 + Documentation/modules.txt. If unsure, say `N'.
301 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
302 --- linux.org/net/ipv4/netfilter/Makefile 2006-06-18 01:49:35.000000000 +0000
303 +++ linux/net/ipv4/netfilter/Makefile 2006-08-29 12:32:46.000000000 +0000
305 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o