Playing around with my WL500g.Deluxe i found out, that the NAT support is somehow broken.
NAT only works for /24 networks, regardless which netmask is configured for the LAN interface. The reason is a bug in src/router/rc/firewall_ex.c in the function ip2class. This function is invoked to calculate the numeric network class for the iptables configuration stored in /tmp/nat_rules.
This is the original ASUS code:
Code:
ip2class(char *lan_ip, char *netmask, char *buf)
{
unsigned int val, ip;
struct in_addr in;
int i=0;
// only handle class A,B,C
val = (unsigned int)inet_addr(netmask);
ip = (unsigned int)inet_addr(lan_ip);
in.s_addr = ip & val;
if (val==0xff00000) sprintf(buf, "%s/8", inet_ntoa(in));
else if (val==0xffff0000) sprintf(buf, "%s/16", inet_ntoa(in));
else sprintf(buf, "%s/24", inet_ntoa(in));
dprintf(buf);
}
It seems that this function supports only Class A,B and C (/8, /16 and /24) networks. But wait! The function inet_addr (from arpa/inet.h) returns the ip address in network byte order, so e.g. 255.255.255.0 will become 0x00ffffff (and not 0xffffff00). This means that the function ip2class above actually always returns "/24" because the else statement always matches.
I found this bug in the 1.9.2.7 source (I'm using oleg's 1.9.2.7-6b), but I just checked 1.9.5.0 from ASUS - the bug is still there. ASUS told me, to post into this forum rather than directly contacting the developers.
However, here is a fix. It also works with all possible netmasks:
Code:
ip2class(char *lan_ip, char *netmask, char *buf)
{
unsigned int val, ip;
struct in_addr in;
int i=0;
// should handle all classes now
val = (unsigned int)inet_addr(netmask);
ip = (unsigned int)inet_addr(lan_ip);
in.s_addr = ip & val;
val = ((val & 0xff000000) >> 24) + ((val & 0x00ff0000) >> 8) + ((val & 0x0000ff00) << 8) + (val & 0x000000ff) << 24);
while (val!=0)
{
val = val << 1;
i++;
}
sprintf(buf, "%s/%d", inet_ntoa(in), i);
dprintf(buf);
}
oleg: can you patch this into your next release, please?