Commit e6a7d3c04f8fe49099521e6dc9a46b0272381f2f

Authored by Pablo Neira Ayuso
Committed by David S. Miller
1 parent 129404a1f1

netfilter: ctnetlink: remove bogus module dependency between ctnetlink and nf_nat

This patch removes the module dependency between ctnetlink and
nf_nat by means of an indirect call that is initialized when
nf_nat is loaded. Now, nf_conntrack_netlink only requires
nf_conntrack and nfnetlink.

This patch puts nfnetlink_parse_nat_setup_hook into the
nf_conntrack_core to avoid dependencies between ctnetlink,
nf_conntrack_ipv4 and nf_conntrack_ipv6.

This patch also introduces the function ctnetlink_change_nat
that is only invoked from the creation path. Actually, the
nat handling cannot be invoked from the update path since
this is not allowed. By introducing this function, we remove
the useless nat handling in the update path and we avoid
deadlock-prone code.

This patch also adds the required EAGAIN logic for nfnetlink.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 6 changed files with 185 additions and 93 deletions Side-by-side Diff

include/linux/netfilter/nfnetlink.h
... ... @@ -78,6 +78,9 @@
78 78 int echo);
79 79 extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
80 80  
  81 +extern void nfnl_lock(void);
  82 +extern void nfnl_unlock(void);
  83 +
81 84 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
82 85 MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
83 86  
include/net/netfilter/nf_nat_core.h
... ... @@ -25,5 +25,13 @@
25 25 else
26 26 return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
27 27 }
  28 +
  29 +struct nlattr;
  30 +
  31 +extern int
  32 +(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
  33 + enum nf_nat_manip_type manip,
  34 + struct nlattr *attr);
  35 +
28 36 #endif /* _NF_NAT_CORE_H */
net/ipv4/netfilter/nf_nat_core.c
... ... @@ -584,6 +584,98 @@
584 584 .flags = NF_CT_EXT_F_PREALLOC,
585 585 };
586 586  
  587 +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  588 +
  589 +#include <linux/netfilter/nfnetlink.h>
  590 +#include <linux/netfilter/nfnetlink_conntrack.h>
  591 +
  592 +static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
  593 + [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
  594 + [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
  595 +};
  596 +
  597 +static int nfnetlink_parse_nat_proto(struct nlattr *attr,
  598 + const struct nf_conn *ct,
  599 + struct nf_nat_range *range)
  600 +{
  601 + struct nlattr *tb[CTA_PROTONAT_MAX+1];
  602 + const struct nf_nat_protocol *npt;
  603 + int err;
  604 +
  605 + err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
  606 + if (err < 0)
  607 + return err;
  608 +
  609 + npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
  610 + if (npt->nlattr_to_range)
  611 + err = npt->nlattr_to_range(tb, range);
  612 + nf_nat_proto_put(npt);
  613 + return err;
  614 +}
  615 +
  616 +static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
  617 + [CTA_NAT_MINIP] = { .type = NLA_U32 },
  618 + [CTA_NAT_MAXIP] = { .type = NLA_U32 },
  619 +};
  620 +
  621 +static int
  622 +nfnetlink_parse_nat(struct nlattr *nat,
  623 + const struct nf_conn *ct, struct nf_nat_range *range)
  624 +{
  625 + struct nlattr *tb[CTA_NAT_MAX+1];
  626 + int err;
  627 +
  628 + memset(range, 0, sizeof(*range));
  629 +
  630 + err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
  631 + if (err < 0)
  632 + return err;
  633 +
  634 + if (tb[CTA_NAT_MINIP])
  635 + range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
  636 +
  637 + if (!tb[CTA_NAT_MAXIP])
  638 + range->max_ip = range->min_ip;
  639 + else
  640 + range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
  641 +
  642 + if (range->min_ip)
  643 + range->flags |= IP_NAT_RANGE_MAP_IPS;
  644 +
  645 + if (!tb[CTA_NAT_PROTO])
  646 + return 0;
  647 +
  648 + err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
  649 + if (err < 0)
  650 + return err;
  651 +
  652 + return 0;
  653 +}
  654 +
  655 +static int
  656 +nfnetlink_parse_nat_setup(struct nf_conn *ct,
  657 + enum nf_nat_manip_type manip,
  658 + struct nlattr *attr)
  659 +{
  660 + struct nf_nat_range range;
  661 +
  662 + if (nfnetlink_parse_nat(attr, ct, &range) < 0)
  663 + return -EINVAL;
  664 + if (nf_nat_initialized(ct, manip))
  665 + return -EEXIST;
  666 +
  667 + return nf_nat_setup_info(ct, &range, manip);
  668 +}
  669 +#else
  670 +static int
  671 +nfnetlink_parse_nat_setup(struct nf_conn *ct,
  672 + enum nf_nat_manip_type manip,
  673 + struct nlattr *attr)
  674 +{
  675 + return -EOPNOTSUPP;
  676 +}
  677 +#endif
  678 +
587 679 static int __net_init nf_nat_net_init(struct net *net)
588 680 {
589 681 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
... ... @@ -654,6 +746,9 @@
654 746  
655 747 BUG_ON(nf_nat_seq_adjust_hook != NULL);
656 748 rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
  749 + BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
  750 + rcu_assign_pointer(nfnetlink_parse_nat_setup_hook,
  751 + nfnetlink_parse_nat_setup);
657 752 return 0;
658 753  
659 754 cleanup_extend:
660 755  
... ... @@ -667,10 +762,12 @@
667 762 nf_ct_l3proto_put(l3proto);
668 763 nf_ct_extend_unregister(&nat_extend);
669 764 rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
  765 + rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL);
670 766 synchronize_net();
671 767 }
672 768  
673 769 MODULE_LICENSE("GPL");
  770 +MODULE_ALIAS("nf-nat-ipv4");
674 771  
675 772 module_init(nf_nat_init);
676 773 module_exit(nf_nat_cleanup);
net/netfilter/nf_conntrack_core.c
... ... @@ -38,8 +38,15 @@
38 38 #include <net/netfilter/nf_conntrack_core.h>
39 39 #include <net/netfilter/nf_conntrack_extend.h>
40 40 #include <net/netfilter/nf_conntrack_acct.h>
  41 +#include <net/netfilter/nf_nat.h>
41 42  
42 43 #define NF_CONNTRACK_VERSION "0.5.0"
  44 +
  45 +unsigned int
  46 +(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
  47 + enum nf_nat_manip_type manip,
  48 + struct nlattr *attr) __read_mostly;
  49 +EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
43 50  
44 51 DEFINE_SPINLOCK(nf_conntrack_lock);
45 52 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
net/netfilter/nf_conntrack_netlink.c
... ... @@ -689,72 +689,7 @@
689 689 return 0;
690 690 }
691 691  
692   -#ifdef CONFIG_NF_NAT_NEEDED
693   -static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
694   - [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
695   - [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
696   -};
697   -
698   -static int nfnetlink_parse_nat_proto(struct nlattr *attr,
699   - const struct nf_conn *ct,
700   - struct nf_nat_range *range)
701   -{
702   - struct nlattr *tb[CTA_PROTONAT_MAX+1];
703   - const struct nf_nat_protocol *npt;
704   - int err;
705   -
706   - err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
707   - if (err < 0)
708   - return err;
709   -
710   - npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
711   - if (npt->nlattr_to_range)
712   - err = npt->nlattr_to_range(tb, range);
713   - nf_nat_proto_put(npt);
714   - return err;
715   -}
716   -
717   -static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
718   - [CTA_NAT_MINIP] = { .type = NLA_U32 },
719   - [CTA_NAT_MAXIP] = { .type = NLA_U32 },
720   -};
721   -
722 692 static inline int
723   -nfnetlink_parse_nat(struct nlattr *nat,
724   - const struct nf_conn *ct, struct nf_nat_range *range)
725   -{
726   - struct nlattr *tb[CTA_NAT_MAX+1];
727   - int err;
728   -
729   - memset(range, 0, sizeof(*range));
730   -
731   - err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
732   - if (err < 0)
733   - return err;
734   -
735   - if (tb[CTA_NAT_MINIP])
736   - range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
737   -
738   - if (!tb[CTA_NAT_MAXIP])
739   - range->max_ip = range->min_ip;
740   - else
741   - range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
742   -
743   - if (range->min_ip)
744   - range->flags |= IP_NAT_RANGE_MAP_IPS;
745   -
746   - if (!tb[CTA_NAT_PROTO])
747   - return 0;
748   -
749   - err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
750   - if (err < 0)
751   - return err;
752   -
753   - return 0;
754   -}
755   -#endif
756   -
757   -static inline int
758 693 ctnetlink_parse_help(struct nlattr *attr, char **helper_name)
759 694 {
760 695 struct nlattr *tb[CTA_HELP_MAX+1];
... ... @@ -879,6 +814,34 @@
879 814 }
880 815  
881 816 static int
  817 +ctnetlink_parse_nat_setup(struct nf_conn *ct,
  818 + enum nf_nat_manip_type manip,
  819 + struct nlattr *attr)
  820 +{
  821 + typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
  822 +
  823 + parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
  824 + if (!parse_nat_setup) {
  825 +#ifdef CONFIG_KMOD
  826 + rcu_read_unlock();
  827 + nfnl_unlock();
  828 + if (request_module("nf-nat-ipv4") < 0) {
  829 + nfnl_lock();
  830 + rcu_read_lock();
  831 + return -EOPNOTSUPP;
  832 + }
  833 + nfnl_lock();
  834 + rcu_read_lock();
  835 + if (nfnetlink_parse_nat_setup_hook)
  836 + return -EAGAIN;
  837 +#endif
  838 + return -EOPNOTSUPP;
  839 + }
  840 +
  841 + return parse_nat_setup(ct, manip, attr);
  842 +}
  843 +
  844 +static int
882 845 ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
883 846 {
884 847 unsigned long d;
... ... @@ -897,31 +860,6 @@
897 860 /* ASSURED bit can only be set */
898 861 return -EBUSY;
899 862  
900   - if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
901   -#ifndef CONFIG_NF_NAT_NEEDED
902   - return -EOPNOTSUPP;
903   -#else
904   - struct nf_nat_range range;
905   -
906   - if (cda[CTA_NAT_DST]) {
907   - if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct,
908   - &range) < 0)
909   - return -EINVAL;
910   - if (nf_nat_initialized(ct, IP_NAT_MANIP_DST))
911   - return -EEXIST;
912   - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
913   - }
914   - if (cda[CTA_NAT_SRC]) {
915   - if (nfnetlink_parse_nat(cda[CTA_NAT_SRC], ct,
916   - &range) < 0)
917   - return -EINVAL;
918   - if (nf_nat_initialized(ct, IP_NAT_MANIP_SRC))
919   - return -EEXIST;
920   - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
921   - }
922   -#endif
923   - }
924   -
925 863 /* Be careful here, modifying NAT bits can screw up things,
926 864 * so don't let users modify them directly if they don't pass
927 865 * nf_nat_range. */
928 866  
... ... @@ -929,7 +867,32 @@
929 867 return 0;
930 868 }
931 869  
  870 +static int
  871 +ctnetlink_change_nat(struct nf_conn *ct, struct nlattr *cda[])
  872 +{
  873 +#ifdef CONFIG_NF_NAT_NEEDED
  874 + int ret;
932 875  
  876 + if (cda[CTA_NAT_DST]) {
  877 + ret = ctnetlink_parse_nat_setup(ct,
  878 + IP_NAT_MANIP_DST,
  879 + cda[CTA_NAT_DST]);
  880 + if (ret < 0)
  881 + return ret;
  882 + }
  883 + if (cda[CTA_NAT_SRC]) {
  884 + ret = ctnetlink_parse_nat_setup(ct,
  885 + IP_NAT_MANIP_SRC,
  886 + cda[CTA_NAT_SRC]);
  887 + if (ret < 0)
  888 + return ret;
  889 + }
  890 + return 0;
  891 +#else
  892 + return -EOPNOTSUPP;
  893 +#endif
  894 +}
  895 +
933 896 static inline int
934 897 ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
935 898 {
... ... @@ -1151,6 +1114,14 @@
1151 1114  
1152 1115 if (cda[CTA_STATUS]) {
1153 1116 err = ctnetlink_change_status(ct, cda);
  1117 + if (err < 0) {
  1118 + rcu_read_unlock();
  1119 + goto err;
  1120 + }
  1121 + }
  1122 +
  1123 + if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
  1124 + err = ctnetlink_change_nat(ct, cda);
1154 1125 if (err < 0) {
1155 1126 rcu_read_unlock();
1156 1127 goto err;
net/netfilter/nfnetlink.c
... ... @@ -44,15 +44,17 @@
44 44 static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
45 45 static DEFINE_MUTEX(nfnl_mutex);
46 46  
47   -static inline void nfnl_lock(void)
  47 +void nfnl_lock(void)
48 48 {
49 49 mutex_lock(&nfnl_mutex);
50 50 }
  51 +EXPORT_SYMBOL_GPL(nfnl_lock);
51 52  
52   -static inline void nfnl_unlock(void)
  53 +void nfnl_unlock(void)
53 54 {
54 55 mutex_unlock(&nfnl_mutex);
55 56 }
  57 +EXPORT_SYMBOL_GPL(nfnl_unlock);
56 58  
57 59 int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
58 60 {
... ... @@ -132,6 +134,7 @@
132 134 return 0;
133 135  
134 136 type = nlh->nlmsg_type;
  137 +replay:
135 138 ss = nfnetlink_get_subsys(type);
136 139 if (!ss) {
137 140 #ifdef CONFIG_KMOD
... ... @@ -165,7 +168,10 @@
165 168 } else
166 169 return -EINVAL;
167 170  
168   - return nc->call(nfnl, skb, nlh, cda);
  171 + err = nc->call(nfnl, skb, nlh, cda);
  172 + if (err == -EAGAIN)
  173 + goto replay;
  174 + return err;
169 175 }
170 176 }
171 177