Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3726add7 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: ctnetlink: fix NAT configuration



The current configuration only allows to configure one manip and overloads
conntrack status flags with netlink semantic.

Signed-off-by: default avatarPatrick Mchardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 997ae831
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -27,13 +27,15 @@ enum ctattr_type {
	CTA_STATUS,
	CTA_PROTOINFO,
	CTA_HELP,
	CTA_NAT,
	CTA_NAT_SRC,
#define CTA_NAT	CTA_NAT_SRC	/* backwards compatibility */
	CTA_TIMEOUT,
	CTA_MARK,
	CTA_COUNTERS_ORIG,
	CTA_COUNTERS_REPLY,
	CTA_USE,
	CTA_ID,
	CTA_NAT_DST,
	__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
+22 −31
Original line number Diff line number Diff line
@@ -629,7 +629,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = {
};

static inline int
ctnetlink_parse_nat(struct nfattr *cda[],
ctnetlink_parse_nat(struct nfattr *nat,
		    const struct ip_conntrack *ct, struct ip_nat_range *range)
{
	struct nfattr *tb[CTA_NAT_MAX];
@@ -639,7 +639,7 @@ ctnetlink_parse_nat(struct nfattr *cda[],

	memset(range, 0, sizeof(*range));
	
	nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
	nfattr_parse_nested(tb, CTA_NAT_MAX, nat);

	if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
		return -EINVAL;
@@ -854,39 +854,30 @@ ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
		/* ASSURED bit can only be set */
		return -EINVAL;

	if (cda[CTA_NAT-1]) {
	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED
		return -EINVAL;
#else
		unsigned int hooknum;
		struct ip_nat_range range;

		if (ctnetlink_parse_nat(cda, ct, &range) < 0)
		if (cda[CTA_NAT_DST-1]) {
			if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
						&range) < 0)
				return -EINVAL;

		DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 
		       NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
		       htons(range.min.all), htons(range.max.all));
		
		/* This is tricky but it works. ip_nat_setup_info needs the
		 * hook number as parameter, so let's do the correct 
		 * conversion and run away */
		if (status & IPS_SRC_NAT_DONE)
			hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
		else if (status & IPS_DST_NAT_DONE)
			hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */
		else 
			return -EINVAL; /* Missing NAT flags */

		DEBUGP("NAT status: %lu\n", 
		       status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
		
		if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
			if (ip_nat_initialized(ct,
					       HOOK2MANIP(NF_IP_PRE_ROUTING)))
				return -EEXIST;
		ip_nat_setup_info(ct, &range, hooknum);

                DEBUGP("NAT status after setup_info: %lu\n",
                       ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
			ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
		}
		if (cda[CTA_NAT_SRC-1]) {
			if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
						&range) < 0)
				return -EINVAL;
			if (ip_nat_initialized(ct,
					       HOOK2MANIP(NF_IP_POST_ROUTING)))
				return -EEXIST;
			ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
		}
#endif
	}

@@ -1106,7 +1097,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
	/* implicit 'else' */

	/* we only allow nat config for new conntracks */
	if (cda[CTA_NAT-1]) {
	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
		err = -EINVAL;
		goto out_unlock;
	}
+22 −31
Original line number Diff line number Diff line
@@ -641,7 +641,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = {
};

static inline int
ctnetlink_parse_nat(struct nfattr *cda[],
ctnetlink_parse_nat(struct nfattr *nat,
		    const struct nf_conn *ct, struct ip_nat_range *range)
{
	struct nfattr *tb[CTA_NAT_MAX];
@@ -651,7 +651,7 @@ ctnetlink_parse_nat(struct nfattr *cda[],

	memset(range, 0, sizeof(*range));
	
	nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
	nfattr_parse_nested(tb, CTA_NAT_MAX, nat);

	if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
		return -EINVAL;
@@ -866,39 +866,30 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[])
		/* ASSURED bit can only be set */
		return -EINVAL;

	if (cda[CTA_NAT-1]) {
	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED
		return -EINVAL;
#else
		unsigned int hooknum;
		struct ip_nat_range range;

		if (ctnetlink_parse_nat(cda, ct, &range) < 0)
		if (cda[CTA_NAT_DST-1]) {
			if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
						&range) < 0)
				return -EINVAL;

		DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 
		       NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
		       htons(range.min.all), htons(range.max.all));
		
		/* This is tricky but it works. ip_nat_setup_info needs the
		 * hook number as parameter, so let's do the correct 
		 * conversion and run away */
		if (status & IPS_SRC_NAT_DONE)
			hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
		else if (status & IPS_DST_NAT_DONE)
			hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */
		else 
			return -EINVAL; /* Missing NAT flags */

		DEBUGP("NAT status: %lu\n", 
		       status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
		
		if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
			if (ip_nat_initialized(ct,
					       HOOK2MANIP(NF_IP_PRE_ROUTING)))
				return -EEXIST;
			ip_nat_setup_info(ct, &range, hooknum);

                DEBUGP("NAT status after setup_info: %lu\n",
                       ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
		}
		if (cda[CTA_NAT_SRC-1]) {
			if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
						&range) < 0)
				return -EINVAL;
			if (ip_nat_initialized(ct,
					       HOOK2MANIP(NF_IP_POST_ROUTING)))
				return -EEXIST;
			ip_nat_setup_info(ct, &range, hooknum);
		}
#endif
	}

@@ -1122,7 +1113,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
	/* implicit 'else' */

	/* we only allow nat config for new conntracks */
	if (cda[CTA_NAT-1]) {
	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
		err = -EINVAL;
		goto out_unlock;
	}