Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15-rc3 458 lines 12 kB view raw
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 7 * (C) CC Computer Consultants GmbH, 2007 8 * 9 * based on ... 10 * 11 * Kernel module to match connection tracking information. 12 * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). 13 */ 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15#include <linux/in.h> 16#include <linux/in6.h> 17#include <linux/ip.h> 18#include <linux/ipv6.h> 19#include <linux/jhash.h> 20#include <linux/slab.h> 21#include <linux/list.h> 22#include <linux/rbtree.h> 23#include <linux/module.h> 24#include <linux/random.h> 25#include <linux/skbuff.h> 26#include <linux/spinlock.h> 27#include <linux/netfilter/nf_conntrack_tcp.h> 28#include <linux/netfilter/x_tables.h> 29#include <linux/netfilter/xt_connlimit.h> 30#include <net/netfilter/nf_conntrack.h> 31#include <net/netfilter/nf_conntrack_core.h> 32#include <net/netfilter/nf_conntrack_tuple.h> 33#include <net/netfilter/nf_conntrack_zones.h> 34 35#define CONNLIMIT_SLOTS 256U 36 37#ifdef CONFIG_LOCKDEP 38#define CONNLIMIT_LOCK_SLOTS 8U 39#else 40#define CONNLIMIT_LOCK_SLOTS 256U 41#endif 42 43#define CONNLIMIT_GC_MAX_NODES 8 44 45/* we will save the tuples of all connections we care about */ 46struct xt_connlimit_conn { 47 struct hlist_node node; 48 struct nf_conntrack_tuple tuple; 49}; 50 51struct xt_connlimit_rb { 52 struct rb_node node; 53 struct hlist_head hhead; /* connections/hosts in same subnet */ 54 union nf_inet_addr addr; /* search key */ 55}; 56 57static spinlock_t xt_connlimit_locks[CONNLIMIT_LOCK_SLOTS] __cacheline_aligned_in_smp; 58 59struct xt_connlimit_data { 60 struct rb_root climit_root[CONNLIMIT_SLOTS]; 61}; 62 63static u_int32_t connlimit_rnd __read_mostly; 64static struct kmem_cache *connlimit_rb_cachep __read_mostly; 65static struct kmem_cache *connlimit_conn_cachep __read_mostly; 66 67static inline unsigned int connlimit_iphash(__be32 addr) 68{ 69 return jhash_1word((__force __u32)addr, 70 connlimit_rnd) % CONNLIMIT_SLOTS; 71} 72 73static inline unsigned int 74connlimit_iphash6(const union nf_inet_addr *addr) 75{ 76 return jhash2((u32 *)addr->ip6, ARRAY_SIZE(addr->ip6), 77 connlimit_rnd) % CONNLIMIT_SLOTS; 78} 79 80static inline bool already_closed(const struct nf_conn *conn) 81{ 82 if (nf_ct_protonum(conn) == IPPROTO_TCP) 83 return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT || 84 conn->proto.tcp.state == TCP_CONNTRACK_CLOSE; 85 else 86 return 0; 87} 88 89static int 90same_source(const union nf_inet_addr *addr, 91 const union nf_inet_addr *u3, u_int8_t family) 92{ 93 if (family == NFPROTO_IPV4) 94 return ntohl(addr->ip) - ntohl(u3->ip); 95 96 return memcmp(addr->ip6, u3->ip6, sizeof(addr->ip6)); 97} 98 99static bool add_hlist(struct hlist_head *head, 100 const struct nf_conntrack_tuple *tuple, 101 const union nf_inet_addr *addr) 102{ 103 struct xt_connlimit_conn *conn; 104 105 conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC); 106 if (conn == NULL) 107 return false; 108 conn->tuple = *tuple; 109 hlist_add_head(&conn->node, head); 110 return true; 111} 112 113static unsigned int check_hlist(struct net *net, 114 struct hlist_head *head, 115 const struct nf_conntrack_tuple *tuple, 116 const struct nf_conntrack_zone *zone, 117 bool *addit) 118{ 119 const struct nf_conntrack_tuple_hash *found; 120 struct xt_connlimit_conn *conn; 121 struct hlist_node *n; 122 struct nf_conn *found_ct; 123 unsigned int length = 0; 124 125 *addit = true; 126 127 /* check the saved connections */ 128 hlist_for_each_entry_safe(conn, n, head, node) { 129 found = nf_conntrack_find_get(net, zone, &conn->tuple); 130 if (found == NULL) { 131 hlist_del(&conn->node); 132 kmem_cache_free(connlimit_conn_cachep, conn); 133 continue; 134 } 135 136 found_ct = nf_ct_tuplehash_to_ctrack(found); 137 138 if (nf_ct_tuple_equal(&conn->tuple, tuple)) { 139 /* 140 * Just to be sure we have it only once in the list. 141 * We should not see tuples twice unless someone hooks 142 * this into a table without "-p tcp --syn". 143 */ 144 *addit = false; 145 } else if (already_closed(found_ct)) { 146 /* 147 * we do not care about connections which are 148 * closed already -> ditch it 149 */ 150 nf_ct_put(found_ct); 151 hlist_del(&conn->node); 152 kmem_cache_free(connlimit_conn_cachep, conn); 153 continue; 154 } 155 156 nf_ct_put(found_ct); 157 length++; 158 } 159 160 return length; 161} 162 163static void tree_nodes_free(struct rb_root *root, 164 struct xt_connlimit_rb *gc_nodes[], 165 unsigned int gc_count) 166{ 167 struct xt_connlimit_rb *rbconn; 168 169 while (gc_count) { 170 rbconn = gc_nodes[--gc_count]; 171 rb_erase(&rbconn->node, root); 172 kmem_cache_free(connlimit_rb_cachep, rbconn); 173 } 174} 175 176static unsigned int 177count_tree(struct net *net, struct rb_root *root, 178 const struct nf_conntrack_tuple *tuple, 179 const union nf_inet_addr *addr, 180 u8 family, const struct nf_conntrack_zone *zone) 181{ 182 struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES]; 183 struct rb_node **rbnode, *parent; 184 struct xt_connlimit_rb *rbconn; 185 struct xt_connlimit_conn *conn; 186 unsigned int gc_count; 187 bool no_gc = false; 188 189 restart: 190 gc_count = 0; 191 parent = NULL; 192 rbnode = &(root->rb_node); 193 while (*rbnode) { 194 int diff; 195 bool addit; 196 197 rbconn = rb_entry(*rbnode, struct xt_connlimit_rb, node); 198 199 parent = *rbnode; 200 diff = same_source(addr, &rbconn->addr, family); 201 if (diff < 0) { 202 rbnode = &((*rbnode)->rb_left); 203 } else if (diff > 0) { 204 rbnode = &((*rbnode)->rb_right); 205 } else { 206 /* same source network -> be counted! */ 207 unsigned int count; 208 count = check_hlist(net, &rbconn->hhead, tuple, zone, &addit); 209 210 tree_nodes_free(root, gc_nodes, gc_count); 211 if (!addit) 212 return count; 213 214 if (!add_hlist(&rbconn->hhead, tuple, addr)) 215 return 0; /* hotdrop */ 216 217 return count + 1; 218 } 219 220 if (no_gc || gc_count >= ARRAY_SIZE(gc_nodes)) 221 continue; 222 223 /* only used for GC on hhead, retval and 'addit' ignored */ 224 check_hlist(net, &rbconn->hhead, tuple, zone, &addit); 225 if (hlist_empty(&rbconn->hhead)) 226 gc_nodes[gc_count++] = rbconn; 227 } 228 229 if (gc_count) { 230 no_gc = true; 231 tree_nodes_free(root, gc_nodes, gc_count); 232 /* tree_node_free before new allocation permits 233 * allocator to re-use newly free'd object. 234 * 235 * This is a rare event; in most cases we will find 236 * existing node to re-use. (or gc_count is 0). 237 */ 238 goto restart; 239 } 240 241 /* no match, need to insert new node */ 242 rbconn = kmem_cache_alloc(connlimit_rb_cachep, GFP_ATOMIC); 243 if (rbconn == NULL) 244 return 0; 245 246 conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC); 247 if (conn == NULL) { 248 kmem_cache_free(connlimit_rb_cachep, rbconn); 249 return 0; 250 } 251 252 conn->tuple = *tuple; 253 rbconn->addr = *addr; 254 255 INIT_HLIST_HEAD(&rbconn->hhead); 256 hlist_add_head(&conn->node, &rbconn->hhead); 257 258 rb_link_node(&rbconn->node, parent, rbnode); 259 rb_insert_color(&rbconn->node, root); 260 return 1; 261} 262 263static int count_them(struct net *net, 264 struct xt_connlimit_data *data, 265 const struct nf_conntrack_tuple *tuple, 266 const union nf_inet_addr *addr, 267 u_int8_t family, 268 const struct nf_conntrack_zone *zone) 269{ 270 struct rb_root *root; 271 int count; 272 u32 hash; 273 274 if (family == NFPROTO_IPV6) 275 hash = connlimit_iphash6(addr); 276 else 277 hash = connlimit_iphash(addr->ip); 278 root = &data->climit_root[hash]; 279 280 spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); 281 282 count = count_tree(net, root, tuple, addr, family, zone); 283 284 spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]); 285 286 return count; 287} 288 289static bool 290connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) 291{ 292 struct net *net = xt_net(par); 293 const struct xt_connlimit_info *info = par->matchinfo; 294 union nf_inet_addr addr; 295 struct nf_conntrack_tuple tuple; 296 const struct nf_conntrack_tuple *tuple_ptr = &tuple; 297 const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; 298 enum ip_conntrack_info ctinfo; 299 const struct nf_conn *ct; 300 unsigned int connections; 301 302 ct = nf_ct_get(skb, &ctinfo); 303 if (ct != NULL) { 304 tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 305 zone = nf_ct_zone(ct); 306 } else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), 307 xt_family(par), net, &tuple)) { 308 goto hotdrop; 309 } 310 311 if (xt_family(par) == NFPROTO_IPV6) { 312 const struct ipv6hdr *iph = ipv6_hdr(skb); 313 unsigned int i; 314 315 memcpy(&addr.ip6, (info->flags & XT_CONNLIMIT_DADDR) ? 316 &iph->daddr : &iph->saddr, sizeof(addr.ip6)); 317 318 for (i = 0; i < ARRAY_SIZE(addr.ip6); ++i) 319 addr.ip6[i] &= info->mask.ip6[i]; 320 } else { 321 const struct iphdr *iph = ip_hdr(skb); 322 addr.ip = (info->flags & XT_CONNLIMIT_DADDR) ? 323 iph->daddr : iph->saddr; 324 325 addr.ip &= info->mask.ip; 326 } 327 328 connections = count_them(net, info->data, tuple_ptr, &addr, 329 xt_family(par), zone); 330 if (connections == 0) 331 /* kmalloc failed, drop it entirely */ 332 goto hotdrop; 333 334 return (connections > info->limit) ^ 335 !!(info->flags & XT_CONNLIMIT_INVERT); 336 337 hotdrop: 338 par->hotdrop = true; 339 return false; 340} 341 342static int connlimit_mt_check(const struct xt_mtchk_param *par) 343{ 344 struct xt_connlimit_info *info = par->matchinfo; 345 unsigned int i; 346 int ret; 347 348 net_get_random_once(&connlimit_rnd, sizeof(connlimit_rnd)); 349 350 ret = nf_ct_netns_get(par->net, par->family); 351 if (ret < 0) { 352 pr_info("cannot load conntrack support for " 353 "address family %u\n", par->family); 354 return ret; 355 } 356 357 /* init private data */ 358 info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL); 359 if (info->data == NULL) { 360 nf_ct_netns_put(par->net, par->family); 361 return -ENOMEM; 362 } 363 364 for (i = 0; i < ARRAY_SIZE(info->data->climit_root); ++i) 365 info->data->climit_root[i] = RB_ROOT; 366 367 return 0; 368} 369 370static void destroy_tree(struct rb_root *r) 371{ 372 struct xt_connlimit_conn *conn; 373 struct xt_connlimit_rb *rbconn; 374 struct hlist_node *n; 375 struct rb_node *node; 376 377 while ((node = rb_first(r)) != NULL) { 378 rbconn = rb_entry(node, struct xt_connlimit_rb, node); 379 380 rb_erase(node, r); 381 382 hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node) 383 kmem_cache_free(connlimit_conn_cachep, conn); 384 385 kmem_cache_free(connlimit_rb_cachep, rbconn); 386 } 387} 388 389static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) 390{ 391 const struct xt_connlimit_info *info = par->matchinfo; 392 unsigned int i; 393 394 nf_ct_netns_put(par->net, par->family); 395 396 for (i = 0; i < ARRAY_SIZE(info->data->climit_root); ++i) 397 destroy_tree(&info->data->climit_root[i]); 398 399 kfree(info->data); 400} 401 402static struct xt_match connlimit_mt_reg __read_mostly = { 403 .name = "connlimit", 404 .revision = 1, 405 .family = NFPROTO_UNSPEC, 406 .checkentry = connlimit_mt_check, 407 .match = connlimit_mt, 408 .matchsize = sizeof(struct xt_connlimit_info), 409 .usersize = offsetof(struct xt_connlimit_info, data), 410 .destroy = connlimit_mt_destroy, 411 .me = THIS_MODULE, 412}; 413 414static int __init connlimit_mt_init(void) 415{ 416 int ret, i; 417 418 BUILD_BUG_ON(CONNLIMIT_LOCK_SLOTS > CONNLIMIT_SLOTS); 419 BUILD_BUG_ON((CONNLIMIT_SLOTS % CONNLIMIT_LOCK_SLOTS) != 0); 420 421 for (i = 0; i < CONNLIMIT_LOCK_SLOTS; ++i) 422 spin_lock_init(&xt_connlimit_locks[i]); 423 424 connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn", 425 sizeof(struct xt_connlimit_conn), 426 0, 0, NULL); 427 if (!connlimit_conn_cachep) 428 return -ENOMEM; 429 430 connlimit_rb_cachep = kmem_cache_create("xt_connlimit_rb", 431 sizeof(struct xt_connlimit_rb), 432 0, 0, NULL); 433 if (!connlimit_rb_cachep) { 434 kmem_cache_destroy(connlimit_conn_cachep); 435 return -ENOMEM; 436 } 437 ret = xt_register_match(&connlimit_mt_reg); 438 if (ret != 0) { 439 kmem_cache_destroy(connlimit_conn_cachep); 440 kmem_cache_destroy(connlimit_rb_cachep); 441 } 442 return ret; 443} 444 445static void __exit connlimit_mt_exit(void) 446{ 447 xt_unregister_match(&connlimit_mt_reg); 448 kmem_cache_destroy(connlimit_conn_cachep); 449 kmem_cache_destroy(connlimit_rb_cachep); 450} 451 452module_init(connlimit_mt_init); 453module_exit(connlimit_mt_exit); 454MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 455MODULE_DESCRIPTION("Xtables: Number of connections matching"); 456MODULE_LICENSE("GPL"); 457MODULE_ALIAS("ipt_connlimit"); 458MODULE_ALIAS("ip6t_connlimit");