]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.1-NF-connlimit-20040107.patch
- obsolete (new driver name sym53c8xx_2 doesn't conflict now)
[packages/kernel.git] / 2.6.1-NF-connlimit-20040107.patch
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
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 -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  
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
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  
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
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 0.045925 seconds and 3 git commands to generate.