Reply
Highlighted
Follower

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. 

 

Model: Orbi High-Performance AC3000 Tri-Band WiFi System (RBK50)
Message 1 of 6
Highlighted
Guru

Re: Static Routing and NAT (iptables)

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.

Message 2 of 6
Highlighted
Tutor

Re: Static Routing and NAT (iptables)

  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

 

Model: Orbi High-Performance AC3000 Tri-Band WiFi System (RBK50)
Message 3 of 6
Highlighted
Guru

Re: Static Routing and NAT (iptables)

Very clever!
Message 4 of 6
Highlighted
Tutor

Re: Static Routing and NAT (iptables) - Updated Script

  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
Model: Orbi High-Performance AC3000 Tri-Band WiFi System (RBK50)
Message 5 of 6
Tutor

Re: Static Routing and NAT (iptables) - Now as OpenWRT Service

  Last version of this script - I promise! Quick instructions: install socat, netcat and openssl-util on your openwrt router. Drop the script in a file called `/etc/init.d/orbi` - make the file executable. Edit the file to change your password and Orbi IP address - if it's not 192.168.1.1. Then enable the script: `/etc/init.d/orbi enable' and start it: '/etc/init.d/orbi start'.

 

  The script will listen for multicast messages from Orbi - every time it will detect one, it will check if the Orbi is configured for forwarding the internal lan - sleep for 30 seconds and start listening again.

 

  Let me know if anyone finds this useful.

 

  Fabio

 

#!/bin/sh /etc/rc.common
# Example script
# Copyright (C) 2007 OpenWrt.org
 
START=10
STOP=15

# NOTE: This script requires socat, openssl and the real netcat to be available, not the BusyBox version. On OpenWRT
#       you can get them via:
#        
#       opkg install socat netcat openssl-util
#

ORBI_USERNAME="admin"
ORBI_PASSWORD="*************"

ORBI_ADDRESS=192.168.1.1
ORBI_MCAST_PORT=5353
ORBI_MCAST_ADDR=224.0.0.251
ORBI_MCAST_IF=eth0.2

AUTH_TOKEN=`echo -n "${ORBI_USERNAME}:${ORBI_PASSWORD}" | openssl enc -base64`

ORBI_SCRIPT=/etc/init.d/orbi

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
    FORWARDING=1
  else
    FORWARDING=0
  fi
}

function enableForwarding() {
  isForwarding
  if [ ${FORWARDING} -eq 0 ]
  then
    logger -t ORBI -p daemon.info "Enabling forwarding"
    (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
  else
    logger -t ORBI -p daemon.warn "Forwarding is already enabled!"
  fi
}


EXTRA_COMMANDS="on off forward check monitor"
EXTRA_HELP=<<EOF
                    on    Enable telnet on the Orbi
                   off    Disable telnet on the Orbi
               forward    Manually enable forwarding for the Orbi
                 check    Check the Orbi to see if forwarding is enabled
               monitor    Enable monitoring of Orbi
EOF


start () {
  logger -t ORBI -p daemon.info 'Launching background monitor'
  (( ${ORBI_SCRIPT} monitor >/dev/null 2>&1 ) & ) &
}

stop () {
    if [ -f /tmp/.orbi.running ]
    then
      logger -t ORBI -p daemon.info 'Stopping Orbi Service'
      PID=`cat /tmp/.orbi.running`
      rm /tmp/.orbi.running
      kill -TERM ${PID}
    else
      logger -t ORBI -p daemon.info 'Orbi Service not Running'
    fi
}

restart () {
  stop
  sleep 1
  start
}

monitor() {
    logger -t ORBI -p daemon.info 'Starting Orbi Monitor Service'
    echo $$ > /tmp/.orbi.running 
    while [ -f /tmp/.orbi.running ]
    do
      socat UDP4-RECV:${ORBI_MCAST_PORT},bind=${ORBI_MCAST_ADDR},ip-add-membership=${ORBI_MCAST_ADDR}:${ORBI_MCAST_IF},range=${ORBI_ADDRESS}/32 SYSTEM:"${ORBI_SCRIPT} forward"
      sleep 30
    done
    logger -t ORBI -p daemon.info 'Orbi Monitor Service Exited'
}

on () {
  forceLogout
  enableTelnet
}

off () {
  forceLogout
  disableTelnet
}

check () {
  forceLogout
  enableTelnet
  isForwarding
  if [ ${FORWARDING} -eq 0 ]
  then
    echo "Forwarding is disabled"
  else
    echo "Forwarding is enabled"
  fi
  disableTelnet
}

forward () {
  if [ -f /tmp/.orbi.enabling ]
  then
    logger -t ORBI -p daemon.warn "Already enabling Orbi forwarding - Ignoring request"
  else
    touch /tmp/.orbi.enabling
    forceLogout
    enableTelnet
    enableForwarding
    disableTelnet
    rm /tmp/.orbi.enabling
  fi
}
Model: Orbi High-Performance AC3000 Tri-Band WiFi System (RBK50)
Message 6 of 6
Top Contributors
Discussion stats
  • 5 replies
  • 5200 views
  • 10 kudos
  • 3 in conversation
Announcements