Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.12-rc3 440 lines 11 kB view raw
1/* 2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 3 * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation (or any later at your option). 8 */ 9#include <linux/init.h> 10#include <linux/module.h> 11#include <linux/kernel.h> 12#include <linux/rculist.h> 13#include <linux/rculist_nulls.h> 14#include <linux/types.h> 15#include <linux/timer.h> 16#include <linux/security.h> 17#include <linux/skbuff.h> 18#include <linux/errno.h> 19#include <linux/netlink.h> 20#include <linux/spinlock.h> 21#include <linux/interrupt.h> 22#include <linux/slab.h> 23 24#include <linux/netfilter.h> 25#include <net/netlink.h> 26#include <net/sock.h> 27#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_l3proto.h> 30#include <net/netfilter/nf_conntrack_l4proto.h> 31#include <net/netfilter/nf_conntrack_tuple.h> 32#include <net/netfilter/nf_conntrack_timeout.h> 33 34#include <linux/netfilter/nfnetlink.h> 35#include <linux/netfilter/nfnetlink_cttimeout.h> 36 37MODULE_LICENSE("GPL"); 38MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 39MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); 40 41static LIST_HEAD(cttimeout_list); 42 43static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { 44 [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING, 45 .len = CTNL_TIMEOUT_NAME_MAX - 1}, 46 [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, 47 [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, 48 [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, 49}; 50 51static int 52ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, 53 struct nf_conntrack_l4proto *l4proto, 54 struct net *net, 55 const struct nlattr *attr) 56{ 57 int ret = 0; 58 59 if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { 60 struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; 61 62 ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, 63 attr, l4proto->ctnl_timeout.nla_policy); 64 if (ret < 0) 65 return ret; 66 67 ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, 68 &timeout->data); 69 } 70 return ret; 71} 72 73static int 74cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, 75 const struct nlmsghdr *nlh, 76 const struct nlattr * const cda[]) 77{ 78 __u16 l3num; 79 __u8 l4num; 80 struct nf_conntrack_l4proto *l4proto; 81 struct ctnl_timeout *timeout, *matching = NULL; 82 struct net *net = sock_net(skb->sk); 83 char *name; 84 int ret; 85 86 if (!cda[CTA_TIMEOUT_NAME] || 87 !cda[CTA_TIMEOUT_L3PROTO] || 88 !cda[CTA_TIMEOUT_L4PROTO] || 89 !cda[CTA_TIMEOUT_DATA]) 90 return -EINVAL; 91 92 name = nla_data(cda[CTA_TIMEOUT_NAME]); 93 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); 94 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); 95 96 list_for_each_entry(timeout, &cttimeout_list, head) { 97 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 98 continue; 99 100 if (nlh->nlmsg_flags & NLM_F_EXCL) 101 return -EEXIST; 102 103 matching = timeout; 104 break; 105 } 106 107 l4proto = nf_ct_l4proto_find_get(l3num, l4num); 108 109 /* This protocol is not supportted, skip. */ 110 if (l4proto->l4proto != l4num) { 111 ret = -EOPNOTSUPP; 112 goto err_proto_put; 113 } 114 115 if (matching) { 116 if (nlh->nlmsg_flags & NLM_F_REPLACE) { 117 /* You cannot replace one timeout policy by another of 118 * different kind, sorry. 119 */ 120 if (matching->l3num != l3num || 121 matching->l4proto->l4proto != l4num) { 122 ret = -EINVAL; 123 goto err_proto_put; 124 } 125 126 ret = ctnl_timeout_parse_policy(matching, l4proto, net, 127 cda[CTA_TIMEOUT_DATA]); 128 return ret; 129 } 130 ret = -EBUSY; 131 goto err_proto_put; 132 } 133 134 timeout = kzalloc(sizeof(struct ctnl_timeout) + 135 l4proto->ctnl_timeout.obj_size, GFP_KERNEL); 136 if (timeout == NULL) { 137 ret = -ENOMEM; 138 goto err_proto_put; 139 } 140 141 ret = ctnl_timeout_parse_policy(timeout, l4proto, net, 142 cda[CTA_TIMEOUT_DATA]); 143 if (ret < 0) 144 goto err; 145 146 strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); 147 timeout->l3num = l3num; 148 timeout->l4proto = l4proto; 149 atomic_set(&timeout->refcnt, 1); 150 list_add_tail_rcu(&timeout->head, &cttimeout_list); 151 152 return 0; 153err: 154 kfree(timeout); 155err_proto_put: 156 nf_ct_l4proto_put(l4proto); 157 return ret; 158} 159 160static int 161ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 162 int event, struct ctnl_timeout *timeout) 163{ 164 struct nlmsghdr *nlh; 165 struct nfgenmsg *nfmsg; 166 unsigned int flags = portid ? NLM_F_MULTI : 0; 167 struct nf_conntrack_l4proto *l4proto = timeout->l4proto; 168 169 event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; 170 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 171 if (nlh == NULL) 172 goto nlmsg_failure; 173 174 nfmsg = nlmsg_data(nlh); 175 nfmsg->nfgen_family = AF_UNSPEC; 176 nfmsg->version = NFNETLINK_V0; 177 nfmsg->res_id = 0; 178 179 if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) || 180 nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)) || 181 nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) || 182 nla_put_be32(skb, CTA_TIMEOUT_USE, 183 htonl(atomic_read(&timeout->refcnt)))) 184 goto nla_put_failure; 185 186 if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { 187 struct nlattr *nest_parms; 188 int ret; 189 190 nest_parms = nla_nest_start(skb, 191 CTA_TIMEOUT_DATA | NLA_F_NESTED); 192 if (!nest_parms) 193 goto nla_put_failure; 194 195 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); 196 if (ret < 0) 197 goto nla_put_failure; 198 199 nla_nest_end(skb, nest_parms); 200 } 201 202 nlmsg_end(skb, nlh); 203 return skb->len; 204 205nlmsg_failure: 206nla_put_failure: 207 nlmsg_cancel(skb, nlh); 208 return -1; 209} 210 211static int 212ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) 213{ 214 struct ctnl_timeout *cur, *last; 215 216 if (cb->args[2]) 217 return 0; 218 219 last = (struct ctnl_timeout *)cb->args[1]; 220 if (cb->args[1]) 221 cb->args[1] = 0; 222 223 rcu_read_lock(); 224 list_for_each_entry_rcu(cur, &cttimeout_list, head) { 225 if (last) { 226 if (cur != last) 227 continue; 228 229 last = NULL; 230 } 231 if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid, 232 cb->nlh->nlmsg_seq, 233 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 234 IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { 235 cb->args[1] = (unsigned long)cur; 236 break; 237 } 238 } 239 if (!cb->args[1]) 240 cb->args[2] = 1; 241 rcu_read_unlock(); 242 return skb->len; 243} 244 245static int 246cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb, 247 const struct nlmsghdr *nlh, 248 const struct nlattr * const cda[]) 249{ 250 int ret = -ENOENT; 251 char *name; 252 struct ctnl_timeout *cur; 253 254 if (nlh->nlmsg_flags & NLM_F_DUMP) { 255 struct netlink_dump_control c = { 256 .dump = ctnl_timeout_dump, 257 }; 258 return netlink_dump_start(ctnl, skb, nlh, &c); 259 } 260 261 if (!cda[CTA_TIMEOUT_NAME]) 262 return -EINVAL; 263 name = nla_data(cda[CTA_TIMEOUT_NAME]); 264 265 list_for_each_entry(cur, &cttimeout_list, head) { 266 struct sk_buff *skb2; 267 268 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 269 continue; 270 271 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 272 if (skb2 == NULL) { 273 ret = -ENOMEM; 274 break; 275 } 276 277 ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid, 278 nlh->nlmsg_seq, 279 NFNL_MSG_TYPE(nlh->nlmsg_type), 280 IPCTNL_MSG_TIMEOUT_NEW, cur); 281 if (ret <= 0) { 282 kfree_skb(skb2); 283 break; 284 } 285 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, 286 MSG_DONTWAIT); 287 if (ret > 0) 288 ret = 0; 289 290 /* this avoids a loop in nfnetlink. */ 291 return ret == -EAGAIN ? -ENOBUFS : ret; 292 } 293 return ret; 294} 295 296/* try to delete object, fail if it is still in use. */ 297static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) 298{ 299 int ret = 0; 300 301 /* we want to avoid races with nf_ct_timeout_find_get. */ 302 if (atomic_dec_and_test(&timeout->refcnt)) { 303 /* We are protected by nfnl mutex. */ 304 list_del_rcu(&timeout->head); 305 nf_ct_l4proto_put(timeout->l4proto); 306 kfree_rcu(timeout, rcu_head); 307 } else { 308 /* still in use, restore reference counter. */ 309 atomic_inc(&timeout->refcnt); 310 ret = -EBUSY; 311 } 312 return ret; 313} 314 315static int 316cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, 317 const struct nlmsghdr *nlh, 318 const struct nlattr * const cda[]) 319{ 320 char *name; 321 struct ctnl_timeout *cur; 322 int ret = -ENOENT; 323 324 if (!cda[CTA_TIMEOUT_NAME]) { 325 list_for_each_entry(cur, &cttimeout_list, head) 326 ctnl_timeout_try_del(cur); 327 328 return 0; 329 } 330 name = nla_data(cda[CTA_TIMEOUT_NAME]); 331 332 list_for_each_entry(cur, &cttimeout_list, head) { 333 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 334 continue; 335 336 ret = ctnl_timeout_try_del(cur); 337 if (ret < 0) 338 return ret; 339 340 break; 341 } 342 return ret; 343} 344 345#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 346static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) 347{ 348 struct ctnl_timeout *timeout, *matching = NULL; 349 350 rcu_read_lock(); 351 list_for_each_entry_rcu(timeout, &cttimeout_list, head) { 352 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 353 continue; 354 355 if (!try_module_get(THIS_MODULE)) 356 goto err; 357 358 if (!atomic_inc_not_zero(&timeout->refcnt)) { 359 module_put(THIS_MODULE); 360 goto err; 361 } 362 matching = timeout; 363 break; 364 } 365err: 366 rcu_read_unlock(); 367 return matching; 368} 369 370static void ctnl_timeout_put(struct ctnl_timeout *timeout) 371{ 372 atomic_dec(&timeout->refcnt); 373 module_put(THIS_MODULE); 374} 375#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 376 377static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { 378 [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, 379 .attr_count = CTA_TIMEOUT_MAX, 380 .policy = cttimeout_nla_policy }, 381 [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, 382 .attr_count = CTA_TIMEOUT_MAX, 383 .policy = cttimeout_nla_policy }, 384 [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, 385 .attr_count = CTA_TIMEOUT_MAX, 386 .policy = cttimeout_nla_policy }, 387}; 388 389static const struct nfnetlink_subsystem cttimeout_subsys = { 390 .name = "conntrack_timeout", 391 .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, 392 .cb_count = IPCTNL_MSG_TIMEOUT_MAX, 393 .cb = cttimeout_cb, 394}; 395 396MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); 397 398static int __init cttimeout_init(void) 399{ 400 int ret; 401 402 ret = nfnetlink_subsys_register(&cttimeout_subsys); 403 if (ret < 0) { 404 pr_err("cttimeout_init: cannot register cttimeout with " 405 "nfnetlink.\n"); 406 goto err_out; 407 } 408#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 409 RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); 410 RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); 411#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 412 return 0; 413 414err_out: 415 return ret; 416} 417 418static void __exit cttimeout_exit(void) 419{ 420 struct ctnl_timeout *cur, *tmp; 421 422 pr_info("cttimeout: unregistering from nfnetlink.\n"); 423 424 nfnetlink_subsys_unregister(&cttimeout_subsys); 425 list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) { 426 list_del_rcu(&cur->head); 427 /* We are sure that our objects have no clients at this point, 428 * it's safe to release them all without checking refcnt. 429 */ 430 nf_ct_l4proto_put(cur->l4proto); 431 kfree_rcu(cur, rcu_head); 432 } 433#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 434 RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); 435 RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); 436#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ 437} 438 439module_init(cttimeout_init); 440module_exit(cttimeout_exit);