History

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.

Pablo Neira Ayuso committed 13 years ago

Commit 91cb4981 parent 180cf722 files · +155 −8Browse files

Unified · Split

2 files
  1. include/uapi/linux/netfilter/nfnetlink_cttimeout.h +2 −0
  2. net/netfilter/nfnetlink_cttimeout.c +153 −8
include/uapi/linux/netfilter/nfnetlink_cttimeout.h+2−0
@@ -6,6 +6,8 @@ enum ctnl_timeout_msg_types { · 5 unmodified lines
66 IPCTNL_MSG_TIMEOUT_NEW,
77 IPCTNL_MSG_TIMEOUT_GET,
88 IPCTNL_MSG_TIMEOUT_DELETE,
9+ IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
10+ IPCTNL_MSG_TIMEOUT_DEFAULT_GET,
911
1012 IPCTNL_MSG_TIMEOUT_MAX
1113 };
net/netfilter/nfnetlink_cttimeout.c+153−8
@@ -49,10 +49,8 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { · 48 unmodified lines
4949 };
5050
5151 static int
52−ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
53− struct nf_conntrack_l4proto *l4proto,
54− struct net *net,
55− const struct nlattr *attr)
52+ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
53+ struct net *net, const struct nlattr *attr)
5654 {
5755 int ret = 0;
5856
@@ -64,8 +62,7 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, · 5 unmodified lines
6462 if (ret < 0)
6563 return ret;
6664
67− ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net,
68− &timeout->data);
65+ ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts);
6966 }
7067 return ret;
7168 }
@@ -123,7 +120,8 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, · 51 unmodified lines
123120 goto err_proto_put;
124121 }
125122
126− ret = ctnl_timeout_parse_policy(matching, l4proto, net,
123+ ret = ctnl_timeout_parse_policy(&matching->data,
124+ l4proto, net,
127125 cda[CTA_TIMEOUT_DATA]);
128126 return ret;
129127 }
@@ -138,7 +136,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, · 8 unmodified lines
138136 goto err_proto_put;
139137 }
140138
141− ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
139+ ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net,
142140 cda[CTA_TIMEOUT_DATA]);
143141 if (ret < 0)
144142 goto err;
@@ -342,6 +340,147 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, · 197 unmodified lines
342340 return ret;
343341 }
344342
343+static int
344+cttimeout_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;
379+err:
380+ nf_ct_l4proto_put(l4proto);
381+ return ret;
382+}
383+
384+static int
385+cttimeout_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+
427+nlmsg_failure:
428+nla_put_failure:
429+ nlmsg_cancel(skb, nlh);
430+ return -1;
431+}
432+
433+static 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;
479+err:
480+ nf_ct_l4proto_put(l4proto);
481+ return err;
482+}
483+
345484 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
346485 static struct ctnl_timeout *ctnl_timeout_find_get(const char *name)
347486 {
@@ -384,6 +523,12 @@ static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { · 36 unmodified lines
384523 [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
385524 .attr_count = CTA_TIMEOUT_MAX,
386525 .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 },
387532 };
388533
389534 static const struct nfnetlink_subsystem cttimeout_subsys = {