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


Hello,

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 127.0.0.0/8 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 192.168.0.4/24, a gateway 192.168.0.1/24 with public 
address 81.56.x.y and HTTP port forwarding to a local server 
192.168.0.6/24. 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 192.168.0.6

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 192.168.0.6 -> 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 (192.168.0.4) instead of the new destination 
address (192.168.0.6) and "dst" to be the new destination address 
(192.168.0.6) 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