I still love using IPTables rather than nft (that I need to learn better in a near future) and, to firewall rules in a production environment is always a risk thing. Wrong rules can lock you out or expose services you don’t want to.

Fortunately, Linux provides dummy interfaces: virtual network devices that behave like real Ethernet interfaces but have no hardware behind the scenes. Along with virtual machines they are perfect for simulating networks, testing iptables rules, and learning firewall concepts without affecting physical connectivity.

In this article, I will try to show five realistic scenarios where you could simulate them by just using Dummy Interfaces:

  • Basic packet filtering
  • Network Address Translation (NAT)
  • Port forwarding
  • Stateful firewall rules
  • Logging and monitoring

Prerequisites

  • A Linux with root access.
  • The iptables and iproute2 packages installed
  • IP forwarding enabled (for inter‑interface routing):
    sysctl -w net.ipv4.ip_forward=1
    

Creating Dummy Interfaces

To create dummy interfaces you just need to have the support for it loaded in your kernel, generally this happens by putting up the dummy module, after that we need to assign them an IP address and set the link UP.

modprobe dummy

ip link add dummy0 type dummy
ip link add dummy1 type dummy

ip addr add 10.10.1.1/24 dev dummy0
ip addr add 10.10.2.1/24 dev dummy1

ip link set dummy0 up
ip link set dummy1 up

1. Basic Filtering Between Two Networks

Here we can simulate two separate networks: Network A (10.10.1.0/24) on dummy0 and Network B (10.10.2.0/24) on dummy1. Our goal is to allow SSH (TCP/22) from A to B but block ICMP (ping).

iptables -P FORWARD DROP
iptables -F FORWARD

# Allow SSH
iptables -A FORWARD -i dummy0 -o dummy1 -p tcp --dport 22 -j ACCEPT
# Block ICMP
iptables -A FORWARD -i dummy0 -o dummy1 -p icmp -j DROP

iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Testing the rules

For all the tests here we use netcat (the swiss army knife of networking in unix systems) and of course ping (please check the article [reference] about network tools if you want to learn more) We can use ping and nc (netcat) to generate traffic.

Test ICMP (should be dropped)

Ping from 10.10.1.1 to 10.10.2.1:

ping -I 10.10.1.1 10.10.2.1

Test SSH (should be allowed)

# on one of your terminals
nc -l -s 10.10.2.1 -p 22

# on the second terminal
nc -s 10.10.1.1 10.10.2.1 22

2. Network Address Translator (NAT)

Now we treat dummy0 as an “internal” network (e.g., 10.10.1.0/24) and dummy1 as the “external” network (e.g., 10.10.2.0/24). We want internal hosts to access external resources, but we’ll hide them behind the dummy1 IP using source NAT (masquerade).

iptables -t nat -A POSTROUTING -o dummy1 -j MASQUERADE

iptables -A FORWARD -i dummy0 -o dummy1 -j ACCEPT
iptables -A FORWARD -i dummy1 -o dummy0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Testing it:

# on one of your terminals
nc -l -s 10.10.2.1 -p 8080

# on the second terminal
nc -s 10.10.1.100 10.10.2.1 8080

The connection works and the source IP will appear as 10.10.2.1 (the dummy1 interface) because it masquerade the IP. To check it:

# on one of your terminals
tcpdump -i dummy0 -s 0 -nn

# on the second terminal
tcpdump -i dummy1 -s 0 -nn

3. Port Forwarding (DNAT)

Sometimes (this happens frequently in Kubernetes services) we want to forward incoming connections on a port X to an external service on port Y, on this scenario we will also move the request to a different interface, from a 8080 port on dummy1 to an internal server on port 80 of dummy0. This simulates a typical port forwarding

iptables -t nat -A PREROUTING -i dummy1 -p tcp --dport 8080 -j DNAT --to-destination 10.10.1.100:80

iptables -A FORWARD -i dummy1 -o dummy0 -p tcp --dport 80 -j ACCEPT
iptables -A FORWARD -i dummy0 -o dummy1 -m state --state ESTABLISHED,RELATED -j ACCEPT

Testing it:

# on one of your terminals
ip addr add 10.10.1.100/24 dev dummy0   # additional IP on dummy0
nc -l -s 10.10.1.100 -p 80

# on the second terminal
nc 10.10.2.1 8080

4. Stateful Firewall

We’ll demonstrate how connection tracking allows replies but blocks new connections from the external side. We’ll allow internal hosts to initiate any connection to external, but block any new connection attempts from external.

iptables -P FORWARD DROP

iptables -A FORWARD -i dummy0 -o dummy1 -m state --state NEW -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Testing it:

# on one of your terminals
nc -s 10.10.1.1 10.10.2.1 9999   # assume listener on dummy1 port 9999

# on the second terminal
nc -s 10.10.2.1 10.10.1.1 9999

iptables -L FORWARD -v

The initial connection should work because the NEW packet is allowed but the second one should be blocked and it can see by the use of iptables -L

5. Logging

When we are creating new firewall rules and our rules are so big we often need some type of debugging, for that there is nothing better than log the packets and see them rolling into the logs.

iptables -N LOG_DROP
iptables -A LOG_DROP -j LOG --log-prefix "FW-DROP: " --log-level 4
iptables -A LOG_DROP -j DROP

This should log all the DROP connections with the prefix FW-DROP.

# Set policy to ACCEPT temporarily (or keep DROP and add a final rule)
iptables -P FORWARD ACCEPT   # easier for demonstration
iptables -F FORWARD
iptables -A FORWARD -i dummy0 -o dummy1 -p tcp --dport 22 -j ACCEPT
iptables -A FORWARD -j LOG_DROP   # log and drop everything else

As you can see you can also log only specific packets, on this case all the DROP connections with exception of SSH connections. Testing it:

ping -I 10.10.2.1 10.10.1.1
tail -f /var/log/kern.log   # or journalctl -f

The results would probably be like this:

kernel: FW-DROP: IN=dummy1 OUT=dummy0 ... PROTO=ICMP ...

This technique is a life saver for validate your firewall rules.


So thats it folks! I hope you enjoy and use dummy interfaces in a clever way to test your firewall rules whenever you need.