Skip to content

Instantly share code, notes, and snippets.

@kimus
Created March 2, 2014 22:46
Show Gist options
  • Save kimus/9315140 to your computer and use it in GitHub Desktop.
Save kimus/9315140 to your computer and use it in GitHub Desktop.
NAT and FORWARD with Ubuntu’s ufw firewall

UFW

I use Ubuntu’s Uncomplicated firewall because it is available on Ubuntu and it's very simple.

Install UFW

if ufw is not installed by default be sure to install it first.

$ sudo apt-get install ufw

NAT

If you needed ufw to NAT the connections from the external interface to the internal the solution is pretty straight forward. In the file /etc/default/ufw change the parameter DEFAULT_FORWARD_POLICY

DEFAULT_FORWARD_POLICY="ACCEPT"

Also configure /etc/ufw/sysctl.conf to allow ipv4 forwarding (the parameters is commented out by default). Uncomment for ipv6 if you want.

net.ipv4.ip_forward=1
#net/ipv6/conf/default/forwarding=1
#net/ipv6/conf/all/forwarding=1

The final step is to add NAT to ufw’s configuration. Add the following to /etc/ufw/before.rules just before the filter rules.

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT

Now enable the changes by restarting ufw.

$ sudo ufw disable && sudo ufw enable

FORWARD

For port forwardind just do something like this.

# NAT table rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port Forwardings
-A PREROUTING -i eth0 -p tcp --dport 22 -j DNAT --to-destination 192.168.1.10

# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMIT
@phlplowe9
Copy link

Nice simple guide but I spent days struggling to make it work.

The problem is ufw will append all of the rules to the iptables chains every time ufw is reloaded or started/stopped. So you end up with lots of copies of the same thing. Or in my case lots of permutations of slightly different things to test, none of which were applying since they were further down.

you should have a -F before the first -A to flush all of the old rules out first.

@casesolved-co-uk
Copy link

casesolved-co-uk commented Aug 26, 2024

Does anyone know if:
net.ipv4.ip_forward=1
and

ufw route allow in on lxdbr0
ufw route allow out on lxdbr0

are interchangeable?
It seems one enables global routing while the other is more specific to the internal bridge interface

@casesolved-co-uk
Copy link

Can can confirm a -F first flushes the nat table before inserting the rules using the -A rules on a ufw reload.
Preferable to MANAGE_BUILTINS=yes

@casesolved-co-uk
Copy link

Does anyone know if: net.ipv4.ip_forward=1 and

ufw route allow in on lxdbr0
ufw route allow out on lxdbr0

are interchangeable? It seems one enables global routing while the other is more specific to the internal bridge interface

No, these are not interchangeable.
I think the former allows the kernel to action the routing table, while iptables controls/filters the packets that hit the routing table

@dsossna
Copy link

dsossna commented Sep 4, 2024

Hello,

I am trying to forward the traffic from a router on a stick at my pi ethernet to the wlan port at the pi. The problem is, that the packeges are not transfered to the wlan port or the translation to the external ip is not working. So for what is the parameter -s. If I type my vlan networks to it I see the ionternal IP external. I anabled ipv4 routing and the routing between the differen subnets is working fine.


| |
| Pi Ethernet with 5 VLAN
| Pi Wlan Dongle with DHCP
| The configuration above
| in ufw before.rules


@casesolved-co-uk
Copy link

casesolved-co-uk commented Sep 4, 2024

Hello,

I am trying to forward the traffic from a router on a stick at my pi ethernet to the wlan port at the pi. The problem is, that the packeges are not transfered to the wlan port or the translation to the external ip is not working. So for what is the parameter -s. If I type my vlan networks to ist I see the IP external. I anabled ipv4 routing and the routing between the differen subnets is working fine.

@dsossna
The -s in -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE means the source network for outbound NAT (making it look like your internal traffic comes from your public IP).
However these commands are only for NAT, either whole IP or individual ports. It sounds like you just want normal routing without any NAT, so net.ipv4.ip_forward=1 should be enough. A WLAN port won't have a public IP so NAT is not necessary. If routing between vlans is working, the WLAN interface should be the same, it is just another network.

@dsossna
Copy link

dsossna commented Sep 4, 2024

@casesolved-co-uk
No I need nat, because my Pi is behind a wlan access point that routes the traffik to the internet. I can not establish static routes back to the vlan networks. If I try to ping the wlan access points IP iget the answer time fault. This is a typical error if the reverse route is not available.
You are wright that normaly the icmp has no problem with a local connected subnet. But if I ping from a computer at a vlan subnet the router has to nat this because the router in front do not know the subnet

computer ----pi vlan port----Pi wlan port-----GLI Net router with nat to the Internet

@casesolved-co-uk
Copy link

casesolved-co-uk commented Sep 4, 2024

@dsossna
Then there are two ways to solve it:

  1. Add routes to your internet router so that it knows about all your other networks and the pi gateway and ignore internal NAT (recommended). I would try to put all your networks on the same larger subnet (e.g. 10.0.0.0/8) and subnet these onto your vlans (10.0.1.0/24) so your router only has to NAT a single network.
  2. NAT overload IPs on your pi (which is what you are attempting). However, having double nested NAT isn't necessary or recommended and is prone to issues like you're seeing

@dsossna
Copy link

dsossna commented Sep 4, 2024

@casesolved-co-uk
Yes I know that doble nat ios not nassasary, but this is an shool network where I have no internet, only with my GLI Spitz Wlan Hotspot I have Internet with gsm modem in the router. I installed the Pi as a router for the local practise networks for my students. I am using linux as a nat router for a long time and so I do not understand why this constallation is not working. When I am in other places there are subnets with firewall and routing, so I know how to translate the traffic. I normaly use this vommand for nat. iptables -t nat -A POSTROUTING -o enp0sx -j MASQUERADE and this is working fine. Now my wlan network card name is very long in bookworm, but this could not be the reason

@dsossna
Copy link

dsossna commented Sep 5, 2024

I solved the problem. It was a mistake in the Name of the wlan interface

@coding-linux
Copy link

my ufw router configuration:

#eth0=WAN (wired WAN)
#eth1=LAN (wired LAN)
#wlan0=LAN (wifi LAN)

sudo apt update
sudo apt dist-upgrade
sudo apt install nano iptables dnsmasq ufw


sudo nano /etc/network/interfaces:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.1.10
netmask 255.255.255.0
broadcast 192.168.1.255

auto eth1
iface eth1 inet static
address 192.168.10.1
netmask 255.255.255.0
broadcast 192.168.10.255


sudo nano /etc/dnsmasq.conf

interface=eth1
listen-address=192.168.10.1
bind-interfaces
domain-needed
bogus-priv
dhcp-range=192.168.10.50,192.168.10.80,24h


sudo nano /etc/sysctl.conf:

net.ipv4.ip_forward=1

or for ufw only:

sudo nano /etc/ufw/sysctl.conf:

net.ipv4.ip_forward=1


sudo nano /etc/default/ufw:

#Set the default input policy to ACCEPT, DROP, or REJECT. Please note that if
#you change this you will most likely want to adjust your rules.
DEFAULT_INPUT_POLICY="DROP"

#Set the default output policy to ACCEPT, DROP, or REJECT. Please note that if
#you change this you will most likely want to adjust your rules.
DEFAULT_OUTPUT_POLICY="ACCEPT"

#Set the default forward policy to ACCEPT, DROP or REJECT. Please note that
#if you change this you will most likely want to adjust your rules
DEFAULT_FORWARD_POLICY="ACCEPT"


sudo nano /etc/ufw/before.rules:

#rules.before
#Rules that should be run before the ufw command line added rules. Custom
#rules should be added to one of these chains:
#ufw-before-input
#ufw-before-output
#ufw-before-forward

#Don't delete these required lines, otherwise there will be errors
#NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]

#Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -o eth0 -j MASQUERADE

#don't delete the 'COMMIT' line or these nat table rules won't
#be processed
COMMIT

*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
#End required lines

#allow all on loopback
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-output -o lo -j ACCEPT

#quickly process packets for which we already have a connection
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP

#ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP

#ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT

#allow dhcp client to work

-A ufw-before-input -i eth1 -p udp --dport 67 -j ACCEPT
-A ufw-before-input -i eth1 -p udp --dport 68 -j ACCEPT

-A ufw-before-input -i eth1 -p udp --dport 53 -j ACCEPT
-A ufw-before-input -i eth1 -p tcp --dport 53 -j ACCEPT

-A ufw-before-input -i eth1 -p tcp --dport 22 -j ACCEPT
-A ufw-before-input -p tcp --dport 22 -j DROP

#ufw-not-local
-A ufw-before-input -j ufw-not-local

#if LOCAL, RETURN
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN

#if MULTICAST, RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN

#if BROADCAST, RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN

#all other non-local packets are dropped
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP

#allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
#is uncommented)
-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j DROP

#allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
#is uncommented)
-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j DROP

#don't delete the 'COMMIT' line or these rules won't be processed
COMMIT


sudo ufw disable
sudo ufw enable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment