-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
--- | ||
author: Major Hayden | ||
date: '2024-06-28' | ||
summary: | | ||
Redirecting local ports with iptables directly isn't too difficult, | ||
but can we use firewalld to get the same result? 🧱 | ||
tags: | ||
- fedora | ||
- firewalld | ||
- linux | ||
- networking | ||
- security | ||
title: Redirect local ports with firewalld | ||
coverAlt: Night sky over New Mexico | ||
coverCaption: | | ||
[Jake Weirick](https://unsplash.com/photos/silhouette-photography-of-trees-hIV2CAyCPI4) via Unsplash | ||
--- | ||
|
||
Linux networking and firewalls give us plenty of options for redirecting traffic from one port to another. | ||
We can allow people outside our home to reach a web server we run in our internal network. | ||
That's called destination NAT, ot [DNAT](https://en.wikipedia.org/wiki/Network_address_translation#DNAT). | ||
|
||
You can also redirect traffic to different ports on the same host. | ||
For example, if you have a daemon listening on port 3000, but you want people to reach that service on port 80, you can redirect traffic from 80 to 3000 on the same host (without network address translation). | ||
|
||
But how do we do this with [firewalld](https://firewalld.org/)? 🤔 | ||
|
||
## Old-school iptables methods | ||
|
||
Let's say you have a service running on port 3000 and you want to expose it to other computers on your same network as port 80. | ||
With iptables, you would typically start by enabling IP forwarding: | ||
|
||
```console | ||
sudo sysctl -w net.ipv4.ip_forward=1 | ||
``` | ||
|
||
Add two iptables rules to handle packets coming in from the outside as well as any locally generated packets: | ||
|
||
```console | ||
# Handle locally-generated packets on the same machine. | ||
sudo iptables -t nat -A PREROUTING -s 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to 3000` | ||
|
||
# Handle packets coming from outside the current machine. | ||
sudo iptables -t nat -A OUTPUT -s 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to 3000` | ||
``` | ||
|
||
There's a weird situation that happens on certain machines with certain network configurations where packets are not properly routed when they are destined for the local network adapter. | ||
To fix that, set one more sysctl configuration: | ||
|
||
```console | ||
sudo sysctl -w net.ipv4.conf.all.route_localnet=1 | ||
``` | ||
|
||
Remember to make these sysctl configurations permanent: | ||
|
||
```console | ||
sudo mkdir /etc/sysctl.conf.d/ | ||
echo "net.ipv4.ip_forward=1" | sudo tee >> /etc/sysctl.conf.d/redirect.conf | ||
echo "net.ipv4.conf.all.route_localnet" | sudo tee >> /etc/sysctl.conf.d/redirect.conf | ||
``` | ||
|
||
## Why consider firewalld? | ||
|
||
I like firewalld because I can manage lots of settings for different firewall zones and allow access from one zone to another. | ||
It also allows me to put certain interfaces in trusted zones so they automatically get more access. | ||
|
||
Another nice aspect about firewalld is that it supports iptables and nftables backends. | ||
You don't have to think about the differences between the backends. | ||
All of that is taken care of for you. | ||
|
||
## Port redirections in firewalld | ||
|
||
Let's start by checking our default firewalld zone: | ||
|
||
```console | ||
$ sudo firewall-cmd --list-all | ||
FedoraServer (default, active) | ||
target: default | ||
ingress-priority: 0 | ||
egress-priority: 0 | ||
icmp-block-inversion: no | ||
interfaces: bond0 eno1 eno2 | ||
sources: | ||
services: dhcpv6-client http https | ||
ports: 51820/udp | ||
protocols: | ||
forward: yes | ||
masquerade: yes | ||
forward-ports: | ||
source-ports: | ||
icmp-blocks: | ||
rich rules: | ||
``` | ||
|
||
This output shows that my external network interfaces are attached to the zone and forwarding is already on in my case. | ||
If you see `forward: no` here, just run this command: | ||
|
||
```console | ||
$ sudo firewall-cmd --add-forward | ||
success | ||
``` | ||
|
||
Now firewalld will manage your `forwarding` sysctl variables for you on these interfaces. | ||
That's handy. 😉 | ||
|
||
Next, let's get the redirect working. | ||
We want to take external packets on port 80 and send them to 3000: on the local machine. | ||
|
||
```console | ||
$ sudo firewall-cmd \ | ||
--add-forward-port=port=80:proto=tcp:toport=3000:toaddr=127.0.0.1 | ||
success | ||
``` | ||
|
||
In this command, we told firewalld to take 80/tcp from the outside and send it to port 3000 on the local host (127.0.0.1). | ||
Let's double check our current configuration: | ||
|
||
```console | ||
$ sudo firewall-cmd --list-all | ||
FedoraServer (default, active) | ||
target: default | ||
ingress-priority: 0 | ||
egress-priority: 0 | ||
icmp-block-inversion: no | ||
interfaces: bond0 eno1 eno2 | ||
sources: | ||
services: dhcpv6-client http https | ||
ports: 51820/udp | ||
protocols: | ||
forward: yes | ||
masquerade: yes | ||
forward-ports: | ||
port=80:proto=tcp:toport=3000:toaddr=127.0.0.1 | ||
source-ports: | ||
icmp-blocks: | ||
rich rules: | ||
``` | ||
|
||
Test a connection to port 80 with `curl` and it should redirect to the service on port 3000. | ||
|
||
🚨 **If everything works, remember to save the firewalld configuration:** | ||
|
||
```console | ||
$ sudo firewall-cmd --runtime-to-permanent | ||
success | ||
``` | ||
|
||
## Extra credit | ||
|
||
We can inspect the nftables rules to see the firewall rules that firewalld set for us. | ||
The [Arch Linux nftables wiki page](https://wiki.archlinux.org/title/Nftables) is superb for looking up those commands. | ||
|
||
If we dump the current ruleset, we see the rule we created in firewalld: | ||
|
||
```console | ||
$ sudo nft list ruleset | ||
---SNIP--- | ||
chain nat_PRE_FedoraServer_allow { | ||
meta nfproto ipv4 tcp dport 80 dnat ip to 127.0.0.1:3000 | ||
} | ||
---SNIP--- | ||
``` |
Binary file added
BIN
+63.1 KB
...ion/feature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_1024x0_resize_q75_box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+107 KB
...ion/feature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_1320x0_resize_q75_box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+3.31 KB
...ature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_160x120_fill_q75_box_smart1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+9.48 KB
...ature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_320x240_fill_q75_box_smart1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+8.76 KB
...tion/feature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_330x0_resize_q75_box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+28.5 KB
...tion/feature_hu5459c0360c2b0cb7a147d2df0eb350ca_704370_660x0_resize_q75_box.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.