diff options
| author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-02-04 21:44:51 -0500 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-03-07 11:40:46 -0500 |
| commit | 544d5c7d9f4d1ec4f170bc5bcc522012cb7704bc (patch) | |
| tree | d7e4eff56efb23801a5ad0e4720efe13c68672ca | |
| parent | 076a0ca02644657b13e4af363f487ced2942e9cb (diff) | |
netfilter: ctnetlink: allow to set expectfn for expectations
This patch allows you to set expectfn which is specifically used
by the NAT side of most of the existing conntrack helpers.
I have added a symbol map that uses a string as key to look up for
the function that is attached to the expectation object. This is
the best solution I came out with to solve this issue.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
| -rw-r--r-- | include/linux/netfilter/nfnetlink_conntrack.h | 1 | ||||
| -rw-r--r-- | include/net/netfilter/nf_conntrack_helper.h | 13 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 8 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_h323.c | 14 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 7 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 54 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 19 |
7 files changed, 115 insertions, 1 deletions
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index a2f1f483ecc9..e58e4b93c108 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h | |||
| @@ -175,6 +175,7 @@ enum ctattr_expect { | |||
| 175 | CTA_EXPECT_FLAGS, | 175 | CTA_EXPECT_FLAGS, |
| 176 | CTA_EXPECT_CLASS, | 176 | CTA_EXPECT_CLASS, |
| 177 | CTA_EXPECT_NAT, | 177 | CTA_EXPECT_NAT, |
| 178 | CTA_EXPECT_FN, | ||
| 178 | __CTA_EXPECT_MAX | 179 | __CTA_EXPECT_MAX |
| 179 | }; | 180 | }; |
| 180 | #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) | 181 | #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) |
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index f1c1311adc2c..5767dc242dee 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
| @@ -69,4 +69,17 @@ extern int nf_conntrack_broadcast_help(struct sk_buff *skb, | |||
| 69 | enum ip_conntrack_info ctinfo, | 69 | enum ip_conntrack_info ctinfo, |
| 70 | unsigned int timeout); | 70 | unsigned int timeout); |
| 71 | 71 | ||
| 72 | struct nf_ct_helper_expectfn { | ||
| 73 | struct list_head head; | ||
| 74 | const char *name; | ||
| 75 | void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); | ||
| 76 | }; | ||
| 77 | |||
| 78 | void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); | ||
| 79 | void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); | ||
| 80 | struct nf_ct_helper_expectfn * | ||
| 81 | nf_ct_helper_expectfn_find_by_name(const char *name); | ||
| 82 | struct nf_ct_helper_expectfn * | ||
| 83 | nf_ct_helper_expectfn_find_by_symbol(const void *symbol); | ||
| 84 | |||
| 72 | #endif /*_NF_CONNTRACK_HELPER_H*/ | 85 | #endif /*_NF_CONNTRACK_HELPER_H*/ |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index a708933dc230..abb52adf5acd 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
| @@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = { | |||
| 686 | .exit = nf_nat_net_exit, | 686 | .exit = nf_nat_net_exit, |
| 687 | }; | 687 | }; |
| 688 | 688 | ||
| 689 | static struct nf_ct_helper_expectfn follow_master_nat = { | ||
| 690 | .name = "nat-follow-master", | ||
| 691 | .expectfn = nf_nat_follow_master, | ||
| 692 | }; | ||
| 693 | |||
| 689 | static int __init nf_nat_init(void) | 694 | static int __init nf_nat_init(void) |
| 690 | { | 695 | { |
| 691 | size_t i; | 696 | size_t i; |
| @@ -717,6 +722,8 @@ static int __init nf_nat_init(void) | |||
| 717 | 722 | ||
| 718 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); | 723 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); |
| 719 | 724 | ||
| 725 | nf_ct_helper_expectfn_register(&follow_master_nat); | ||
| 726 | |||
| 720 | BUG_ON(nf_nat_seq_adjust_hook != NULL); | 727 | BUG_ON(nf_nat_seq_adjust_hook != NULL); |
| 721 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); | 728 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); |
| 722 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); | 729 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); |
| @@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void) | |||
| 736 | unregister_pernet_subsys(&nf_nat_net_ops); | 743 | unregister_pernet_subsys(&nf_nat_net_ops); |
| 737 | nf_ct_l3proto_put(l3proto); | 744 | nf_ct_l3proto_put(l3proto); |
| 738 | nf_ct_extend_unregister(&nat_extend); | 745 | nf_ct_extend_unregister(&nat_extend); |
| 746 | nf_ct_helper_expectfn_unregister(&follow_master_nat); | ||
| 739 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); | 747 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); |
| 740 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); | 748 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); |
| 741 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | 749 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); |
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index dc1dd912baf4..82536701e3a3 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c | |||
| @@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, | |||
| 568 | return 0; | 568 | return 0; |
| 569 | } | 569 | } |
| 570 | 570 | ||
| 571 | static struct nf_ct_helper_expectfn q931_nat = { | ||
| 572 | .name = "Q.931", | ||
| 573 | .expectfn = ip_nat_q931_expect, | ||
| 574 | }; | ||
| 575 | |||
| 576 | static struct nf_ct_helper_expectfn callforwarding_nat = { | ||
| 577 | .name = "callforwarding", | ||
| 578 | .expectfn = ip_nat_callforwarding_expect, | ||
| 579 | }; | ||
| 580 | |||
| 571 | /****************************************************************************/ | 581 | /****************************************************************************/ |
| 572 | static int __init init(void) | 582 | static int __init init(void) |
| 573 | { | 583 | { |
| @@ -590,6 +600,8 @@ static int __init init(void) | |||
| 590 | RCU_INIT_POINTER(nat_h245_hook, nat_h245); | 600 | RCU_INIT_POINTER(nat_h245_hook, nat_h245); |
| 591 | RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); | 601 | RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); |
| 592 | RCU_INIT_POINTER(nat_q931_hook, nat_q931); | 602 | RCU_INIT_POINTER(nat_q931_hook, nat_q931); |
| 603 | nf_ct_helper_expectfn_register(&q931_nat); | ||
| 604 | nf_ct_helper_expectfn_register(&callforwarding_nat); | ||
| 593 | return 0; | 605 | return 0; |
| 594 | } | 606 | } |
| 595 | 607 | ||
| @@ -605,6 +617,8 @@ static void __exit fini(void) | |||
| 605 | RCU_INIT_POINTER(nat_h245_hook, NULL); | 617 | RCU_INIT_POINTER(nat_h245_hook, NULL); |
| 606 | RCU_INIT_POINTER(nat_callforwarding_hook, NULL); | 618 | RCU_INIT_POINTER(nat_callforwarding_hook, NULL); |
| 607 | RCU_INIT_POINTER(nat_q931_hook, NULL); | 619 | RCU_INIT_POINTER(nat_q931_hook, NULL); |
| 620 | nf_ct_helper_expectfn_unregister(&q931_nat); | ||
| 621 | nf_ct_helper_expectfn_unregister(&callforwarding_nat); | ||
| 608 | synchronize_rcu(); | 622 | synchronize_rcu(); |
| 609 | } | 623 | } |
| 610 | 624 | ||
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index d0319f96269f..57932c43960e 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
| @@ -526,6 +526,11 @@ err1: | |||
| 526 | return NF_DROP; | 526 | return NF_DROP; |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | static struct nf_ct_helper_expectfn sip_nat = { | ||
| 530 | .name = "sip", | ||
| 531 | .expectfn = ip_nat_sip_expected, | ||
| 532 | }; | ||
| 533 | |||
| 529 | static void __exit nf_nat_sip_fini(void) | 534 | static void __exit nf_nat_sip_fini(void) |
| 530 | { | 535 | { |
| 531 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); | 536 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); |
| @@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void) | |||
| 535 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); | 540 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); |
| 536 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); | 541 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); |
| 537 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); | 542 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); |
| 543 | nf_ct_helper_expectfn_unregister(&sip_nat); | ||
| 538 | synchronize_rcu(); | 544 | synchronize_rcu(); |
| 539 | } | 545 | } |
| 540 | 546 | ||
| @@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void) | |||
| 554 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); | 560 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); |
| 555 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); | 561 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); |
| 556 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); | 562 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); |
| 563 | nf_ct_helper_expectfn_register(&sip_nat); | ||
| 557 | return 0; | 564 | return 0; |
| 558 | } | 565 | } |
| 559 | 566 | ||
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index bbe23baa19b6..436b7cb79ba4 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
| @@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct) | |||
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | static LIST_HEAD(nf_ct_helper_expectfn_list); | ||
| 185 | |||
| 186 | void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n) | ||
| 187 | { | ||
| 188 | spin_lock_bh(&nf_conntrack_lock); | ||
| 189 | list_add_rcu(&n->head, &nf_ct_helper_expectfn_list); | ||
| 190 | spin_unlock_bh(&nf_conntrack_lock); | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register); | ||
| 193 | |||
| 194 | void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) | ||
| 195 | { | ||
| 196 | spin_lock_bh(&nf_conntrack_lock); | ||
| 197 | list_del_rcu(&n->head); | ||
| 198 | spin_unlock_bh(&nf_conntrack_lock); | ||
| 199 | } | ||
| 200 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); | ||
| 201 | |||
| 202 | struct nf_ct_helper_expectfn * | ||
| 203 | nf_ct_helper_expectfn_find_by_name(const char *name) | ||
| 204 | { | ||
| 205 | struct nf_ct_helper_expectfn *cur; | ||
| 206 | bool found = false; | ||
| 207 | |||
| 208 | rcu_read_lock(); | ||
| 209 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | ||
| 210 | if (!strcmp(cur->name, name)) { | ||
| 211 | found = true; | ||
| 212 | break; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | rcu_read_unlock(); | ||
| 216 | return found ? cur : NULL; | ||
| 217 | } | ||
| 218 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name); | ||
| 219 | |||
| 220 | struct nf_ct_helper_expectfn * | ||
| 221 | nf_ct_helper_expectfn_find_by_symbol(const void *symbol) | ||
| 222 | { | ||
| 223 | struct nf_ct_helper_expectfn *cur; | ||
| 224 | bool found = false; | ||
| 225 | |||
| 226 | rcu_read_lock(); | ||
| 227 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | ||
| 228 | if (cur->expectfn == symbol) { | ||
| 229 | found = true; | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | rcu_read_unlock(); | ||
| 234 | return found ? cur : NULL; | ||
| 235 | } | ||
| 236 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol); | ||
| 237 | |||
| 184 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 238 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
| 185 | { | 239 | { |
| 186 | unsigned int h = helper_hash(&me->tuple); | 240 | unsigned int h = helper_hash(&me->tuple); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 845c8ca28563..b8827e8a11fe 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
| @@ -1679,6 +1679,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
| 1679 | struct nlattr *nest_parms; | 1679 | struct nlattr *nest_parms; |
| 1680 | struct nf_conntrack_tuple nat_tuple = {}; | 1680 | struct nf_conntrack_tuple nat_tuple = {}; |
| 1681 | #endif | 1681 | #endif |
| 1682 | struct nf_ct_helper_expectfn *expfn; | ||
| 1683 | |||
| 1682 | if (timeout < 0) | 1684 | if (timeout < 0) |
| 1683 | timeout = 0; | 1685 | timeout = 0; |
| 1684 | 1686 | ||
| @@ -1722,6 +1724,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
| 1722 | if (helper) | 1724 | if (helper) |
| 1723 | NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); | 1725 | NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); |
| 1724 | } | 1726 | } |
| 1727 | expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn); | ||
| 1728 | if (expfn != NULL) | ||
| 1729 | NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name); | ||
| 1725 | 1730 | ||
| 1726 | return 0; | 1731 | return 0; |
| 1727 | 1732 | ||
| @@ -1881,6 +1886,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { | |||
| 1881 | [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, | 1886 | [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, |
| 1882 | [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, | 1887 | [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, |
| 1883 | [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, | 1888 | [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, |
| 1889 | [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING }, | ||
| 1884 | }; | 1890 | }; |
| 1885 | 1891 | ||
| 1886 | static int | 1892 | static int |
| @@ -2182,9 +2188,20 @@ ctnetlink_create_expect(struct net *net, u16 zone, | |||
| 2182 | } else | 2188 | } else |
| 2183 | exp->flags = 0; | 2189 | exp->flags = 0; |
| 2184 | } | 2190 | } |
| 2191 | if (cda[CTA_EXPECT_FN]) { | ||
| 2192 | const char *name = nla_data(cda[CTA_EXPECT_FN]); | ||
| 2193 | struct nf_ct_helper_expectfn *expfn; | ||
| 2194 | |||
| 2195 | expfn = nf_ct_helper_expectfn_find_by_name(name); | ||
| 2196 | if (expfn == NULL) { | ||
| 2197 | err = -EINVAL; | ||
| 2198 | goto err_out; | ||
| 2199 | } | ||
| 2200 | exp->expectfn = expfn->expectfn; | ||
| 2201 | } else | ||
| 2202 | exp->expectfn = NULL; | ||
| 2185 | 2203 | ||
| 2186 | exp->class = class; | 2204 | exp->class = class; |
| 2187 | exp->expectfn = NULL; | ||
| 2188 | exp->master = ct; | 2205 | exp->master = ct; |
| 2189 | exp->helper = helper; | 2206 | exp->helper = helper; |
| 2190 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); | 2207 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); |
