Firewall
This page is an extension of the firewall overview page of the user's guide.
It describes with more details how to manage and configure the firewall:
- Disable firewall over reboot
- Modify the firewall rules and persist the rules
We will not describe how iptables and ip6tables work since there is a lot of documentation available on internet but rather describe how they are integrated in the LORIX OS and how they can be managed from a system point of view.
Enable and disable firewall (persistent)
As described in the user's guide, the firewall service can be started and stopped for the current session.
Starting and stopping a service is however not really considered as "enabling/disabling" the service since it's just a temporary state.
On next reboot, the service will start as usual even if it has been stopped during the last session.
Starting or stopping a service doesn't make this action persistent over a reboot.
If you want to learn more about the "start/stop vs enable/disable" concept, please consult the more advanced service management documentation.
As a shortcut, the following section describes how to enable and disable the firewall over reboot, as a persistent state.
Enable the firewall at boot
The firewall is already configured to run at boot by default on the LORIX OS but if you have disabled this service, you can enable it again using the following command:
Enable the firewall at boot
sudo rc-update add iptables default
Result
lorix-one-aabbcc:~$ sudo rc-update add iptables default
* service iptables added to runlevel default
Enable the firewall at boot
sudo rc-update add ip6tables default
Result
lorix-one-aabbcc:~$ sudo rc-update add ip6tables default
* service ip6tables added to runlevel default
Enable is not start
Please note that enabling the service (start at boot) will not make it immediately start. You still need to run the command sudo rc-service <service> start
.
Disable the firewall at boot
You can avoid starting the firewall at boot with the following command:
Disable the firewall at boot
sudo rc-update del iptables default
Result
lorix-one-aabbcc:~$ sudo rc-update del iptables default
* service iptables removed from runlevel default
Disable the firewall at boot
sudo rc-update del ip6tables default
Result
lorix-one-aabbcc:~$ sudo rc-update del ip6tables default
* service ip6tables removed from runlevel default
Disable is not stop
Please note that disabling the service (no start at boot) will not make it immediately stop. You still need to run the command sudo rc-service <service> stop
.
Configure the firewall
Workflow and data state
As explained previously, the ip[6]tables rules are stored in the files /etc/iptables/ip[6]tables.rules
. When the firewall services are started, the iptables and ip6tables applications are loaded with the rules from these files.
There is then two ways of modifying the rules:
- Use directly iptables and ip6tables to modify the rules in memory and save the result in the files
This is the preferred way, the syntax follows documentation and rules are applied directly - Edit directly the rule files and restart the services to load the new rules
This is not the preferred way since the rule files use a specific syntax which is less documented
Modify the rules in place with iptables (preferred way)
Ensure firewall is running
To modify the rules using ip[6]tables, the corresponding service need to run first of all, if you stopped it, ensure it's running:
Enable the firewall
sudo rc-service iptables start
Enable the firewall
sudo rc-service ip6tables start
Edit the rules
You can then use standard iptables and ip6tables commands using available documentation on internet:
- Base documentation of the command: https://linux.die.net/man/8/iptables
- iptables How-to from Ubuntu: https://help.ubuntu.com/community/IptablesHowTo
Be careful when modifying the rules since they are immediately applied and some of them could stop connections like SSH.
Any firewall modification should always be done using the USB access or at least done when this access is possible.
For example, the following command display the actual running rules:
Show current firewall rules
sudo iptables -L -n -v --line-numbers
Result
gw150b2n7:~$ sudo iptables -L -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 1030 153K ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 /* Accept everything on loopback */
2 0 0 ACCEPT all -- usb0 * 0.0.0.0/0 0.0.0.0/0 /* Accept everything on usb0 */
3 2 104 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 state INVALID
4 0 0 ACCEPT all -- * * 127.0.0.1 127.0.0.1
5 0 0 DROP all -- !lo * 127.0.0.0/8 0.0.0.0/0
6 0 0 PINGPROTECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8 /* Must stay before ACCEPT for ESTABLISHED */
7 849 58967 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
8 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 3
9 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 11
10 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 12
11 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp spt:5353
12 1 60 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 flags:0x17/0x02 state NEW
13 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 flags:0x17/0x02 state NEW
14 0 0 SSHPROTECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW
15 79 10184 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 1748 packets, 244K bytes)
num pkts bytes target prot opt in out source destination
Chain PINGPROTECT (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 all -- * * 0.0.0.0/0 0.0.0.0/0 recent: SET name: PING side: source mask: 255.255.255.255 /* PING: Only 10 tries per source IP per second */
2 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 recent: UPDATE seconds: 1 hit_count: 10 TTL-Match name: PING side: source mask: 255.255.255.255
3 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0
Chain SSHPROTECT (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 all -- * * 0.0.0.0/0 0.0.0.0/0 recent: SET name: SSH side: source mask: 255.255.255.255 /* SSH: Only 4 tries per source IP per minute */
2 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 recent: UPDATE seconds: 60 hit_count: 4 name: SSH side: source mask: 255.255.255.255
3 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0
Show current firewall rules
sudo ip6tables -L -n -v --line-numbers
Result
gw150b2n7:~$ sudo ip6tables -L -n -v --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 8 944 ACCEPT all lo * ::/0 ::/0
2 0 0 DROP all * * ::/0 ::/0 state INVALID
3 0 0 ACCEPT all * * ::1 ::1
4 0 0 DROP all !lo * ::1 ::/0
5 0 0 PINGPROTECT icmpv6 * * ::/0 ::/0 ipv6-icmptype 128 /* Must stay before ACCEPT for ESTABLISHED */
6 0 0 ACCEPT all * * ::/0 ::/0 state RELATED,ESTABLISHED
7 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 1 /* RFC 4890 */
8 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 2 /* RFC 4890 */
9 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 3 /* RFC 4890 */
10 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 4 /* RFC 4890 */
11 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 133 HL match HL == 255 /* RFC 4890 */
12 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 134 HL match HL == 255 /* RFC 4890 */
13 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 135 HL match HL == 255 /* RFC 4890 */
14 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 136 HL match HL == 255 /* RFC 4890 */
15 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 137 HL match HL == 255 /* RFC 4890 */
16 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 141 HL match HL == 255 /* RFC 4890 */
17 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 142 HL match HL == 255 /* RFC 4890 */
18 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 130 /* RFC 4890 */
19 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 131 /* RFC 4890 */
20 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 132 /* RFC 4890 */
21 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 143 /* RFC 4890 */
22 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 148 HL match HL == 255 /* RFC 4890 */
23 0 0 ACCEPT icmpv6 * * ::/0 ::/0 ipv6-icmptype 149 HL match HL == 255 /* RFC 4890 */
24 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 151 HL match HL == 1 /* RFC 4890 */
25 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 152 HL match HL == 1 /* RFC 4890 */
26 0 0 ACCEPT icmpv6 * * fe80::/10 ::/0 ipv6-icmptype 153 HL match HL == 1 /* RFC 4890 */
27 8 1526 ACCEPT udp * * ::/0 ::/0 udp spt:5353
28 0 0 ACCEPT tcp * * ::/0 ::/0 tcp dpt:80 flags:0x17/0x02 state NEW
29 0 0 ACCEPT tcp * * ::/0 ::/0 tcp dpt:443 flags:0x17/0x02 state NEW
30 0 0 SSHPROTECT tcp * * ::/0 ::/0 tcp dpt:22 state NEW
31 19996 3869K DROP all * * ::/0 ::/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 191 packets, 10226 bytes)
num pkts bytes target prot opt in out source destination
Chain PINGPROTECT (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 all * * ::/0 ::/0 recent: SET name: PING side: source mask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff /* PING: Only 10 tries per source IP per second */
2 0 0 DROP all * * ::/0 ::/0 recent: UPDATE seconds: 1 hit_count: 10 TTL-Match name: PING side: source mask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
3 0 0 ACCEPT all * * ::/0 ::/0
Chain SSHPROTECT (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 all * * ::/0 ::/0 recent: SET name: SSH side: source mask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff /* SSH: Only 4 tries per source IP per minute */
2 0 0 DROP all * * ::/0 ::/0 recent: UPDATE seconds: 60 hit_count: 4 name: SSH side: source mask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
3 0 0 ACCEPT all * * ::/0 ::/0
Check the iptables documentation for the available commands for modifications.
E.g. to delete a rule, use (where 12 is the num of the rule from the previous output):
sudo iptables -D INPUT 12
Save the rules
Once you have done your modifications in the running rules, you can save them in the persistent rule files:
Save the rules
sudo rc-service iptables save
Result
lorix-one-aabbcc:~$ sudo rc-service iptables save
iptables | * Saving iptables state ...
Save the rules
sudo rc-service ip6tables save
Result
lorix-one-aabbcc:~$ sudo rc-service ip6tables save
ip6tables | * Saving ip6tables state ...
From there, the rules have been saved to the corresponding file and will be reloaded each time the firewall service is started.
No need to reload the service since the rules are already loaded in the firewall.
Modify the rule configuration files
Service state
The service doesn't need to be started or stopped at this point since we will only edit the rule file and reload it into the running service.
Modify the rule file
You can edit the rule files using your favorite editor:
Edit the rule file
sudo nano /etc/iptables/iptables.rules
Default file content
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:PINGPROTECT - [0:0]
:SSHPROTECT - [0:0]
# Accept everything on loopback
[0:0] -A INPUT -i lo -j ACCEPT
# Drop non-conforming packets, such as malformed headers, etc.
[0:0] -A INPUT -m state --state INVALID -j DROP
# Accept everything on localhost to localhost
[0:0] -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
# Block remote packets claiming to be from a loopback address.
[0:0] -A INPUT -s 127.0.0.0/8 ! -i lo -j DROP
# Accept ICMP (echo-request) before accept all ESTABLISHED connection
[0:0] -A INPUT -p icmp -m icmp --icmp-type echo-request -m comment --comment "Must stay before ACCEPT for ESTABLISHED" -j PINGPROTECT
# Accept already existing connections
[0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# Accept ICMP (destination-unreachable, time-exceeded, parameter-problem)
[0:0] -A INPUT -p icmp -m icmp --icmp-type destination-unreachable -j ACCEPT
[0:0] -A INPUT -p icmp -m icmp --icmp-type time-exceeded -j ACCEPT
[0:0] -A INPUT -p icmp -m icmp --icmp-type parameter-problem -j ACCEPT
# Accept mDNS
[0:0] -A INPUT -p udp -m udp --sport 5353 -j ACCEPT
# Accept HTTP and HTTPS
[0:0] -A INPUT -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT
[0:0] -A INPUT -p tcp -m tcp --dport 443 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT
# Accept SSH with brute force protection
[0:0] -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j SSHPROTECT
# Drop the rest for the INPUT chain
[0:0] -A INPUT -j DROP
# Manage ping protection PINGPROTECT chain
[0:0] -A PINGPROTECT -m recent --name PING --set --rsource -m comment --comment "PING: Only 10 tries per source IP per second"
[0:0] -A PINGPROTECT -m recent --name PING --update --seconds 1 --hitcount 10 --rttl --rsource -j DROP
[0:0] -A PINGPROTECT -j ACCEPT
# Manage SSH protection SSHPROTECT chain
[0:0] -A SSHPROTECT -m recent --set --name SSH --rsource -m comment --comment "SSH: Only 4 tries per source IP per minute"
[0:0] -A SSHPROTECT -m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j DROP
[0:0] -A SSHPROTECT -j ACCEPT
COMMIT
Edit the rule file
sudo nano /etc/iptables/ip6tables.rules
Default file content
# Generated by ip6tables-save v1.8.4 on Mon Aug 10 15:14:59 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [64:8779]
:PINGPROTECT - [0:0]
:SSHPROTECT - [0:0]
[0:0] -A INPUT -i lo -j ACCEPT
[0:0] -A INPUT -m state --state INVALID -j DROP
[0:0] -A INPUT -s ::1/128 -d ::1/128 -j ACCEPT
[0:0] -A INPUT -s ::1/128 ! -i lo -j DROP
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m comment --comment "Must stay before ACCEPT for ESTABLISHED" -j PINGPROTECT
[0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 1 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 2 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 3 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 4 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 137 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 141 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 142 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 130 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 131 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 132 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 143 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 148 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 149 -m hl --hl-eq 255 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 151 -m hl --hl-eq 1 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 152 -m hl --hl-eq 1 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -s fe80::/10 -p ipv6-icmp -m icmp6 --icmpv6-type 153 -m hl --hl-eq 1 -m comment --comment "RFC 4890" -j ACCEPT
[0:0] -A INPUT -p udp -m udp --sport 5353 -j ACCEPT
[0:0] -A INPUT -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT
[0:0] -A INPUT -p tcp -m tcp --dport 443 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT
[0:0] -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j SSHPROTECT
[0:0] -A INPUT -j DROP
[0:0] -A PINGPROTECT -m recent --set --name PING --mask ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff --rsource -m comment --comment "PING: Only 10 tries per source IP per second"
[0:0] -A PINGPROTECT -m recent --update --seconds 1 --hitcount 10 --rttl --name PING --mask ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff --rsource -j DROP
[0:0] -A PINGPROTECT -j ACCEPT
[0:0] -A SSHPROTECT -m recent --set --name SSH --mask ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff --rsource -m comment --comment "SSH: Only 4 tries per source IP per minute"
[0:0] -A SSHPROTECT -m recent --update --seconds 60 --hitcount 4 --name SSH --mask ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff --rsource -j DROP
[0:0] -A SSHPROTECT -j ACCEPT
COMMIT
# Completed on Mon Aug 10 15:14:59 2020
# Generated by ip6tables-save v1.8.4 on Mon Aug 10 15:14:59 2020
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [12:1350]
:POSTROUTING ACCEPT [12:1350]
COMMIT
As you can see, the content of the file is difficult to read and most of all, if you insert an error inside, ip[6]tables will not be able to load it:
Wrong format error
lorix-one-aabbcc:~$ sudo rc-service iptables start
iptables | * Loading iptables state and starting firewall ...
iptables |Bad argument `test'
iptables |Error occurred at line: 19
iptables |Try `iptables-restore -h' or 'iptables-restore --help' for more information. [ !! ]
iptables | * ERROR: iptables failed to start
Reload the rules into the firewall
The rules are persisted into the rule files but not loaded into the running application. To load them, you need to (re)start the firewall service:
Load the rules
sudo rc-service iptables restart
Result
lorix-one-aabbcc:~$ sudo rc-service iptables restart
iptables | * Stopping firewall ... [ ok ]
iptables | * Loading iptables state and starting firewall ...
Load the rules
sudo rc-service ip6tables restart
Result
lorix-one-aabbcc:~$ sudo rc-service ip6tables restart
ip6tables | * Stopping firewall ... [ ok ]
ip6tables | * Loading ip6tables state and starting firewall ...