OpenWrt Forum Archive

Topic: Easy port forwarding

The content of this topic has been archived on 15 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Hi,

I thought I'd share the port forwarding script I wrote with the OpenWRT community.  It is quite simple, but it makes it very easy to forward a port, just execute:

port_forward tcp 119 192.168.1.2

I'll paste it in below:

#!/bin/sh

WAN=$(nvram get wan_ifname)

# ensure a valid protocol is specified
if [ "$1" != "tcp" -a "$1" != "udp" ]
then
  echo "Specify a protocol (tcp or udp)."
  echo "Usage: `basename $0` [tcp|udp] [port] [IP]"
  exit
fi

# check that the port range is valid
if [ -z "$2" -o "$2" -le 1 -o "$2" -ge 65536 ]
then
  echo "Specify a port number."
  echo "Usage: `basename $0` [tcp|udp] [port] [IP]"
  exit
fi

# check for IP address validity                    
ipcalc $3 > /dev/null 2>&1                         
if [ $? -ne 0 ]                                    
then                                               
  echo "Specify a LAN ip address."                 
  echo "Usage: `basename $0` [tcp|udp] [port] [IP]"
  exit                                             
fi                                                 
                                                   
iptables -t nat -A prerouting_rule -i $WAN -p $1 --dport $2 -j DNAT --to $3
iptables        -A forwarding_rule -i $WAN -p $1 --dport $2 -d $3 -j ACCEPT

Rupan's script misses a couple of useful options.  Namely, forwarding to a different port than the one incoming connections arrive on and deleteing port forwarding rules.  Also, rules should be added to prerouting_rule chain, not the PREROUTING, and I think adding -i $WAN is redundant.  I've attached an improved version.

To forward a port 10022 to port 22 on 192.168.1.100, run:

port_forward -A tcp 10022 192.168.1.100 22

To delete this port forwarding, replace the -A with -D.

To see the currently forwarded ports, use:

iptables -L forwarding_rule

This should perhaps be integrated into the script.  Also, the script doesn't support deleting all the currently forwarded ports.

#!/bin/sh

usage()
{
  echo "Usage: `basename $0` -A tcp|udp local-port IP [remote-port]"
  echo "       `basename $0` -D tcp|udp local-port IP [remote-port]"
  echo
  echo "-A adds a forwarding rule, -D deletes one."
  exit 1
}

valid_port()
{
  [ -n "$1" -a "$1" -ge 1 -a "$1" -lt 65536 ]
}

if [ $# -ne 4 -a $# -ne 5 ]
then
  usage
fi

action=$1
shift
if [ "$action" != "-A" -a "$action" != "-D" ]
then
  echo "Invalid option: $action."
  usage
fi

proto=$1
shift
if [ "$proto" != "tcp" -a "$proto" != "udp" ]
then
  echo "Invalid protocol \`$proto' (must be tcp or udp)."
  usage
fi

listen_port=$1
shift
if ! valid_port "$listen_port"
then
  echo "Invalid port number \`$listen_port' (must be between 1 and 65536)."
  usage
fi

ip=$1
shift
if ! ipcalc "$ip" > /dev/null 2>&1
then
  echo "Invalid IP address \`$ip' (must be a numeric IP)."
  usage
fi

if [ $# -eq 0 ]
then
  remote_port=$listen_port
else
  remote_port=$1
  if ! valid_port "$remote_port"
  then
    echo "Invalid port number \`$remote_port' (must be between 1 and 65536)."
    usage
  fi
fi

# Reroute the packet.
iptables -t nat $action prerouting_rule \
  -p "$proto" --dport "$listen_port" -j DNAT --to "$ip:$remote_port"
# Let the traffic in.
iptables $action forwarding_rule \
  -p "$proto" --dport "$remote_port" -d "$ip" -j ACCEPT

Excellent, thank you very much for the improvements!  I just installed your version and it works very well.

It turns out that you do in fact want -i $WAN as the iptable rules as written rewrite all packets going through the router not just those intended for the router on any interface.  For instance, if you forwarded port 80 to 192.168.1.100:80, browsing the web no longer works.  Here is a fixed version:

#!/bin/sh

usage()
{
  echo "Usage: `basename $0` -A tcp|udp local-port IP [remote-port]"
  echo "       `basename $0` -D tcp|udp local-port IP [remote-port]"
  echo
  echo "-A adds a forwarding rule, -D deletes one."
  exit 1
}

valid_port()
{
  [ -n "$1" -a "$1" -ge 1 -a "$1" -lt 65536 ]
}

if [ $# -ne 4 -a $# -ne 5 ]
then
  usage
fi

action=$1
shift
if [ "$action" != "-A" -a "$action" != "-D" ]
then
  echo "Invalid option: $action."
  usage
fi

proto=$1
shift
if [ "$proto" != "tcp" -a "$proto" != "udp" ]
then
  echo "Invalid protocol \`$proto' (must be tcp or udp)."
  usage
fi

listen_port=$1
shift
if ! valid_port "$listen_port"
then
  echo "Invalid port number \`$listen_port' (must be between 1 and 65536)."
  usage
fi

ip=$1
shift
if ! ipcalc "$ip" > /dev/null 2>&1
then
  echo "Invalid IP address \`$ip' (must be a numeric IP)."
  usage
fi

if [ $# -eq 0 ]
then
  remote_port=$listen_port
else
  remote_port=$1
  if ! valid_port "$remote_port"
  then
    echo "Invalid port number \`$remote_port' (must be between 1 and 65536)."
    usage
  fi
fi

WAN=$(nvram get wan_ifname)

# Reroute the packet.
iptables -t nat $action prerouting_rule \
  -i $WAN -p "$proto" --dport "$listen_port" -j DNAT --to "$ip:$remote_port"
# Let the traffic in.
iptables $action forwarding_rule \
  -i $WAN -p "$proto" --dport "$remote_port" -d "$ip" -j ACCEPT

The discussion might have continued from here.