How can I port forward with iptables?
How about this: I’m a programmer trying to set up an environment so I can debug my server application in eclipse being called from the innernet. Close enough?
8 Answers 8
First of all — you should check if forwarding is allowed at all:
cat /proc/sys/net/ipv4/conf/ppp0/forwarding cat /proc/sys/net/ipv4/conf/eth0/forwarding
If both returns 1 it’s ok. If not do the following:
echo '1' | sudo tee /proc/sys/net/ipv4/conf/ppp0/forwarding echo '1' | sudo tee /proc/sys/net/ipv4/conf/eth0/forwarding
Second thing — DNAT could be applied on nat table only. So, your rule should be extended by adding table specification as well ( -t nat ):
iptables -t nat -A PREROUTING -p tcp -i ppp0 --dport 8001 -j DNAT --to-destination 192.168.1.200:8080 iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
Both rules are applied only to TCP traffic (if you want to alter UDP as well, you need to provide similar rules but with -p udp option set).
Last, but not least is routing configuration. Type:
and check if 192.168.1.0/24 is among returned routing entries.
second line: «iptables -A FORWARD -p tcp -d 192.168.1.200 —dport 8080 -m state —state NEW,ESTABLISHED,RELATED -j ACCEPT» is NOT required if you don’t have firewall restrictions/security, which is the case with most of home LANs, otherwise be careful with -A, be cause it will add it AFTER restrictions/security and may not work (so check -I instead, that is adding IN FRONT of iptables rules)
You forget postrouting source address SNAT ‘ing:
sysctl net.ipv4.ip_forward=1 yours_wan_ip=101.23.3.1 -A PREROUTING -p tcp -m tcp -d $yours_wan_ip --dport 8001 -j DNAT --to-destination 192.168.1.200:8080 -A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT -A POSTROUTING -t nat -p tcp -m tcp -s 192.168.1.200 --sport 8080 -j SNAT --to-source $yours_wan_ip
And don’t forget to set your linux firewall as default gateway on computer with 192.168.1.200 address.
You got it backwards on the POSTROUNTING step. At this point the conversation is still about —destination rather than —source .
iptables -A FORWARD -m state -p tcp -d 192.168.1.200 --dport 8080 --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A PREROUTING -p tcp --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
ummm. that IS what I have already. I use iptables-restore to load it so each is in its own section, but that’s what I wrote above.
Okay, the syntax looked bad in the original. Did you try -i ppp0 in the rules? What is the problem exactly?
The accepted solution works when the destination host and the gateway are on the same subnet (like is in your case, both are on eth0 192.168.1.0/24).
Below is a generic solution for when the gateway, source and destination are all on different subnets.
1) Enable IP forwarding:
sysctl net.ipv4.conf.eth0.forwarding=1 sysctl net.ipv6.conf.eth0.forwarding=1
2) Add 2 iptables rules to forward a specific TCP port:
To rewrite the destination IP of the packet (and back in the reply packet):
iptables -A PREROUTING -t nat -p tcp -i ppp0 --dport 8001 -j DNAT --to-destination 192.168.1.200:8080
To rewrite the source IP of the packet to the IP of the gateway (and back in the reply packet):
iptables -A POSTROUTING -t nat -p tcp -d 192.168.1.200 --dport 8080 -j MASQUERADE
3) If you don’t have a default ACCEPT firewall rule, allow traffic to the destination:
iptables -A FORWARD -p tcp -d 192.168.1.200 --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
4) Test the new setup. If it works, make sure the changes persist across reboots:
cat /etc/sysctl.d/99-forwarding.conf sysctl net.ipv4.conf.eth0.forwarding=1 sysctl net.ipv6.conf.eth0.forwarding=1 EOF iptables-save > /etc/network/iptables.up.rules echo '#!/bin/sh' > /etc/network/if-pre-up.d/iptables echo "`which iptables-restore` < /etc/network/iptables.up.rules" >> /etc/network/if-pre-up.d/iptables chmod +x /etc/network/if-pre-up.d/iptables
I guess that should be the accepted answer because the others do not consider the POSTROUTING part which solves the problem of calling wanIP:8081 from the LAN.
This worked for me, first time, after months of flailing with various inferior alternatives. Most excellent. I guess someone named «rusty» can be trusted when it comes to iptables. 🙂
I have created the following bash script for doing this on my linux router. It automatically infers the WAN IP and confirms your selections before proceeding.
#!/bin/bash # decide which action to use action="add" if [[ "-r" == "$1" ]]; then action="remove" shift fi # break out components dest_addr_lan="$1" dest_port_wan="$2" dest_port_lan="$3" # figure out our WAN ip wan_addr=`curl -4 -s icanhazip.com` # auto fill our dest lan port if we need to if [ -z $dest_port_lan ]; then dest_port_lan="$dest_port_wan" fi # print info for review echo "Destination LAN Address: $dest_addr_lan" echo "Destination Port WAN: $dest_port_wan" echo "Destination Port LAN: $dest_port_lan" echo "WAN Address: $wan_addr" # confirm with user read -p "Does everything look correct? " -n 1 -r echo # (optional) move to a new line if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ "remove" == "$action" ]]; then iptables -t nat -D PREROUTING -p tcp -m tcp -d $wan_addr --dport $dest_port_wan -j DNAT --to-destination $dest_addr_lan:$dest_port_lan iptables -D FORWARD -m state -p tcp -d $dest_addr_lan --dport $dest_port_lan --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -D POSTROUTING -p tcp -m tcp -s $dest_addr_lan --sport $dest_port_lan -j SNAT --to-source $wan_addr echo "Forwarding rule removed" else iptables -t nat -A PREROUTING -p tcp -m tcp -d $wan_addr --dport $dest_port_wan -j DNAT --to-destination $dest_addr_lan:$dest_port_lan iptables -A FORWARD -m state -p tcp -d $dest_addr_lan --dport $dest_port_lan --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A POSTROUTING -p tcp -m tcp -s $dest_addr_lan --sport $dest_port_lan -j SNAT --to-source $wan_addr echo "Forwarding rule added" fi else echo "Info not confirmed, exiting. " fi
The use of the script is simple just copy and paste it to a file and then.
# chmod +x port_forward.sh # ./port_forward.sh 192.168.1.100 3000 . confirm details . press y # Forwarding rule added
# ./port_forward.sh -r 192.168.1.100 3000 . confirm details . press y # Forwarding rule removed
I thought this might save someone time on their respective router.
Iptables: немного о действии REDIRECT, его ограничениях и области применения
Данная заметка повествует о действии REDIRECT в iptables, его ограничениях и области применения.
Iptables и REDIRECT
Действие REDIRECT предназначено для перенаправления пакетов с одного набора портов на другой внутри одной системы, не выходя за пределы хоста.
Работает REDIRECT только в цепочках PREROUTING и OUTPUT таблицы nat. Таким образом, область применения сводится только к перенаправлению с одного порта на другой. Чаще всего это используется для прозрачного прокси, когда клиент из локальной сети коннектится на 80 порт, а шлюз редиректит пакеты на локальный порт прокси:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3128
Кейс
Допустим, надо сменить порт приложения только перенаправлением при помощи iptables, не трогая настроек демона. Пусть новый порт будет 5555, а порт приложения 22. Таким образом, надо сделать редирект с порта 5555 на 22.
REDIRECT и удаленный клиент
Первый шаг очевиден и будет таким же, что и в примере выше:
iptables -t nat -A PREROUTING -p tcp --dport 5555 -j REDIRECT --to-port 22
Однако, правило будет работать только для внешних клиентов и только при открытом порте приложения.
REDIRECT и локальный клиент
Предыдущее правило для самого хоста с iptables не сработает, т.к. пакеты с localhost не попадают в таблицу nat. Чтобы кейс сработал на локальной машине — надо добавить редирект в цепочку OUTPUT таблицы nat:
iptables -t nat -A OUTPUT -p tcp -s 127.0.0.1 --dport 5555 -j REDIRECT --to-ports 22
Теперь локальный клиент тоже может подключиться по 5555 порту.
REDIRECT и закрытый порт
Смысл кейса в том, чтобы использовать левый порт, а порт приложения держать закрытым, но если выполнить DROP правило в INPUT цепочке по 22 порту, то 5555 тоже перестанет отвечать. Собственно, хитрость в том, чтобы открыть порт приложения в INPUT цепочке, а дропать его в mangle:
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j DROP
Полный набор правил
Редирект с сетевым и локальным доступом при закрытом порте приложения:
iptables -t nat -A PREROUTING -p tcp --dport 5555 -j REDIRECT --to-port 22 iptables -t nat -A OUTPUT -p tcp -s 127.0.0.1 --dport 5555 -j REDIRECT --to-ports 22 iptables -A INPUT -p tcp --dport 5555 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -t mangle -A PREROUTING -p tcp --dport 22 -j DROP iptables -P INPUT DROP