[CentOS] Masquerading (packet forwarding) on CentOS 7

Thu Feb 19 12:19:17 UTC 2015
Dennis Jacobfeuerborn <dennisml at conversis.de>

On 19.02.2015 11:58, Niki Kovacs wrote:
> Hi,
> 
> I just migrated my office's server from Slackware64 14.1 to CentOS 7. So
> far everything's running fine, I just have a few minor details to work out.
> 
> I removed the firewalld package and replaced it by a simple Iptables
> script:
> 
> 
> --8<----------------------------------------------------
> #!/bin/sh
> #
> # firewall-lan.sh
> 
> IPT=$(which iptables)
> MOD=$(which modprobe)
> SYS=$(which sysctl)
> SERVICE=$(which service)
> 
> # Internet
> IFACE_INET=enp2s0
> 
> # Réseau local
> IFACE_LAN=enp3s0
> IFACE_LAN_IP=192.168.2.0/24
> 
> # Relais des paquets (yes/no)
> MASQ=yes
> 
> # Tout accepter
> $IPT -t filter -P INPUT ACCEPT
> $IPT -t filter -P FORWARD ACCEPT
> $IPT -t filter -P OUTPUT ACCEPT
> $IPT -t nat -P PREROUTING ACCEPT
> $IPT -t nat -P POSTROUTING ACCEPT
> $IPT -t nat -P OUTPUT ACCEPT
> $IPT -t mangle -P PREROUTING ACCEPT
> $IPT -t mangle -P INPUT ACCEPT
> $IPT -t mangle -P FORWARD ACCEPT
> $IPT -t mangle -P OUTPUT ACCEPT
> $IPT -t mangle -P POSTROUTING ACCEPT
> 
> # Remettre les compteurs à zéro
> $IPT -t filter -Z
> $IPT -t nat -Z
> $IPT -t mangle -Z
> 
> # Supprimer toutes les règles actives et les chaînes personnalisées
> $IPT -t filter -F
> $IPT -t filter -X
> $IPT -t nat -F
> $IPT -t nat -X
> $IPT -t mangle -F
> $IPT -t mangle -X
> 
> # Désactiver le relais des paquets
> $SYS -q -w net.ipv4.ip_forward=0
> 
> # Politique par défaut
> $IPT -P INPUT DROP
> $IPT -P FORWARD ACCEPT
> $IPT -P OUTPUT ACCEPT
> 
> # Faire confiance à nous-même
> $IPT -A INPUT -i lo -j ACCEPT
> 
> # Ping
> $IPT -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
> $IPT -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
> $IPT -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
> 
> # Connexions établies
> $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
> 
> # SSH local
> $IPT -A INPUT -p tcp -i $IFACE_LAN --dport 22 -j ACCEPT
> 
> # SSH limité en provenance de l'extérieur
> $IPT -A INPUT -p tcp -i $IFACE_INET --dport 22 -m state \
>  --state NEW -m recent --set --name SSH
> $IPT -A INPUT -p tcp -i $IFACE_INET --dport 22 -m state \
>  --state NEW -m recent --update --seconds 60 --hitcount 2 \
>  --rttl --name SSH -j DROP
> $IPT -A INPUT -p tcp -i $IFACE_INET --dport 22 -j ACCEPT
> 
> # DNS
> $IPT -A INPUT -p tcp -i $IFACE_LAN --dport 53 -j ACCEPT
> $IPT -A INPUT -p udp -i $IFACE_LAN --dport 53 -j ACCEPT
> 
> # DHCP
> $IPT -A INPUT -p udp -i $IFACE_LAN --dport 67:68 -j ACCEPT
> 
> # Activer le relais des paquets
> if [ $MASQ = 'yes' ]; then
>  $IPT -t nat -A POSTROUTING -o $IFACE_INET -s $IFACE_LAN_IP \
>    -j MASQUERADE
>  $SYS -q -w net.ipv4.ip_forward=1
> fi
> 
> # Enregistrer les connexions refusées
> $IPT -A INPUT -j LOG --log-prefix "+++ IPv4 packet rejected +++"
> $IPT -A INPUT -j REJECT
> 
> # Enregistrer la configuration
> $SERVICE iptables save
> --8<----------------------------------------------------
> 
> As you can see, the script is also supposed to handle IP packet
> forwarding (masquerading).
> 
> Once I run firewall-lan.sh manually, everything works as expected.
> 
> When I restart the server, Iptables rules are still the same. The only
> thing that's not activated is IP forwarding. So as far as I can tell,
> iptables rules are stored, but packet forwarding returns to its pristine
> state (not activated).
> 
> What would be an orthodox way of handling this? Put
> "net.ipv4.ip_forward=1" in /etc/sysctl.conf? Something else?

Hi,
on CentOS 7 you probably want to take advantage of the ability to put
multiple config files in /etc/sysctl.d. For example this is what
/etc/sysctl.d/50-network.conf looks like on one of my routers:

# cat /etc/sysctl.d/50-network.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.eth1.promote_secondaries = 1

The other thing i would recommend is to replace the iptables script with
the iptables-service package. That package uses iptables-restore to load
the iptables rules from /etc/sysconfig/iptables on boot and you can use
iptables-save to store the iptables rules there when you make changes.

The advantage of using iptables-save/restore is that it's more robust.
When you have a typo in your script then you end up with a
half-initialized firewall but when you use iptables-restore it parses
the specified file into a new kernel structure and then simply flips a
pointer to make that the active firewall configuration and deletes the
old one. That means if there is a problem with parsing the file
iptables-restore simply never switches to the new config i.e. during the
whole process the active firewall never gets touched and is never in an
half-initialized state. It also means that the switch is atomic i.e. The
complete old configuration is active until the moment the pointer gets
flipped at which point the whole new configuration gets active. The same
mechanism is also available for ipset using "ipset save" or "ipset restore".

Regards,
  Dennis