]>
Commit | Line | Data |
---|---|---|
370786f9 JE |
1 | /* |
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 | |
ba5dc275 | 7 | * (C) CC Computer Consultants GmbH, 2007 |
370786f9 JE |
8 | * |
9 | * based on ... | |
10 | * | |
11 | * Kernel module to match connection tracking information. | |
12 | * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). | |
13 | */ | |
8bee4bad | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
625c5561 | 15 | |
370786f9 | 16 | #include <linux/module.h> |
370786f9 | 17 | #include <linux/skbuff.h> |
370786f9 JE |
18 | #include <linux/netfilter/x_tables.h> |
19 | #include <linux/netfilter/xt_connlimit.h> | |
625c5561 | 20 | |
370786f9 JE |
21 | #include <net/netfilter/nf_conntrack.h> |
22 | #include <net/netfilter/nf_conntrack_core.h> | |
23 | #include <net/netfilter/nf_conntrack_tuple.h> | |
5d0aa2cc | 24 | #include <net/netfilter/nf_conntrack_zones.h> |
625c5561 | 25 | #include <net/netfilter/nf_conntrack_count.h> |
15cfd528 | 26 | |
d3c5ee6d | 27 | static bool |
62fc8051 | 28 | connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) |
370786f9 | 29 | { |
613dbd95 | 30 | struct net *net = xt_net(par); |
f7108a20 | 31 | const struct xt_connlimit_info *info = par->matchinfo; |
370786f9 JE |
32 | struct nf_conntrack_tuple tuple; |
33 | const struct nf_conntrack_tuple *tuple_ptr = &tuple; | |
308ac914 | 34 | const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; |
370786f9 JE |
35 | enum ip_conntrack_info ctinfo; |
36 | const struct nf_conn *ct; | |
7d084877 | 37 | unsigned int connections; |
625c5561 | 38 | u32 key[5]; |
370786f9 JE |
39 | |
40 | ct = nf_ct_get(skb, &ctinfo); | |
e59ea3df | 41 | if (ct != NULL) { |
8183e3a8 | 42 | tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
e59ea3df FW |
43 | zone = nf_ct_zone(ct); |
44 | } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), | |
613dbd95 | 45 | xt_family(par), net, &tuple)) { |
370786f9 | 46 | goto hotdrop; |
e59ea3df | 47 | } |
370786f9 | 48 | |
613dbd95 | 49 | if (xt_family(par) == NFPROTO_IPV6) { |
370786f9 | 50 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
625c5561 | 51 | union nf_inet_addr addr; |
b1fc1372 FW |
52 | unsigned int i; |
53 | ||
cc4fc022 JE |
54 | memcpy(&addr.ip6, (info->flags & XT_CONNLIMIT_DADDR) ? |
55 | &iph->daddr : &iph->saddr, sizeof(addr.ip6)); | |
b1fc1372 FW |
56 | |
57 | for (i = 0; i < ARRAY_SIZE(addr.ip6); ++i) | |
58 | addr.ip6[i] &= info->mask.ip6[i]; | |
625c5561 FW |
59 | memcpy(key, &addr, sizeof(addr.ip6)); |
60 | key[4] = zone->id; | |
370786f9 JE |
61 | } else { |
62 | const struct iphdr *iph = ip_hdr(skb); | |
625c5561 | 63 | key[0] = (info->flags & XT_CONNLIMIT_DADDR) ? |
cc4fc022 | 64 | iph->daddr : iph->saddr; |
b1fc1372 | 65 | |
625c5561 FW |
66 | key[0] &= info->mask.ip; |
67 | key[1] = zone->id; | |
370786f9 JE |
68 | } |
69 | ||
6aec2087 YHW |
70 | connections = nf_conncount_count(net, info->data, key, tuple_ptr, |
71 | zone); | |
7d084877 | 72 | if (connections == 0) |
370786f9 | 73 | /* kmalloc failed, drop it entirely */ |
1cc34c30 | 74 | goto hotdrop; |
370786f9 | 75 | |
625c5561 | 76 | return (connections > info->limit) ^ !!(info->flags & XT_CONNLIMIT_INVERT); |
370786f9 JE |
77 | |
78 | hotdrop: | |
b4ba2611 | 79 | par->hotdrop = true; |
370786f9 JE |
80 | return false; |
81 | } | |
82 | ||
b0f38452 | 83 | static int connlimit_mt_check(const struct xt_mtchk_param *par) |
370786f9 | 84 | { |
9b4fce7a | 85 | struct xt_connlimit_info *info = par->matchinfo; |
625c5561 | 86 | unsigned int keylen; |
370786f9 | 87 | |
625c5561 FW |
88 | keylen = sizeof(u32); |
89 | if (par->family == NFPROTO_IPV6) | |
90 | keylen += sizeof(struct in6_addr); | |
91 | else | |
92 | keylen += sizeof(struct in_addr); | |
370786f9 JE |
93 | |
94 | /* init private data */ | |
625c5561 | 95 | info->data = nf_conncount_init(par->net, par->family, keylen); |
370786f9 | 96 | |
33b78aaa | 97 | return PTR_ERR_OR_ZERO(info->data); |
370786f9 JE |
98 | } |
99 | ||
7d084877 FW |
100 | static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) |
101 | { | |
102 | const struct xt_connlimit_info *info = par->matchinfo; | |
370786f9 | 103 | |
625c5561 | 104 | nf_conncount_destroy(par->net, par->family, info->data); |
370786f9 JE |
105 | } |
106 | ||
68c07cb6 CW |
107 | static struct xt_match connlimit_mt_reg __read_mostly = { |
108 | .name = "connlimit", | |
109 | .revision = 1, | |
110 | .family = NFPROTO_UNSPEC, | |
111 | .checkentry = connlimit_mt_check, | |
112 | .match = connlimit_mt, | |
113 | .matchsize = sizeof(struct xt_connlimit_info), | |
ec231890 | 114 | .usersize = offsetof(struct xt_connlimit_info, data), |
68c07cb6 CW |
115 | .destroy = connlimit_mt_destroy, |
116 | .me = THIS_MODULE, | |
370786f9 JE |
117 | }; |
118 | ||
d3c5ee6d | 119 | static int __init connlimit_mt_init(void) |
370786f9 | 120 | { |
625c5561 | 121 | return xt_register_match(&connlimit_mt_reg); |
370786f9 JE |
122 | } |
123 | ||
d3c5ee6d | 124 | static void __exit connlimit_mt_exit(void) |
370786f9 | 125 | { |
68c07cb6 | 126 | xt_unregister_match(&connlimit_mt_reg); |
370786f9 JE |
127 | } |
128 | ||
d3c5ee6d JE |
129 | module_init(connlimit_mt_init); |
130 | module_exit(connlimit_mt_exit); | |
92f3b2b1 | 131 | MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); |
2ae15b64 | 132 | MODULE_DESCRIPTION("Xtables: Number of connections matching"); |
370786f9 JE |
133 | MODULE_LICENSE("GPL"); |
134 | MODULE_ALIAS("ipt_connlimit"); | |
135 | MODULE_ALIAS("ip6t_connlimit"); |