Requirements:
- Debian Linux
- Multiple network interfaces connected to WAN (for example using a switch, might also be possible using bridge and dummy interfaces in Linux)
- ISP that gives multiple IPs via DHCP
Configure the interfaces
File: /etc/network/interfaces , change the interface names to match yours.
# The loopback network interface
auto lo
iface lo inet loopback
# LAN Interface
allow-hotplug ens3
iface ens3 inet static
address 172.16.1.1
netmask 255.255.255.0
up /sbin/ip rule add 172.16.1.0/24 dev $IFACE table 10
up /sbin/ip rule add 172.16.1.0/24 dev $IFACE table 11
# WAN Interface 1
allow-hotplug ens5
iface ens5 inet manual
up /sbin/dhclient -4 -v -pf /run/dhclient.$IFACE.pid -lf /var/lib/dhcp/dhclient.$IFACE.leases -I -df /var/lib/dhcp/dhclient6.$IFACE.leases $IFACE
down /bin/kill $(cat /run/dhclient.$IFACE.pid)
# WAN Inetrface 2
allow-hotplug ens9
iface ens9 inet manual
up /sbin/dhclient -4 -v -pf /run/dhclient.$IFACE.pid -lf /var/lib/dhcp/dhclient.$IFACE.leases -I -df /var/lib/dhcp/dhclient6.$IFACE.leases $IFACE
down /bin/kill $(cat /run/dhclient.$IFACE.pid)
# WAN Interface 3
allow-hotplug ens10
iface ens10 inet manual
up /sbin/dhclient -4 -v -pf /run/dhclient.$IFACE.pid -lf /var/lib/dhcp/dhclient.$IFACE.leases -I -df /var/lib/dhcp/dhclient6.$IFACE.leases $IFACE
down /bin/kill $(cat /run/dhclient.$IFACE.pid)
Configure dhclient enter hooks to use multiple routing tables
File: /etc/dhcp/dhclient-enter-hooks.d/routing-tables , change the interface names to match yours.
RUN="yes"
if [ "$RUN" = "yes" ]; then
if [ "$interface" = "ens5" ]; then
echo "Main wan interface, not doing anything special" >> /tmp/dhclient-routing-tables.log
else
table=""
if [ "$interface" = "ens9" ]; then
table="10"
elif [ "$interface" = "ens10" ]; then
table="11"
fi
echo "Routing table $table" >> /tmp/dhclient-script.debug
if [ -n $table ]; then
if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
[ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then
if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ]; then
for router in $old_routers; do
echo "Removing default $router table $table" >> /tmp/dhclient-routing-tables.log
/sbin/ip route delete $router dev $interface table $table
/sbin/ip route delete default via $router dev $interface table $table
done
for router in $new_routers; do
echo "Adding default $router table $table" >> /tmp/dhclient-routing-tables.log
/sbin/ip route add $router dev $interface table $table
/sbin/ip route add default via $router dev $interface table $table
done
fi
if [ x$new_ip_address != x$old_ip_address ]; then
echo "ip rule add from $new_ip_address table $table" >> /tmp/dhclient-routing-tables.log
/sbin/ip rule del from $old_ip_address table $table
/sbin/ip rule add from $new_ip_address table $table
fi
fi
fi
new_routers=""
old_routers=""
fi
fi
Automatically update firewall when dhclient runs
File: /etc/dhcp/dhclient-exit-hooks.d/firewall
# Reload firewall in case ip has changed or such
RUN="yes"
if [ "$RUN" = "yes" ]; then
/etc/firewall.sh
fi
Configure the NAT and firewall
File: /etc/firewall.sh
#!/bin/bash
LAN_IF="ens3"
WAN_INTERFACE="ens5"
WAN2_INTERFACE="ens9"
WAN2_IP=$(ip addr show dev $WAN2_INTERFACE | grep 'inet ' |awk '{print $2}' | cut -f1 -d'/')
WAN3_INTERFACE="ens10"
WAN3_IP=$(ip addr show dev $WAN3_INTERFACE | grep 'inet ' |awk '{print $2}' | cut -f1 -d'/')
# Configure routing tables
ip rule delete fwmark 10 table 10
ip rule add fwmark 10 table 10
ip rule delete fwmark 11 table 11
ip rule add fwmark 11 table 11
ip route add 172.16.1.0/24 dev ens3 table 10
ip route add 172.16.1.0/24 dev ens3 table 11
# Configure firewall
iptables -F
iptables -F -t nat
iptables -F -t mangle
ip6tables -F
# Allow ICMP
iptables -A INPUT -p icmp -j ACCEPT
iptables -A FORWARD -p icmp -j ACCEPT
ip6tables -t filter -A INPUT -p icmpv6 -j ACCEPT
ip6tables -t filter -A FORWARD -p icmpv6 -j ACCEPT
# Allow SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow localhost
iptables -I INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
ip6tables -I INPUT -i lo -s ::1 -d ::1 -j ACCEPT
# Allow state
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# NAT Postrouting
# Allow to all from lan
iptables -A FORWARD -i $LAN_IF -o $WAN_INTERFACE -s 172.16.1.0/24 -j ACCEPT
iptables -A FORWARD -i $LAN_IF -o $WAN2_INTERFACE -s 172.16.1.10 -j ACCEPT
iptables -A FORWARD -i $LAN_IF -o $WAN3_INTERFACE -s 172.16.1.20 -j ACCEPT
# Special mangle for multiple routing tables
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN # return if already set
iptables -t mangle -A PREROUTING -i $WAN2_INTERFACE -j MARK --set-mark 10
iptables -t mangle -A PREROUTING -i $WAN3_INTERFACE -j MARK --set-mark 11
iptables -t mangle -A POSTROUTING -o $WAN2_INTERFACE -j MARK --set-mark 10
iptables -t mangle -A POSTROUTING -o $WAN3_INTERFACE -j MARK --set-mark 11
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
# HTTP/HTTPS on WAN2 to webserver
iptables -t nat -A PREROUTING -i $WAN2_INTERFACE -p tcp --dport 80 -j DNAT --to 172.16.1.11:80
iptables -t nat -A PREROUTING -i $WAN2_INTERFACE -p tcp --dport 443 -j DNAT --to 172.16.1.11:443
iptables -A FORWARD -p tcp --dport 80 -d 172.16.1.11 -j ACCEPT
iptables -A FORWARD -p tcp --dport 443 -d 172.16.1.11 -j ACCEPT
# Rest of WAN2 to 172.16.1.10
iptables -t nat -A POSTROUTING -o $WAN2_INTERFACE -s 172.16.1.10 -j SNAT --to-source $WAN2_IP
iptables -t nat -A PREROUTING -i $WAN2_INTERFACE -j DNAT --to-destination 172.16.1.10
iptables -t mangle -A PREROUTING -s 172.16.1.10 -j MARK --set-mark 10
# 1:1 NAT for WAN3
iptables -t nat -A POSTROUTING -o $WAN3_INTERFACE -s 172.16.1.20 -j SNAT --to-source $UWAN3_IP
iptables -t nat -A PREROUTING -i $WAN3_INTERFACE -j DNAT --to-destination 172.16.1.20
iptables -t mangle -A PREROUTING -s 172.16.1.20 -j MARK --set-mark 11
iptables -A FORWARD -p tcp --dport 22 -d 172.16.1.20 -j ACCEPT
# Masquerading
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
# Log the rest
iptables -t filter -A INPUT -j LOG
ip6tables -t filter -A INPUT -j LOG
iptables -A FORWARD -j LOG
ip6tables -A FORWARD -j LOG
# Default drop
iptables -P INPUT DROP
iptables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
Make script executable:
# chmod +x /etc/firewall.sh
Create systemd service for firewall
File: /etc/systemd/system/firewall.service
[Unit]
Description=Firewall
ConditionFileIsExecutable=/etc/firewall.sh
[Service]
Type=oneshot
ExecStart=/etc/firewall.sh
[Install]
WantedBy=basic.target
Enable service:
# systemctl enable firewall
Enable forwarding
File: /etc/sysctl.conf
net.ipv4.ip_forward=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
Completion
Reboot the system and verify functionality.