|
@@ -689,71 +689,6 @@ ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_NF_NAT_NEEDED
|
|
|
-static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
|
|
|
- [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
|
|
|
- [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
|
|
|
-};
|
|
|
-
|
|
|
-static int nfnetlink_parse_nat_proto(struct nlattr *attr,
|
|
|
- const struct nf_conn *ct,
|
|
|
- struct nf_nat_range *range)
|
|
|
-{
|
|
|
- struct nlattr *tb[CTA_PROTONAT_MAX+1];
|
|
|
- const struct nf_nat_protocol *npt;
|
|
|
- int err;
|
|
|
-
|
|
|
- err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
-
|
|
|
- npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
|
|
|
- if (npt->nlattr_to_range)
|
|
|
- err = npt->nlattr_to_range(tb, range);
|
|
|
- nf_nat_proto_put(npt);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
-static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
|
|
|
- [CTA_NAT_MINIP] = { .type = NLA_U32 },
|
|
|
- [CTA_NAT_MAXIP] = { .type = NLA_U32 },
|
|
|
-};
|
|
|
-
|
|
|
-static inline int
|
|
|
-nfnetlink_parse_nat(struct nlattr *nat,
|
|
|
- const struct nf_conn *ct, struct nf_nat_range *range)
|
|
|
-{
|
|
|
- struct nlattr *tb[CTA_NAT_MAX+1];
|
|
|
- int err;
|
|
|
-
|
|
|
- memset(range, 0, sizeof(*range));
|
|
|
-
|
|
|
- err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
-
|
|
|
- if (tb[CTA_NAT_MINIP])
|
|
|
- range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
|
|
|
-
|
|
|
- if (!tb[CTA_NAT_MAXIP])
|
|
|
- range->max_ip = range->min_ip;
|
|
|
- else
|
|
|
- range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
|
|
|
-
|
|
|
- if (range->min_ip)
|
|
|
- range->flags |= IP_NAT_RANGE_MAP_IPS;
|
|
|
-
|
|
|
- if (!tb[CTA_NAT_PROTO])
|
|
|
- return 0;
|
|
|
-
|
|
|
- err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
static inline int
|
|
|
ctnetlink_parse_help(struct nlattr *attr, char **helper_name)
|
|
|
{
|
|
@@ -878,6 +813,34 @@ out:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+ctnetlink_parse_nat_setup(struct nf_conn *ct,
|
|
|
+ enum nf_nat_manip_type manip,
|
|
|
+ struct nlattr *attr)
|
|
|
+{
|
|
|
+ typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
|
|
|
+
|
|
|
+ parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
|
|
|
+ if (!parse_nat_setup) {
|
|
|
+#ifdef CONFIG_KMOD
|
|
|
+ rcu_read_unlock();
|
|
|
+ nfnl_unlock();
|
|
|
+ if (request_module("nf-nat-ipv4") < 0) {
|
|
|
+ nfnl_lock();
|
|
|
+ rcu_read_lock();
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+ nfnl_lock();
|
|
|
+ rcu_read_lock();
|
|
|
+ if (nfnetlink_parse_nat_setup_hook)
|
|
|
+ return -EAGAIN;
|
|
|
+#endif
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ return parse_nat_setup(ct, manip, attr);
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
|
|
|
{
|
|
@@ -897,31 +860,6 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
|
|
|
/* ASSURED bit can only be set */
|
|
|
return -EBUSY;
|
|
|
|
|
|
- if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
|
|
|
-#ifndef CONFIG_NF_NAT_NEEDED
|
|
|
- return -EOPNOTSUPP;
|
|
|
-#else
|
|
|
- struct nf_nat_range range;
|
|
|
-
|
|
|
- if (cda[CTA_NAT_DST]) {
|
|
|
- if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct,
|
|
|
- &range) < 0)
|
|
|
- return -EINVAL;
|
|
|
- if (nf_nat_initialized(ct, IP_NAT_MANIP_DST))
|
|
|
- return -EEXIST;
|
|
|
- nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
|
|
|
- }
|
|
|
- if (cda[CTA_NAT_SRC]) {
|
|
|
- if (nfnetlink_parse_nat(cda[CTA_NAT_SRC], ct,
|
|
|
- &range) < 0)
|
|
|
- return -EINVAL;
|
|
|
- if (nf_nat_initialized(ct, IP_NAT_MANIP_SRC))
|
|
|
- return -EEXIST;
|
|
|
- nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
|
|
|
- }
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
/* Be careful here, modifying NAT bits can screw up things,
|
|
|
* so don't let users modify them directly if they don't pass
|
|
|
* nf_nat_range. */
|
|
@@ -929,6 +867,31 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+ctnetlink_change_nat(struct nf_conn *ct, struct nlattr *cda[])
|
|
|
+{
|
|
|
+#ifdef CONFIG_NF_NAT_NEEDED
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (cda[CTA_NAT_DST]) {
|
|
|
+ ret = ctnetlink_parse_nat_setup(ct,
|
|
|
+ IP_NAT_MANIP_DST,
|
|
|
+ cda[CTA_NAT_DST]);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ if (cda[CTA_NAT_SRC]) {
|
|
|
+ ret = ctnetlink_parse_nat_setup(ct,
|
|
|
+ IP_NAT_MANIP_SRC,
|
|
|
+ cda[CTA_NAT_SRC]);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+#else
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+#endif
|
|
|
+}
|
|
|
|
|
|
static inline int
|
|
|
ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
|
|
@@ -1157,6 +1120,14 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
|
|
|
+ err = ctnetlink_change_nat(ct, cda);
|
|
|
+ if (err < 0) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (cda[CTA_PROTOINFO]) {
|
|
|
err = ctnetlink_change_protoinfo(ct, cda);
|
|
|
if (err < 0) {
|