Blame view
net/netfilter/xt_connlimit.c
3.73 KB
370786f9c
|
1 2 3 4 5 6 |
/* * netfilter module to limit the number of parallel tcp * connections per IP address. * (c) 2000 Gerd Knorr <kraxel@bytesex.org> * Nov 2002: Martin Bene <martin.bene@icomedias.com>: * only ignore TIME_WAIT or gone connections |
ba5dc2756
|
7 |
* (C) CC Computer Consultants GmbH, 2007 |
370786f9c
|
8 9 10 11 12 13 |
* * based on ... * * Kernel module to match connection tracking information. * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). */ |
8bee4bad0
|
14 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
625c55611
|
15 |
|
40d102cde
|
16 17 |
#include <linux/ip.h> #include <linux/ipv6.h> |
370786f9c
|
18 |
#include <linux/module.h> |
370786f9c
|
19 |
#include <linux/skbuff.h> |
370786f9c
|
20 21 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_connlimit.h> |
625c55611
|
22 |
|
370786f9c
|
23 24 25 |
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_tuple.h> |
5d0aa2ccd
|
26 |
#include <net/netfilter/nf_conntrack_zones.h> |
625c55611
|
27 |
#include <net/netfilter/nf_conntrack_count.h> |
15cfd5289
|
28 |
|
d3c5ee6d5
|
29 |
static bool |
62fc80510
|
30 |
connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) |
370786f9c
|
31 |
{ |
613dbd957
|
32 |
struct net *net = xt_net(par); |
f7108a20d
|
33 |
const struct xt_connlimit_info *info = par->matchinfo; |
370786f9c
|
34 35 |
struct nf_conntrack_tuple tuple; const struct nf_conntrack_tuple *tuple_ptr = &tuple; |
308ac9143
|
36 |
const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; |
370786f9c
|
37 38 |
enum ip_conntrack_info ctinfo; const struct nf_conn *ct; |
7d0848777
|
39 |
unsigned int connections; |
625c55611
|
40 |
u32 key[5]; |
370786f9c
|
41 42 |
ct = nf_ct_get(skb, &ctinfo); |
e59ea3df3
|
43 |
if (ct != NULL) { |
8183e3a88
|
44 |
tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
e59ea3df3
|
45 46 |
zone = nf_ct_zone(ct); } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), |
613dbd957
|
47 |
xt_family(par), net, &tuple)) { |
370786f9c
|
48 |
goto hotdrop; |
e59ea3df3
|
49 |
} |
370786f9c
|
50 |
|
613dbd957
|
51 |
if (xt_family(par) == NFPROTO_IPV6) { |
370786f9c
|
52 |
const struct ipv6hdr *iph = ipv6_hdr(skb); |
625c55611
|
53 |
union nf_inet_addr addr; |
b1fc1372c
|
54 |
unsigned int i; |
cc4fc0225
|
55 56 |
memcpy(&addr.ip6, (info->flags & XT_CONNLIMIT_DADDR) ? &iph->daddr : &iph->saddr, sizeof(addr.ip6)); |
b1fc1372c
|
57 58 59 |
for (i = 0; i < ARRAY_SIZE(addr.ip6); ++i) addr.ip6[i] &= info->mask.ip6[i]; |
625c55611
|
60 61 |
memcpy(key, &addr, sizeof(addr.ip6)); key[4] = zone->id; |
370786f9c
|
62 63 |
} else { const struct iphdr *iph = ip_hdr(skb); |
625c55611
|
64 |
key[0] = (info->flags & XT_CONNLIMIT_DADDR) ? |
cc4fc0225
|
65 |
iph->daddr : iph->saddr; |
b1fc1372c
|
66 |
|
625c55611
|
67 68 |
key[0] &= info->mask.ip; key[1] = zone->id; |
370786f9c
|
69 |
} |
6aec20878
|
70 71 |
connections = nf_conncount_count(net, info->data, key, tuple_ptr, zone); |
7d0848777
|
72 |
if (connections == 0) |
370786f9c
|
73 |
/* kmalloc failed, drop it entirely */ |
1cc34c30b
|
74 |
goto hotdrop; |
370786f9c
|
75 |
|
625c55611
|
76 |
return (connections > info->limit) ^ !!(info->flags & XT_CONNLIMIT_INVERT); |
370786f9c
|
77 78 |
hotdrop: |
b4ba26119
|
79 |
par->hotdrop = true; |
370786f9c
|
80 81 |
return false; } |
b0f38452f
|
82 |
static int connlimit_mt_check(const struct xt_mtchk_param *par) |
370786f9c
|
83 |
{ |
9b4fce7a3
|
84 |
struct xt_connlimit_info *info = par->matchinfo; |
625c55611
|
85 |
unsigned int keylen; |
370786f9c
|
86 |
|
625c55611
|
87 88 89 90 91 |
keylen = sizeof(u32); if (par->family == NFPROTO_IPV6) keylen += sizeof(struct in6_addr); else keylen += sizeof(struct in_addr); |
370786f9c
|
92 93 |
/* init private data */ |
625c55611
|
94 |
info->data = nf_conncount_init(par->net, par->family, keylen); |
370786f9c
|
95 |
|
33b78aaa4
|
96 |
return PTR_ERR_OR_ZERO(info->data); |
370786f9c
|
97 |
} |
7d0848777
|
98 99 100 |
static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) { const struct xt_connlimit_info *info = par->matchinfo; |
370786f9c
|
101 |
|
625c55611
|
102 |
nf_conncount_destroy(par->net, par->family, info->data); |
370786f9c
|
103 |
} |
68c07cb6d
|
104 105 106 107 108 109 110 |
static struct xt_match connlimit_mt_reg __read_mostly = { .name = "connlimit", .revision = 1, .family = NFPROTO_UNSPEC, .checkentry = connlimit_mt_check, .match = connlimit_mt, .matchsize = sizeof(struct xt_connlimit_info), |
ec2318904
|
111 |
.usersize = offsetof(struct xt_connlimit_info, data), |
68c07cb6d
|
112 113 |
.destroy = connlimit_mt_destroy, .me = THIS_MODULE, |
370786f9c
|
114 |
}; |
d3c5ee6d5
|
115 |
static int __init connlimit_mt_init(void) |
370786f9c
|
116 |
{ |
625c55611
|
117 |
return xt_register_match(&connlimit_mt_reg); |
370786f9c
|
118 |
} |
d3c5ee6d5
|
119 |
static void __exit connlimit_mt_exit(void) |
370786f9c
|
120 |
{ |
68c07cb6d
|
121 |
xt_unregister_match(&connlimit_mt_reg); |
370786f9c
|
122 |
} |
d3c5ee6d5
|
123 124 |
module_init(connlimit_mt_init); module_exit(connlimit_mt_exit); |
92f3b2b1b
|
125 |
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); |
2ae15b64e
|
126 |
MODULE_DESCRIPTION("Xtables: Number of connections matching"); |
370786f9c
|
127 128 129 |
MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_connlimit"); MODULE_ALIAS("ip6t_connlimit"); |