aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2013-09-04 14:57:48 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-10-01 07:17:39 -0400
commit91cb498e6a34b429a032f8cfbb57dde28cd20e0c (patch)
treecdd44ad555fa1968ddde61543b7f0f12f69e8545 /net
parent180cf72f56fab2810e00497c087c7126bfe53c85 (diff)
netfilter: cttimeout: allow to set/get default protocol timeouts
Default timeouts are currently set via proc/sysctl interface, the typical pattern is a file name like: /proc/sys/net/netfilter/nf_conntrack_PROTOCOL_timeout_STATE This results in one entry per default protocol state timeout. This patch simplifies this by allowing to set default protocol timeouts via cttimeout netlink interface. This should allow us to get rid of the existing proc/sysctl code in the midterm. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c161
1 files changed, 153 insertions, 8 deletions
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 50580494148d..476accd17145 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -49,10 +49,8 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
49}; 49};
50 50
51static int 51static int
52ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, 52ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
53 struct nf_conntrack_l4proto *l4proto, 53 struct net *net, const struct nlattr *attr)
54 struct net *net,
55 const struct nlattr *attr)
56{ 54{
57 int ret = 0; 55 int ret = 0;
58 56
@@ -64,8 +62,7 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
64 if (ret < 0) 62 if (ret < 0)
65 return ret; 63 return ret;
66 64
67 ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, 65 ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts);
68 &timeout->data);
69 } 66 }
70 return ret; 67 return ret;
71} 68}
@@ -123,7 +120,8 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
123 goto err_proto_put; 120 goto err_proto_put;
124 } 121 }
125 122
126 ret = ctnl_timeout_parse_policy(matching, l4proto, net, 123 ret = ctnl_timeout_parse_policy(&matching->data,
124 l4proto, net,
127 cda[CTA_TIMEOUT_DATA]); 125 cda[CTA_TIMEOUT_DATA]);
128 return ret; 126 return ret;
129 } 127 }
@@ -138,7 +136,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
138 goto err_proto_put; 136 goto err_proto_put;
139 } 137 }
140 138
141 ret = ctnl_timeout_parse_policy(timeout, l4proto, net, 139 ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net,
142 cda[CTA_TIMEOUT_DATA]); 140 cda[CTA_TIMEOUT_DATA]);
143 if (ret < 0) 141 if (ret < 0)
144 goto err; 142 goto err;
@@ -342,6 +340,147 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
342 return ret; 340 return ret;
343} 341}
344 342
343static int
344cttimeout_default_set(struct sock *ctnl, struct sk_buff *skb,
345 const struct nlmsghdr *nlh,
346 const struct nlattr * const cda[])
347{
348 __u16 l3num;
349 __u8 l4num;
350 struct nf_conntrack_l4proto *l4proto;
351 struct net *net = sock_net(skb->sk);
352 unsigned int *timeouts;
353 int ret;
354
355 if (!cda[CTA_TIMEOUT_L3PROTO] ||
356 !cda[CTA_TIMEOUT_L4PROTO] ||
357 !cda[CTA_TIMEOUT_DATA])
358 return -EINVAL;
359
360 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
361 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
362 l4proto = nf_ct_l4proto_find_get(l3num, l4num);
363
364 /* This protocol is not supported, skip. */
365 if (l4proto->l4proto != l4num) {
366 ret = -EOPNOTSUPP;
367 goto err;
368 }
369
370 timeouts = l4proto->get_timeouts(net);
371
372 ret = ctnl_timeout_parse_policy(timeouts, l4proto, net,
373 cda[CTA_TIMEOUT_DATA]);
374 if (ret < 0)
375 goto err;
376
377 nf_ct_l4proto_put(l4proto);
378 return 0;
379err:
380 nf_ct_l4proto_put(l4proto);
381 return ret;
382}
383
384static int
385cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
386 u32 seq, u32 type, int event,
387 struct nf_conntrack_l4proto *l4proto)
388{
389 struct nlmsghdr *nlh;
390 struct nfgenmsg *nfmsg;
391 unsigned int flags = portid ? NLM_F_MULTI : 0;
392
393 event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
394 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
395 if (nlh == NULL)
396 goto nlmsg_failure;
397
398 nfmsg = nlmsg_data(nlh);
399 nfmsg->nfgen_family = AF_UNSPEC;
400 nfmsg->version = NFNETLINK_V0;
401 nfmsg->res_id = 0;
402
403 if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) ||
404 nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
405 goto nla_put_failure;
406
407 if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
408 struct nlattr *nest_parms;
409 unsigned int *timeouts = l4proto->get_timeouts(net);
410 int ret;
411
412 nest_parms = nla_nest_start(skb,
413 CTA_TIMEOUT_DATA | NLA_F_NESTED);
414 if (!nest_parms)
415 goto nla_put_failure;
416
417 ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
418 if (ret < 0)
419 goto nla_put_failure;
420
421 nla_nest_end(skb, nest_parms);
422 }
423
424 nlmsg_end(skb, nlh);
425 return skb->len;
426
427nlmsg_failure:
428nla_put_failure:
429 nlmsg_cancel(skb, nlh);
430 return -1;
431}
432
433static int cttimeout_default_get(struct sock *ctnl, struct sk_buff *skb,
434 const struct nlmsghdr *nlh,
435 const struct nlattr * const cda[])
436{
437 __u16 l3num;
438 __u8 l4num;
439 struct nf_conntrack_l4proto *l4proto;
440 struct net *net = sock_net(skb->sk);
441 struct sk_buff *skb2;
442 int ret, err;
443
444 if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
445 return -EINVAL;
446
447 l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
448 l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
449 l4proto = nf_ct_l4proto_find_get(l3num, l4num);
450
451 /* This protocol is not supported, skip. */
452 if (l4proto->l4proto != l4num) {
453 err = -EOPNOTSUPP;
454 goto err;
455 }
456
457 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
458 if (skb2 == NULL) {
459 err = -ENOMEM;
460 goto err;
461 }
462
463 ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
464 nlh->nlmsg_seq,
465 NFNL_MSG_TYPE(nlh->nlmsg_type),
466 IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
467 l4proto);
468 if (ret <= 0) {
469 kfree_skb(skb2);
470 err = -ENOMEM;
471 goto err;
472 }
473 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
474 if (ret > 0)
475 ret = 0;
476
477 /* this avoids a loop in nfnetlink. */
478 return ret == -EAGAIN ? -ENOBUFS : ret;
479err:
480 nf_ct_l4proto_put(l4proto);
481 return err;
482}
483
345#ifdef CONFIG_NF_CONNTRACK_TIMEOUT 484#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
346static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) 485static struct ctnl_timeout *ctnl_timeout_find_get(const char *name)
347{ 486{
@@ -384,6 +523,12 @@ static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
384 [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, 523 [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
385 .attr_count = CTA_TIMEOUT_MAX, 524 .attr_count = CTA_TIMEOUT_MAX,
386 .policy = cttimeout_nla_policy }, 525 .policy = cttimeout_nla_policy },
526 [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
527 .attr_count = CTA_TIMEOUT_MAX,
528 .policy = cttimeout_nla_policy },
529 [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
530 .attr_count = CTA_TIMEOUT_MAX,
531 .policy = cttimeout_nla_policy },
387}; 532};
388 533
389static const struct nfnetlink_subsystem cttimeout_subsys = { 534static const struct nfnetlink_subsystem cttimeout_subsys = {