aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2008-10-14 14:58:31 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-14 14:58:31 -0400
commite6a7d3c04f8fe49099521e6dc9a46b0272381f2f (patch)
tree4717fcfe05549d39c9281b3b23310b775ad38d16
parent129404a1f117c35c6224e020444fc27eb4479817 (diff)
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>
-rw-r--r--include/linux/netfilter/nfnetlink.h3
-rw-r--r--include/net/netfilter/nf_nat_core.h8
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c97
-rw-r--r--net/netfilter/nf_conntrack_core.c7
-rw-r--r--net/netfilter/nf_conntrack_netlink.c151
-rw-r--r--net/netfilter/nfnetlink.c12
6 files changed, 185 insertions, 93 deletions
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 0d8424f76899..7d8e0455ccac 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -78,6 +78,9 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
78 int echo); 78 int echo);
79extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); 79extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
80 80
81extern void nfnl_lock(void);
82extern void nfnl_unlock(void);
83
81#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \ 84#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
82 MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys)) 85 MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
83 86
diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h
index f29eeb9777e0..58684066388c 100644
--- a/include/net/netfilter/nf_nat_core.h
+++ b/include/net/netfilter/nf_nat_core.h
@@ -25,4 +25,12 @@ static inline int nf_nat_initialized(struct nf_conn *ct,
25 else 25 else
26 return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status); 26 return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
27} 27}
28
29struct nlattr;
30
31extern int
32(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
33 enum nf_nat_manip_type manip,
34 struct nlattr *attr);
35
28#endif /* _NF_NAT_CORE_H */ 36#endif /* _NF_NAT_CORE_H */
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 2ac9eaf1a8c9..a65cf692359f 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -584,6 +584,98 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
584 .flags = NF_CT_EXT_F_PREALLOC, 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
592static 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
597static 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
616static 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
621static int
622nfnetlink_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
655static int
656nfnetlink_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
670static int
671nfnetlink_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
587static int __net_init nf_nat_net_init(struct net *net) 679static int __net_init nf_nat_net_init(struct net *net)
588{ 680{
589 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, 681 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
@@ -654,6 +746,9 @@ static int __init nf_nat_init(void)
654 746
655 BUG_ON(nf_nat_seq_adjust_hook != NULL); 747 BUG_ON(nf_nat_seq_adjust_hook != NULL);
656 rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); 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 return 0; 752 return 0;
658 753
659 cleanup_extend: 754 cleanup_extend:
@@ -667,10 +762,12 @@ static void __exit nf_nat_cleanup(void)
667 nf_ct_l3proto_put(l3proto); 762 nf_ct_l3proto_put(l3proto);
668 nf_ct_extend_unregister(&nat_extend); 763 nf_ct_extend_unregister(&nat_extend);
669 rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); 764 rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
765 rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL);
670 synchronize_net(); 766 synchronize_net();
671} 767}
672 768
673MODULE_LICENSE("GPL"); 769MODULE_LICENSE("GPL");
770MODULE_ALIAS("nf-nat-ipv4");
674 771
675module_init(nf_nat_init); 772module_init(nf_nat_init);
676module_exit(nf_nat_cleanup); 773module_exit(nf_nat_cleanup);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 27de3c7b006e..622d7c671cb7 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -38,9 +38,16 @@
38#include <net/netfilter/nf_conntrack_core.h> 38#include <net/netfilter/nf_conntrack_core.h>
39#include <net/netfilter/nf_conntrack_extend.h> 39#include <net/netfilter/nf_conntrack_extend.h>
40#include <net/netfilter/nf_conntrack_acct.h> 40#include <net/netfilter/nf_conntrack_acct.h>
41#include <net/netfilter/nf_nat.h>
41 42
42#define NF_CONNTRACK_VERSION "0.5.0" 43#define NF_CONNTRACK_VERSION "0.5.0"
43 44
45unsigned int
46(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
47 enum nf_nat_manip_type manip,
48 struct nlattr *attr) __read_mostly;
49EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
50
44DEFINE_SPINLOCK(nf_conntrack_lock); 51DEFINE_SPINLOCK(nf_conntrack_lock);
45EXPORT_SYMBOL_GPL(nf_conntrack_lock); 52EXPORT_SYMBOL_GPL(nf_conntrack_lock);
46 53
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index cadfd15b44f6..08e82d64eb6f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -689,71 +689,6 @@ ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple,
689 return 0; 689 return 0;
690} 690}
691 691
692#ifdef CONFIG_NF_NAT_NEEDED
693static 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
698static 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
717static 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
722static inline int
723nfnetlink_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
757static inline int 692static inline int
758ctnetlink_parse_help(struct nlattr *attr, char **helper_name) 693ctnetlink_parse_help(struct nlattr *attr, char **helper_name)
759{ 694{
@@ -879,6 +814,34 @@ out:
879} 814}
880 815
881static int 816static int
817ctnetlink_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
844static int
882ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) 845ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
883{ 846{
884 unsigned long d; 847 unsigned long d;
@@ -897,31 +860,6 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
897 /* ASSURED bit can only be set */ 860 /* ASSURED bit can only be set */
898 return -EBUSY; 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 /* Be careful here, modifying NAT bits can screw up things, 863 /* Be careful here, modifying NAT bits can screw up things,
926 * so don't let users modify them directly if they don't pass 864 * so don't let users modify them directly if they don't pass
927 * nf_nat_range. */ 865 * nf_nat_range. */
@@ -929,6 +867,31 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
929 return 0; 867 return 0;
930} 868}
931 869
870static int
871ctnetlink_change_nat(struct nf_conn *ct, struct nlattr *cda[])
872{
873#ifdef CONFIG_NF_NAT_NEEDED
874 int ret;
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}
932 895
933static inline int 896static inline int
934ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) 897ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
@@ -1157,6 +1120,14 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1157 } 1120 }
1158 } 1121 }
1159 1122
1123 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1124 err = ctnetlink_change_nat(ct, cda);
1125 if (err < 0) {
1126 rcu_read_unlock();
1127 goto err;
1128 }
1129 }
1130
1160 if (cda[CTA_PROTOINFO]) { 1131 if (cda[CTA_PROTOINFO]) {
1161 err = ctnetlink_change_protoinfo(ct, cda); 1132 err = ctnetlink_change_protoinfo(ct, cda);
1162 if (err < 0) { 1133 if (err < 0) {
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index b75c9c4a995d..4739f9f961d8 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -44,15 +44,17 @@ static struct sock *nfnl = NULL;
44static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; 44static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
45static DEFINE_MUTEX(nfnl_mutex); 45static DEFINE_MUTEX(nfnl_mutex);
46 46
47static inline void nfnl_lock(void) 47void nfnl_lock(void)
48{ 48{
49 mutex_lock(&nfnl_mutex); 49 mutex_lock(&nfnl_mutex);
50} 50}
51EXPORT_SYMBOL_GPL(nfnl_lock);
51 52
52static inline void nfnl_unlock(void) 53void nfnl_unlock(void)
53{ 54{
54 mutex_unlock(&nfnl_mutex); 55 mutex_unlock(&nfnl_mutex);
55} 56}
57EXPORT_SYMBOL_GPL(nfnl_unlock);
56 58
57int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) 59int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
58{ 60{
@@ -132,6 +134,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
132 return 0; 134 return 0;
133 135
134 type = nlh->nlmsg_type; 136 type = nlh->nlmsg_type;
137replay:
135 ss = nfnetlink_get_subsys(type); 138 ss = nfnetlink_get_subsys(type);
136 if (!ss) { 139 if (!ss) {
137#ifdef CONFIG_KMOD 140#ifdef CONFIG_KMOD
@@ -165,7 +168,10 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
165 } else 168 } else
166 return -EINVAL; 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