Wrong addresses passed to warn_if_extra_mangle() ?

Pascal Hambourg pascal.mail at plouf.fr.eu.org
Mon Nov 13 17:01:48 CET 2006


Since Linux 2.6.11, DNAT of locally generated packets does no implicit 
source NAT to match the new destination any more.

 From ChangeLog-2.6.11 :
>   [PATCH] Remove do_extra_mangle: double NAT on LOCAL_OUT
>   On NF_IP_LOCAL_OUT, when destination NAT changes the destination
>   interface, we also change the source address, so the packet is the
>   same as if it were generated to go that way in the first place.  This
>   is not strictly necessary, I believe.
>   This patch rips that code out to see what breaks.

[One thing that breaks is that now you cannot do things like this any more :

iptables -t nat -A OUTPUT -d 127.x.y.z -j DNAT --to <remote_ip>

because the default source address for a destination in is 
the same as the destination, and the output routing prohibits using such 
source address to send a packet to a remote destination.

But this is not the subject of this message.]

Consider a host, a gateway with public 
address 81.56.x.y and HTTP port forwarding to a local server When using the following rule on the host :

iptables -t nat -A OUTPUT -d 81.56.x.y -p tcp --dport 80 \
   -j DNAT --to-destination

the first time a locally generated packet matches the rule, the kernel 
prints the following message :

> NAT: no longer support implicit source local NAT
> NAT: packet src -> dst 81.56.x.y

This message is printed by the function warn_if_extra_mangle(). But the 
"src" and "dst" addresses look strange. I would expect "src" to be the 
packet source address ( instead of the new destination 
address ( and "dst" to be the new destination address 
( instead of the original destination address (81.56.x.y). 
Besides, if I understand correctly, this message should not be printed 
in this situation because the source address would be the same for both 
the original and the new destination addresses. Am I correct ?

 From net/ipv4/netfilter/ip_nat_rule.c :

> /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
> static void warn_if_extra_mangle(u32 dstip, u32 srcip)
> {
> 	static int warned = 0;
> 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
> 	struct rtable *rt;
> 	if (ip_route_output_key(&rt, &fl) != 0)
> 		return;
> 	if (rt->rt_src != srcip && !warned) {
> 		printk("NAT: no longer support implicit source local NAT\n");
> 		printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n",
> 		       NIPQUAD(srcip), NIPQUAD(dstip))
> 	warned = 1;
> 	}
> 	ip_rt_put(rt);
> }

warn_if_extra_mangle() is called in ipt_dnat_target() :

> 	if (hooknum == NF_IP_LOCAL_OUT
> 	    && mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
> 		warn_if_extra_mangle((*pskb)->nh.iph->daddr,
> 				     mr->range[0].min_ip);

If I understand correctly :
- dstip = (*pskb)->nh.iph->daddr which is the original destination address ;
- srcip = mr->range[0].min_ip which is the new destination address.

However I am not sure whether mr->range[0].min_ip is the actual new 
destination address or the lower address in the DNAT --to range.

Shouldn't it be rather :
- dstip = the new destination address ;
- srcip = the source address ((*pskb)->nh.iph->saddr ?) ?

More information about the netfilter mailing list