NETGEAR is aware of a growing number of phone and online scams. To learn how to stay safe click here.

Forum Discussion

chickenfrog's avatar
chickenfrog
Follower
Apr 21, 2017

Static Routing and NAT (iptables)

*******

I'm posting this as a reference.  I struggled with this for about a day, trying to untangle the iptables of my Netgear Orbi.  

Maybe this write-up can help others.

USE AT YOUR OWN RISK

These changes will not survive a reboot because iptables-save is broken.  (Another reason I wrote it down)

*******

 

I have a home lab network that needs to access the Internet.  I added a static route to my lab network through and internal router.  The lab network does not have Internet access.  This is a problem with iptables.

 

Quick break down:

* Home Network - 192.168.1.0/24. (Orbi is 192.168.1.1)

* Lab Network - 192.168.2.0/24.  (Accessible through a router at 192.168.1.2)

* "router" at 192.168.1.2 on home side, 192.168.2.1 on lab side.

* static route on Orbi pointing 192.168.2.0/24 to the gateway of 192.168.1.2

* all routing is working internally.

 

The first problem is in the iptables table "filter" chain loc2net.

 

root@netgear:/# iptables -t filter -L loc2net
Chain loc2net (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
DROP       tcp  --  anywhere             anywhere             state NEW tcp flags:!FIN,SYN,RST,PSH,ACK,URG/SYN
DROP       tcp  --  anywhere             anywhere             state INVALID
TRIGGER    all  --  anywhere             anywhere            [16 bytes of unknown target data] 
DROP       all  -- !192.168.1.0/24     anywhere            
ACCEPT     all  --  anywhere             anywhere  

 

All traffic that is not coming from 192.168.1.0/24 is dropped - easy to remove.

 

 

iptables -t filter -D loc2net 5

 

 

The next table we need to look at is the table "nat" (shortened for readability)

 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
br0_masq   all  --  anywhere             anywhere            
brwan_masq  all  --  anywhere             anywhere            

Chain br0_masq (1 references)
target     prot opt source               destination         
HAIRPIN    all  --  192.168.1.0/24     anywhere            [24 bytes of unknown target data] 

Chain brwan_masq (1 references)
target     prot opt source               destination         
SNATP2P    all  --  192.168.1.0/24     anywhere            [24 bytes of unknown target data] 

 

The chain POSTROUTING calls two other chains which reference other targets that I cannot find nor configure.  It should be an easy update to add to the brwan_masq chain since I can copy the existing line and change it to reference my lab network.

 

 

root@athena:/# iptables -t nat -A brwan_masq -s 192.168.2.0/24 -j SNATP2P
iptables v1.4.21: Couldn't load target `SNATP2P':No such file or directory

Try `iptables -h' or 'iptables --help' for more information.

Except it's not.  SNATP2P is not a configurable target.  Doh.

 

 

OK, fine.  I'll just use MASQUERADE under the POSTROUTING chain and insert it as the top rule.

 

 

root@netgear:/# iptables -t nat -I POSTROUTING 1 -o brwan -j MASQUERADE
root@netgear:/# iptables -t nat -L POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere            
br0_masq   all  --  anywhere             anywhere            
brwan_masq  all  --  anywhere             anywhere            
root@netgear:/# 

I could have been more specific (by limiting the source) on the MASQUERADE, but it was easier to show with and any-to-any config.

 

That will fix the problem of hosts inside your network that are behind another router. 

 

5 Replies

  • Very cool.  I've known for a long time that Netgear stopped support for NAT-ing non-directly-connected subnets.  Thanks for finding a workaround, albeit one that won't survive a reboot.  Too bad you can't put this into a script that can be saved somewhere non-volatile.

  •   Thanks for the tip! I created a script that I run on the OpenWRT to enable forwarding and check the state of the forwarding. You can hook it up to the DHCP message from the Orbi - so that wen the Orbi comes up the script is automatically executed. More datails on that in another reply I guess. The script should work from any shell that has curl, netcat and openssl installed.

     

      Fabio

    #!/bin/sh
    
    # NOTE: This script requires openssl and the real netcat to be available, not the BusyBox version. On OpenWRT
    #       you can get them via:
    #        
    #       opkg install netcat openssl-util
    #
    
    ORBI_USERNAME="admin"
    ORBI_PASSWORD="**********"
    
    ORBI_ADDRESS="192.168.1.1"
    
    AUTH_TOKEN=`echo -n "${ORBI_USERNAME}:${ORBI_PASSWORD}" | openssl enc -base64`
    
    function timeStamp() {
      curl https://${ORBI_ADDRESS}/debug_detail.htm -s --insecure  -H "Authorization: Basic ${AUTH_TOKEN}"  | grep -e '^var ts'  | sed -e 's/var\W\+ts="\([^"]\+\)".*/\1/g'
    }
    
    function enableTelnet() {
      TS_CODE=`timeStamp`
      curl "https://${ORBI_ADDRESS}/apply.cgi?/debug_detail.htm%20timestamp=${TS_CODE}" -H "Authorization: Basic ${AUTH_TOKEN}" --data 'submit_flag=debug_info&hid_telnet=1&enable_telnet=on' --insecure -s > /dev/null
    }
    
    function disableTelnet() {
      TS_CODE=`timeStamp`
      curl "https://${ORBI_ADDRESS}/apply.cgi?/debug_detail.htm%20timestamp=${TS_CODE}" -H "Authorization: Basic ${AUTH_TOKEN}" --data 'submit_flag=debug_info&hid_telnet=0&enable_telnet=off' --insecure -s > /dev/null
    }
    
    function isForwarding() {
      RULE=`(echo "iptables -L --line-numbers"; sleep 2) | netcat -c -t ${ORBI_ADDRESS} 23 | grep '^5\W\+DROP\W\+all\W\+--\W\+!\d\+\.\d\+\.\d\+\.\d\+\/\d\+\W\+anywhere'`
      if [ "${RULE}" = "" ]
      then
        echo "Forwarding enabled"
      else
        echo "Forwarding disabled"
      fi
    }
    
    function enableForwarding() {
      FORWARD=`isForwarding`
      if [ "${FORWARD}" = "Forwarding disabled" ]
      then
        echo "Enabling forwarding - current state: ${FORWARD}"
        (echo "iptables -t filter -D loc2net 5 && iptables -t nat -I POSTROUTING 1 -o brwan -j MASQUERADE"; sleep 1) | netcat -c -t ${ORBI_ADDRESS} 23 > /dev/null
        isForwarding
      else
       echo "Forwarding is already enabled!"
      fi
    }
    
    case "$1" in
      enable)
    enableTelnet
    ;;
    disable)
    disableTelnet
    ;;
    check)
    enableTelnet
    isForwarding
    disableTelnet
    ;;
    forward)
    enableTelnet
    enableForwarding
    disableTelnet
    ;;
    *) echo "" echo "$0 [enable|disable|forward]" echo "" echo " enable: enable Orbi telnet interface" echo " disable: disable Orbi telnet interface" echo " check: check if Orbi is forwarding internal networks" echo " forward: allow Orbi to forward internal networks" echo "" esac

     

      • fabbari's avatar
        fabbari
        Tutor

          I updated the script to make sure we logout any admin using the web-interface. It may be an inconvenience when an admin is using the web interface, but ensures that automated scripts will always run successfully.

         

        #!/bin/sh
        
        # NOTE: This script requires openssl and the real netcat to be available, not the BusyBox version. On OpenWRT
        #       you can get them via:
        #        
        #       opkg install netcat openssl-util
        #
        
        ORBI_USERNAME="admin"
        ORBI_PASSWORD="*********"
        
        ORBI_ADDRESS="192.168.1.1"
        
        AUTH_TOKEN=`echo -n "${ORBI_USERNAME}:${ORBI_PASSWORD}" | openssl enc -base64`
        
        function forceLogout() {
          curl -s "https://${ORBI_ADDRESS}/change_user.html" -H "Authorization: Basic ${AUTH_TOKEN}" --insecure > /dev/null
          curl -s "https://${ORBI_ADDRESS}/change_user.html" -H "Authorization: Basic ${AUTH_TOKEN}" --insecure > /dev/null
        }
        
        function timeStamp() {
          curl https://${ORBI_ADDRESS}/debug_detail.htm -s --insecure  -H "Authorization: Basic ${AUTH_TOKEN}"  | grep -e '^var ts'  | sed -e 's/var\W\+ts="\([^"]\+\)".*/\1/g'
        }
        
        function enableTelnet() {
          TS_CODE=`timeStamp`
          curl "https://${ORBI_ADDRESS}/apply.cgi?/debug_detail.htm%20timestamp=${TS_CODE}" -H "Authorization: Basic ${AUTH_TOKEN}" --data 'submit_flag=debug_info&hid_telnet=1&enable_telnet=on' --insecure -s > /dev/null
        }
        
        function disableTelnet() {
          TS_CODE=`timeStamp`
          curl "https://${ORBI_ADDRESS}/apply.cgi?/debug_detail.htm%20timestamp=${TS_CODE}" -H "Authorization: Basic ${AUTH_TOKEN}" --data 'submit_flag=debug_info&hid_telnet=0&enable_telnet=off' --insecure -s > /dev/null
        }
        
        function isForwarding() {
          RULE=`(echo "iptables -L --line-numbers"; sleep 2) | netcat -c -t ${ORBI_ADDRESS} 23 | grep '^5\W\+DROP\W\+all\W\+--\W\+!\d\+\.\d\+\.\d\+\.\d\+\/\d\+\W\+anywhere'`
          if [ "${RULE}" = "" ]
          then
            echo "Forwarding enabled"
          else
            echo "Forwarding disabled"
          fi
        }
        
        function enableForwarding() {
          FORWARD=`isForwarding`
          if [ "${FORWARD}" = "Forwarding disabled" ]
          then
            echo "Enabling forwarding - current state: ${FORWARD}"
            (echo "iptables -t filter -D loc2net 5 && iptables -t nat -I POSTROUTING 1 -o brwan -j MASQUERADE"; sleep 1) | netcat -c -t ${ORBI_ADDRESS} 23 > /dev/null
            isForwarding
          else
           echo "Forwarding is already enabled!"
          fi
        }
        
        
        
        case "$1" in
          enable)
            forceLogout
            enableTelnet
            ;;
          disable)
            forceLogout
            disableTelnet
            ;;
          check)
            forceLogout
            enableTelnet
            isForwarding
            disableTelnet
            ;;
          forward)
            forceLogout
            enableTelnet
            enableForwarding
            disableTelnet
            ;;
          *)
            echo ""
            echo "$0 [enable|disable|forward]"
            echo ""
            echo "   enable: enable Orbi telnet interface"
            echo "  disable: disable Orbi telnet interface"
            echo "    check: check if Orbi is forwarding internal networks"
            echo "  forward: allow Orbi to forward internal networks"
            echo ""
        esac