aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_cttimeout.h2
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c161
2 files changed, 155 insertions, 8 deletions
diff --git a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h
index a2810a7c5e30..1ab0b97b3a1e 100644
--- a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h
+++ b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h
@@ -6,6 +6,8 @@ enum ctnl_timeout_msg_types {
6 IPCTNL_MSG_TIMEOUT_NEW, 6 IPCTNL_MSG_TIMEOUT_NEW,
7 IPCTNL_MSG_TIMEOUT_GET, 7 IPCTNL_MSG_TIMEOUT_GET,
8 IPCTNL_MSG_TIMEOUT_DELETE, 8 IPCTNL_MSG_TIMEOUT_DELETE,
9 IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
10 IPCTNL_MSG_TIMEOUT_DEFAULT_GET,
9 11
10 IPCTNL_MSG_TIMEOUT_MAX 12 IPCTNL_MSG_TIMEOUT_MAX
11}; 13};
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 = {