2 * netfilter module to limit the number of parallel tcp
3 * connections per IP address.
4 * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
5 * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
6 * only ignore TIME_WAIT or gone connections
10 * Kernel module to match connection tracking information.
11 * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <linux/list.h>
16 #include <linux/version.h>
17 #include <linux/netfilter_ipv4/ip_conntrack.h>
18 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
19 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
20 #include <linux/netfilter_ipv4/ip_tables.h>
21 #include <linux/netfilter_ipv4/ipt_connlimit.h>
25 MODULE_LICENSE("GPL");
27 /* we'll save the tuples of all connections we care about */
28 struct ipt_connlimit_conn
30 struct list_head list
;
31 struct ip_conntrack_tuple tuple
;
34 struct ipt_connlimit_data
{
36 struct list_head iphash
[256];
39 static inline unsigned ipt_iphash(const unsigned addr
)
41 return ((addr
^ (addr
>> 8) ^ (addr
>> 16) ^ (addr
>> 24)) & 0xff);
44 static int count_them(struct ipt_connlimit_data
*data
,
45 u_int32_t addr
, u_int32_t mask
,
46 struct ip_conntrack
*ct
)
49 const static char *tcp
[] = { "none", "established", "syn_sent", "syn_recv",
50 "fin_wait", "time_wait", "close", "close_wait",
51 "last_ack", "listen" };
53 int addit
= 1, matches
= 0;
54 struct ip_conntrack_tuple tuple
;
55 struct ip_conntrack_tuple_hash
*found
;
56 struct ipt_connlimit_conn
*conn
;
57 struct list_head
*hash
,*lh
;
59 spin_lock_bh(&data
->lock
);
60 tuple
= ct
->tuplehash
[0].tuple
;
61 hash
= &data
->iphash
[ipt_iphash(addr
& mask
)];
63 /* check the saved connections */
64 for (lh
= hash
->next
; lh
!= hash
; lh
= lh
->next
) {
65 conn
= list_entry(lh
,struct ipt_connlimit_conn
,list
);
66 found
= ip_conntrack_find_get(&conn
->tuple
,ct
);
68 0 == memcmp(&conn
->tuple
,&tuple
,sizeof(tuple
)) &&
69 found
->ctrack
->proto
.tcp
.state
!= TCP_CONNTRACK_TIME_WAIT
) {
70 /* Just to be sure we have it only once in the list.
71 We should'nt see tuples twice unless someone hooks this
72 into a table without "-p tcp --syn" */
76 printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
77 ipt_iphash(addr
& mask
),
78 NIPQUAD(conn
->tuple
.src
.ip
), ntohs(conn
->tuple
.src
.u
.tcp
.port
),
79 NIPQUAD(conn
->tuple
.dst
.ip
), ntohs(conn
->tuple
.dst
.u
.tcp
.port
),
80 (NULL
!= found
) ? tcp
[found
->ctrack
->proto
.tcp
.state
] : "gone");
83 /* this one is gone */
89 if (found
->ctrack
->proto
.tcp
.state
== TCP_CONNTRACK_TIME_WAIT
) {
90 /* we don't care about connections which are
91 closed already -> ditch it */
95 nf_conntrack_put(&found
->ctrack
->infos
[0]);
98 if ((addr
& mask
) == (conn
->tuple
.src
.ip
& mask
)) {
99 /* same source IP address -> be counted! */
102 nf_conntrack_put(&found
->ctrack
->infos
[0]);
105 /* save the new connection in our list */
107 printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
108 ipt_iphash(addr
& mask
),
109 NIPQUAD(tuple
.src
.ip
), ntohs(tuple
.src
.u
.tcp
.port
),
110 NIPQUAD(tuple
.dst
.ip
), ntohs(tuple
.dst
.u
.tcp
.port
));
112 conn
= kmalloc(sizeof(*conn
),GFP_ATOMIC
);
115 memset(conn
,0,sizeof(*conn
));
116 INIT_LIST_HEAD(&conn
->list
);
118 list_add(&conn
->list
,hash
);
121 spin_unlock_bh(&data
->lock
);
126 match(const struct sk_buff
*skb
,
127 const struct net_device
*in
,
128 const struct net_device
*out
,
129 const void *matchinfo
,
135 const struct ipt_connlimit_info
*info
= matchinfo
;
136 int connections
, match
;
137 struct ip_conntrack
*ct
;
138 enum ip_conntrack_info ctinfo
;
140 ct
= ip_conntrack_get((struct sk_buff
*)skb
, &ctinfo
);
142 printk("ipt_connlimit: Oops: invalid ct state ?\n");
146 connections
= count_them(info
->data
,skb
->nh
.iph
->saddr
,info
->mask
,ct
);
147 if (-1 == connections
) {
148 printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
149 *hotdrop
= 1; /* let's free some memory :-) */
152 match
= (info
->inverse
) ? (connections
<= info
->limit
) : (connections
> info
->limit
);
154 printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
155 "connections=%d limit=%d match=%s\n",
156 NIPQUAD(skb
->nh
.iph
->saddr
), NIPQUAD(info
->mask
),
157 connections
, info
->limit
, match
? "yes" : "no");
163 static int check(const char *tablename
,
164 const struct ipt_ip
*ip
,
166 unsigned int matchsize
,
167 unsigned int hook_mask
)
169 struct ipt_connlimit_info
*info
= matchinfo
;
173 if (matchsize
!= IPT_ALIGN(sizeof(struct ipt_connlimit_info
)))
176 /* refuse anything but tcp */
177 if (ip
->proto
!= IPPROTO_TCP
)
180 /* init private data */
181 info
->data
= kmalloc(sizeof(struct ipt_connlimit_data
),GFP_KERNEL
);
182 spin_lock_init(&(info
->data
->lock
));
183 for (i
= 0; i
< 256; i
++)
184 INIT_LIST_HEAD(&(info
->data
->iphash
[i
]));
189 static void destroy(void *matchinfo
, unsigned int matchinfosize
)
191 struct ipt_connlimit_info
*info
= matchinfo
;
192 struct ipt_connlimit_conn
*conn
;
193 struct list_head
*hash
;
197 for (i
= 0; i
< 256; i
++) {
198 hash
= &(info
->data
->iphash
[i
]);
199 while (hash
!= hash
->next
) {
200 conn
= list_entry(hash
->next
,struct ipt_connlimit_conn
,list
);
201 list_del(hash
->next
);
208 static struct ipt_match connlimit_match
209 = { { NULL
, NULL
}, "connlimit", &match
, &check
, &destroy
, THIS_MODULE
};
211 static int __init
init(void)
213 return ipt_register_match(&connlimit_match
);
216 static void __exit
fini(void)
218 ipt_unregister_match(&connlimit_match
);