diff options
| -rw-r--r-- | include/uapi/linux/netfilter/nfnetlink_cttimeout.h | 2 | ||||
| -rw-r--r-- | net/netfilter/nfnetlink_cttimeout.c | 161 |
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 | ||
| 51 | static int | 51 | static int |
| 52 | ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, | 52 | ctnl_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 | ||
| 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 | |||
| 345 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 484 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
| 346 | static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) | 485 | static 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 | ||
| 389 | static const struct nfnetlink_subsystem cttimeout_subsys = { | 534 | static const struct nfnetlink_subsystem cttimeout_subsys = { |
