Skip to content

Instantly share code, notes, and snippets.

@drmalex07
Last active October 1, 2020 11:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save drmalex07/7712d4185b7651747932 to your computer and use it in GitHub Desktop.
Save drmalex07/7712d4185b7651747932 to your computer and use it in GitHub Desktop.
An example firewall based on an oneshot systemd service. #systemd #firewall #iptables

README

Define service

We define an oneshot service with a unit file /etc/systemd/system/firewall.service:

[Unit]
Description=Apply firewall rules
After=network.target

[Service]
Type=oneshot
EnvironmentFile=/etc/default/firewall
ExecStart=/root/scripts/firewall/setup-firewall.sh
RemainAfterExit=true
ExecStop=/root/scripts/firewall/teardown-firewall.sh
StandardOutput=journal

[Install]
WantedBy=multi-user.target

We provide an environment file so that both setup/teardown actions share a common environment.

An example /etc/default/firewall would be:

INTERNAL_IFACE="eth2"
INTERNAL_ADDR="192.168.5.3"
INTERNAL_NETWORK="192.168.5.0/24"

PUBLIC_ADDR=83.212.115.202
PUBLIC_IFACE=eth1

DNAT_MAP="30530:192.168.5.30:22 30531:192.168.5.31:22"

Define rulesets

Suppose we want to apply firewall rules incoming traffic to a foo service listening at tcp/9999.

Also, suppose we want to do some basic masquerading and forwarding.

An example setup script /root/scripts/firewall/setup-firewall.sh:

#!/bin/bash
echo "Setting up firewall ..."

# Applying firewall rules on INPUT and FORWARD chains

FOO_CLIENTS=10.0.3.15 10.0.3.16
iptables -N FOO
iptables -A INPUT -m tcp -p tcp -i ${PUBLIC_IFACE} --dport 9999 -j FOO
for addr in ${FOO_CLIENTS}; do
    iptables -A FOO -s ${addr}/32 -d -j RETURN # return to INPUT
done
iptables -A FOO -j REJECT # if not in allowed clients

# Masq packets going to external network

iptables -tnat -A POSTROUTING -m comment \
  --out-interface "${PUBLIC_IFACE}" --source "${INTERNAL_NETWORK}" -j MASQUERADE \
  --comment "Masquerade packets going to public (from internal network)"

# Forward TCP traffic for specific hosts of internal network

# DNAT_MAP is a space-separated list of <dport>:<internal-host>:<port>
for x in ${DNAT_MAP}; do 
    dport=${x%%:*}; 
    to=${x#*:}; 
    iptables -tnat -A PREROUTING -m tcp -p tcp \
       --in-interface "${PUBLIC_IFACE}" --dport "${dport}" -j DNAT --to-destination "${to}"
done 

An example teardown script /root/scripts/firewall/teardown-firewall.sh:

#!/bin/bash
echo "Tearing down firewall ..."

iptables -F FOO 
iptables -D INPUT -m tcp -p tcp -i ${PUBLIC_IFACE} --dport 9999 -j FOO
iptables -X FOO

iptables -tnat -F POSTROUTING
iptables -tnat -F PREROUTING
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment