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?