Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+115 -1
+13
include/net/netfilter/nf_conntrack_helper.h
··· 69 69 enum ip_conntrack_info ctinfo, 70 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 85 #endif /*_NF_CONNTRACK_HELPER_H*/
+8
net/ipv4/netfilter/nf_nat_core.c
··· 686 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 694 static int __init nf_nat_init(void) 690 695 { 691 696 size_t i; ··· 722 717 723 718 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); 724 719 720 + nf_ct_helper_expectfn_register(&follow_master_nat); 721 + 725 722 BUG_ON(nf_nat_seq_adjust_hook != NULL); 726 723 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); 727 724 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); ··· 743 736 unregister_pernet_subsys(&nf_nat_net_ops); 744 737 nf_ct_l3proto_put(l3proto); 745 738 nf_ct_extend_unregister(&nat_extend); 739 + nf_ct_helper_expectfn_unregister(&follow_master_nat); 746 740 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); 747 741 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); 748 742 RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
+14
net/ipv4/netfilter/nf_nat_h323.c
··· 568 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 582 static int __init init(void) 573 583 { ··· 600 590 RCU_INIT_POINTER(nat_h245_hook, nat_h245); 601 591 RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); 602 592 RCU_INIT_POINTER(nat_q931_hook, nat_q931); 593 + nf_ct_helper_expectfn_register(&q931_nat); 594 + nf_ct_helper_expectfn_register(&callforwarding_nat); 603 595 return 0; 604 596 } 605 597 ··· 617 605 RCU_INIT_POINTER(nat_h245_hook, NULL); 618 606 RCU_INIT_POINTER(nat_callforwarding_hook, NULL); 619 607 RCU_INIT_POINTER(nat_q931_hook, NULL); 608 + nf_ct_helper_expectfn_unregister(&q931_nat); 609 + nf_ct_helper_expectfn_unregister(&callforwarding_nat); 620 610 synchronize_rcu(); 621 611 } 622 612
+7
net/ipv4/netfilter/nf_nat_sip.c
··· 526 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 534 static void __exit nf_nat_sip_fini(void) 530 535 { 531 536 RCU_INIT_POINTER(nf_nat_sip_hook, NULL); ··· 540 535 RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); 541 536 RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); 542 537 RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); 538 + nf_ct_helper_expectfn_unregister(&sip_nat); 543 539 synchronize_rcu(); 544 540 } 545 541 ··· 560 554 RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); 561 555 RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); 562 556 RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); 557 + nf_ct_helper_expectfn_register(&sip_nat); 563 558 return 0; 564 559 } 565 560
+54
net/netfilter/nf_conntrack_helper.c
··· 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 238 int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 185 239 { 186 240 unsigned int h = helper_hash(&me->tuple);
+18 -1
net/netfilter/nf_conntrack_netlink.c
··· 1679 1679 struct nlattr *nest_parms; 1680 1680 struct nf_conntrack_tuple nat_tuple = {}; 1681 1681 #endif 1682 + struct nf_ct_helper_expectfn *expfn; 1683 + 1682 1684 if (timeout < 0) 1683 1685 timeout = 0; 1684 1686 ··· 1724 1722 if (helper) 1725 1723 NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); 1726 1724 } 1725 + expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn); 1726 + if (expfn != NULL) 1727 + NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name); 1727 1728 1728 1729 return 0; 1729 1730 ··· 1886 1881 [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, 1887 1882 [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, 1888 1883 [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, 1884 + [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING }, 1889 1885 }; 1890 1886 1891 1887 static int ··· 2188 2182 } else 2189 2183 exp->flags = 0; 2190 2184 } 2185 + if (cda[CTA_EXPECT_FN]) { 2186 + const char *name = nla_data(cda[CTA_EXPECT_FN]); 2187 + struct nf_ct_helper_expectfn *expfn; 2188 + 2189 + expfn = nf_ct_helper_expectfn_find_by_name(name); 2190 + if (expfn == NULL) { 2191 + err = -EINVAL; 2192 + goto err_out; 2193 + } 2194 + exp->expectfn = expfn->expectfn; 2195 + } else 2196 + exp->expectfn = NULL; 2191 2197 2192 2198 exp->class = class; 2193 - exp->expectfn = NULL; 2194 2199 exp->master = ct; 2195 2200 exp->helper = helper; 2196 2201 memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));