14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/in6.h>
18 #include <linux/ipv6.h>
20 #include <linux/slab.h>
21 #include <linux/list.h>
22 #include <linux/module.h>
23 #include <linux/random.h>
26 #include <linux/netfilter/nf_conntrack_tcp.h>
27 #include <linux/netfilter/x_tables.h>
48 static inline unsigned int connlimit_iphash(
__be32 addr)
50 return jhash_1word((
__force __u32)addr, connlimit_rnd) & 0xFF;
53 static inline unsigned int
66 static inline bool already_closed(
const struct nf_conn *conn)
75 static inline unsigned int
81 return (addr->
ip & mask->
ip) == (u3->
ip & mask->
ip);
91 return memcmp(&lh.ip6, &rh.ip6,
sizeof(lh.ip6)) == 0;
95 static int count_them(
struct net *
net,
111 hash = &data->
iphash[connlimit_iphash6(addr, mask)];
113 hash = &data->
iphash[connlimit_iphash(addr->
ip & mask->
ip)];
124 found_ct = nf_ct_tuplehash_to_ctrack(found);
126 if (found_ct !=
NULL &&
127 nf_ct_tuple_equal(&conn->
tuple, tuple) &&
128 !already_closed(found_ct))
138 hlist_del(&conn->
node);
143 if (already_closed(found_ct)) {
149 hlist_del(&conn->
node);
154 if (same_source_net(addr, mask, &conn->
addr, family))
167 conn->
tuple = *tuple;
169 hlist_add_head(&conn->
node, hash);
179 struct net *net = dev_net(par->
in ? par->
in : par->
out);
188 ct = nf_ct_get(skb, &ctinfo);
196 const struct ipv6hdr *iph = ipv6_hdr(skb);
200 const struct iphdr *iph = ip_hdr(skb);
205 spin_lock_bh(&info->data->lock);
206 connections = count_them(net, info->data, tuple_ptr, &addr,
208 spin_unlock_bh(&info->data->lock);
214 return (connections > info->
limit) ^
234 cmpxchg(&connlimit_rnd, 0, rand);
238 pr_info(
"cannot load conntrack support for "
239 "address family %u\n", par->
family);
245 if (info->data ==
NULL) {
251 for (i = 0; i <
ARRAY_SIZE(info->data->iphash); ++
i)
267 for (i = 0; i <
ARRAY_SIZE(info->data->iphash); ++
i) {
269 hlist_del(&conn->
node);
281 .checkentry = connlimit_mt_check,
282 .match = connlimit_mt,
284 .
destroy = connlimit_mt_destroy,
288 static int __init connlimit_mt_init(
void)
293 static void __exit connlimit_mt_exit(
void)