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 | 228 +++++++++++++++++++++++++++
5 4 files changed, 251 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 01:00:00.000000000 +0100
9 +++ linux/include/linux/netfilter_ipv4/ipt_connlimit.h 2006-05-04 10:02:23.000000000 +0200
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/Kconfig linux/net/ipv4/netfilter/Kconfig
24 --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
25 +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 10:02:23.000000000 +0200
27 Allows altering the ARP packet payload: source and destination
28 hardware and network addresses.
30 +config IP_NF_MATCH_CONNLIMIT
31 + tristate 'Connections/IP limit match support'
32 + depends on IP_NF_IPTABLES
34 + This match allows you to restrict the number of parallel TCP
35 + connections to a server per client IP address (or address block).
37 + If you want to compile it as a module, say M here and read
38 + Documentation/modules.txt. If unsure, say `N'.
42 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
43 --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
44 +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 10:02:23.000000000 +0200
46 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
47 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_connlimit.c linux/net/ipv4/netfilter/ipt_connlimit.c
48 --- linux.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
49 +++ linux/net/ipv4/netfilter/ipt_connlimit.c 2006-05-04 10:02:23.000000000 +0200
52 + * netfilter module to limit the number of parallel tcp
53 + * connections per IP address.
54 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
55 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
56 + * only ignore TIME_WAIT or gone connections
60 + * Kernel module to match connection tracking information.
61 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
63 +#include <linux/module.h>
64 +#include <linux/skbuff.h>
65 +#include <linux/list.h>
66 +#include <linux/netfilter_ipv4/ip_conntrack.h>
67 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
68 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
69 +#include <linux/netfilter_ipv4/ip_tables.h>
70 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
74 +MODULE_LICENSE("GPL");
76 +/* we'll save the tuples of all connections we care about */
77 +struct ipt_connlimit_conn
79 + struct list_head list;
80 + struct ip_conntrack_tuple tuple;
83 +struct ipt_connlimit_data {
85 + struct list_head iphash[256];
88 +static inline unsigned ipt_iphash(const unsigned addr)
90 + return ((addr ^ (addr >> 8) ^ (addr >> 16) ^ (addr >> 24)) & 0xff);
93 +static int count_them(struct ipt_connlimit_data *data,
94 + u_int32_t addr, u_int32_t mask,
95 + struct ip_conntrack *ct)
98 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
99 + "fin_wait", "time_wait", "close", "close_wait",
100 + "last_ack", "listen" };
102 + int addit = 1, matches = 0;
103 + struct ip_conntrack_tuple tuple;
104 + struct ip_conntrack_tuple_hash *found;
105 + struct ipt_connlimit_conn *conn;
106 + struct list_head *hash,*lh;
108 + spin_lock_bh(&data->lock);
109 + tuple = ct->tuplehash[0].tuple;
110 + hash = &data->iphash[ipt_iphash(addr & mask)];
112 + /* check the saved connections */
113 + for (lh = hash->next; lh != hash; lh = lh->next) {
114 + struct ip_conntrack *found_ct = NULL;
115 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
116 + found = ip_conntrack_find_get(&conn->tuple,ct);
118 + && (found_ct = tuplehash_to_ctrack(found)) != NULL
119 + && 0 == memcmp(&conn->tuple,&tuple,sizeof(tuple))
120 + && found_ct->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
121 + /* Just to be sure we have it only once in the list.
122 + We should'nt see tuples twice unless someone hooks this
123 + into a table without "-p tcp --syn" */
127 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
128 + ipt_iphash(addr & mask),
129 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
130 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
131 + (NULL != found) ? tcp[found_ct->proto.tcp.state] : "gone");
133 + if (NULL == found) {
134 + /* this one is gone */
136 + list_del(lh->next);
140 + if (found_ct->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
141 + /* we don't care about connections which are
142 + closed already -> ditch it */
144 + list_del(lh->next);
146 + nf_conntrack_put(&found_ct->ct_general);
149 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
150 + /* same source IP address -> be counted! */
153 + nf_conntrack_put(&found_ct->ct_general);
156 + /* save the new connection in our list */
158 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
159 + ipt_iphash(addr & mask),
160 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
161 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
163 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
164 + if (NULL == conn) {
165 + spin_unlock_bh(&data->lock);
168 + memset(conn,0,sizeof(*conn));
169 + INIT_LIST_HEAD(&conn->list);
170 + conn->tuple = tuple;
171 + list_add(&conn->list,hash);
174 + spin_unlock_bh(&data->lock);
179 +match(const struct sk_buff *skb,
180 + const struct net_device *in,
181 + const struct net_device *out,
182 + const void *matchinfo,
184 + unsigned int protoff,
187 + const struct ipt_connlimit_info *info = matchinfo;
188 + int connections, match;
189 + struct ip_conntrack *ct;
190 + enum ip_conntrack_info ctinfo;
192 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
194 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
198 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
199 + if (-1 == connections) {
200 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
201 + *hotdrop = 1; /* let's free some memory :-) */
204 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
206 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
207 + "connections=%d limit=%d match=%s\n",
208 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
209 + connections, info->limit, match ? "yes" : "no");
215 +static int check(const char *tablename,
216 + const struct ipt_ip *ip,
218 + unsigned int matchsize,
219 + unsigned int hook_mask)
221 + struct ipt_connlimit_info *info = matchinfo;
225 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
228 + /* refuse anything but tcp */
229 + if (ip->proto != IPPROTO_TCP)
232 + /* init private data */
233 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
234 + spin_lock_init(&(info->data->lock));
235 + for (i = 0; i < 256; i++)
236 + INIT_LIST_HEAD(&(info->data->iphash[i]));
241 +static void destroy(void *matchinfo, unsigned int matchinfosize)
243 + struct ipt_connlimit_info *info = matchinfo;
244 + struct ipt_connlimit_conn *conn;
245 + struct list_head *hash;
249 + for (i = 0; i < 256; i++) {
250 + hash = &(info->data->iphash[i]);
251 + while (hash != hash->next) {
252 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
253 + list_del(hash->next);
260 +static struct ipt_match connlimit_match = {
261 + .name = "connlimit",
263 + .checkentry = &check,
264 + .destroy = &destroy,
268 +static int __init init(void)
270 + return ipt_register_match(&connlimit_match);
273 +static void __exit fini(void)
275 + ipt_unregister_match(&connlimit_match);