Skip to content
This repository was archived by the owner on Aug 5, 2022. It is now read-only.

Commit dc1390c

Browse files
committed
nftables-settings-default: new package.
Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com>
1 parent 73f92df commit dc1390c

15 files changed

Lines changed: 373 additions & 0 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SUBSYSTEM=="net", ENV{SYSTEMD_WANTS}="network-device-event@$name.service"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Unit]
2+
Description=Create firewall config if it doesn't exist
3+
After=firewall-zones-update.service
4+
Requires=firewall-zones-update.service
5+
ConditionPathExists=!/run/firewall/firewall.ruleset
6+
7+
[Service]
8+
Type=oneshot
9+
ExecStart=/usr/bin/firewall-update.py
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[Unit]
2+
Description=Track changes to firewall zone ruleset and service chains
3+
# do not track paths before firewall service is enabled
4+
After=firewall-config-update.service
5+
# break down the ordering cycle with basic.target
6+
DefaultDependencies=false
7+
8+
[Path]
9+
ReloadOnTrigger=true
10+
PathChanged=/run/firewall/zones.ruleset
11+
PathChanged=/usr/lib/firewall/services
12+
PathChanged=/etc/firewall/services
13+
PathChanged=/usr/lib/firewall/zones.config
14+
PathChanged=/etc/firewall/zones.config
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=Update firewall settings
3+
4+
[Service]
5+
Type=simple
6+
7+
# We can run firewall-update.py even though this service might have been
8+
# activated via the same command. If there is no change, the
9+
# zones.ruleset file isn't changed.
10+
11+
ExecStart=/usr/bin/firewall-update.py
12+
ExecReload=/usr/bin/firewall-update.py
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
3+
# TODO: allow defining the zones on-the-fly based on the configuration
4+
5+
import os
6+
import sys
7+
import re
8+
import fcntl
9+
import configparser
10+
11+
zonesConfigPaths = ["/usr/lib/firewall/zones.config", "/etc/firewall/zones.config"]
12+
zonesTemplatePath = "/usr/lib/firewall/zones.template"
13+
zonesRulesetPath = "/run/firewall/zones.ruleset"
14+
servicePaths = ["/usr/lib/firewall/services", "/etc/firewall/services"]
15+
configTemplatePath = "/usr/lib/firewall/firewall.template"
16+
configRulesetPath = "/run/firewall/firewall.ruleset"
17+
18+
# lock to prevent processing several events at once
19+
lock = open("/run/firewall/config_flock", "w")
20+
fcntl.lockf(lock, fcntl.LOCK_EX)
21+
22+
# get available interfaces
23+
interfaces = os.listdir("/sys/class/net")
24+
25+
# map interfaces to zones according to configuration
26+
config = configparser.ConfigParser()
27+
files = config.read(zonesConfigPaths)
28+
29+
def search_interfaces(key, conf):
30+
ret = ""
31+
if "match" in conf:
32+
if key in conf["match"]:
33+
r = re.compile(conf["match"][key])
34+
ifs = ", ".join([i for i in interfaces if r.search(i)])
35+
ret = "elements = { " + ifs + " }"
36+
37+
return ret
38+
39+
# run regexps on the interfaces
40+
local_ifs = search_interfaces("ZONE_LOCAL", config)
41+
lan_ifs = search_interfaces("ZONE_LAN", config)
42+
wan_ifs = search_interfaces("ZONE_WAN", config)
43+
dmz_ifs = search_interfaces("ZONE_DMZ", config)
44+
vpn_ifs = search_interfaces("ZONE_VPN", config)
45+
all_ifs = search_interfaces("ZONE_ALL", config)
46+
47+
# read the zones template
48+
with open(zonesTemplatePath, "r") as f:
49+
data = f.read()
50+
51+
output_data = data.format(local_interfaces=local_ifs, lan_interfaces=lan_ifs,
52+
wan_interfaces=wan_ifs, dmz_interfaces=dmz_ifs,
53+
vpn_interfaces=vpn_ifs, all_interfaces=all_ifs)
54+
55+
# Do not write the ruleset file if it already exists and there is no change.
56+
# This prevents unneccessary firewall setup changes.
57+
58+
current_data = None
59+
60+
if os.path.exists(zonesRulesetPath):
61+
with open(zonesRulesetPath, "r", encoding="utf-8") as f:
62+
current_data = f.read()
63+
64+
if not current_data or current_data != output_data:
65+
# different file content, write the ruleset file
66+
with open(zonesRulesetPath, "w") as f:
67+
f.write(output_data)
68+
69+
if "--only-zones" in sys.argv:
70+
# configured to run only zone update
71+
sys.exit(0)
72+
73+
# read the firewall template
74+
with open(configTemplatePath, "r") as f:
75+
data = f.read()
76+
77+
serviceFiles = []
78+
for path in filter(os.path.exists, servicePaths):
79+
serviceFiles += [os.path.realpath(os.path.join(path, f)) for f in os.listdir(path)]
80+
81+
service_file_blob = "\n".join(['include "%s"' % f for f in serviceFiles])
82+
83+
output_data = data.format(service_chains=service_file_blob)
84+
85+
# write the ruleset file
86+
with open(configRulesetPath, "w") as f:
87+
f.write(output_data)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[Unit]
2+
Description=Create firewall zone configuration if it doesn't exist
3+
ConditionPathExists=!/run/firewall/zones.ruleset
4+
5+
[Service]
6+
ExecStart=/usr/bin/firewall-update.py --only-zones
7+
Type=oneshot
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# tmpfiles.d
2+
d /run/firewall 0600 root root - -
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Unit]
2+
Description=Track changes to firewall configuration
3+
4+
[Path]
5+
ReloadOnTrigger=true
6+
PathChanged=/run/firewall/firewall.ruleset
7+
8+
[Install]
9+
WantedBy=network.target
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[Unit]
2+
Description=nftables firewall
3+
DefaultDependencies=false
4+
Before=network-pre.target multi-user.target shutdown.target
5+
Conflicts=shutdown.target
6+
7+
# firewall-config-update makes sure that the firewall configuration has been created
8+
After=firewall-config-update.service
9+
# requires first-time update and also the configuration file tracking
10+
Requires=firewall-config-update.service
11+
Wants=firewall-config.path
12+
13+
[Service]
14+
Type=simple
15+
ExecStart=/usr/sbin/nft -I /run/firewall -I /usr/lib/firewall -f /run/firewall/firewall.ruleset
16+
ExecReload=/usr/sbin/nft -I /run/firewall -I /usr/lib/firewall -f /run/firewall/firewall.ruleset
17+
18+
[Install]
19+
WantedBy=network.target
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/sbin/nft
2+
3+
flush ruleset;
4+
5+
include "variables.ruleset"
6+
7+
table inet filter {{
8+
9+
include "zones.ruleset"
10+
11+
map tcp_service_map {{
12+
type inet_service : verdict
13+
}}
14+
15+
map udp_service_map {{
16+
type inet_service : verdict
17+
}}
18+
19+
chain input {{
20+
# Run this later than service and application scripts (priority 1)
21+
# and drop all packets that don't match to the the rules.
22+
type filter hook input priority 1; policy drop;
23+
24+
# Accept packets tagged by services and applications.
25+
mark $accept_packet accept;
26+
27+
# Accept packets belonging to established and related connections.
28+
ct state established,related accept;
29+
30+
# Allow packets to localhost interfaces.
31+
iif @ZONE_LOCAL accept;
32+
33+
# Check if the services have declared custom rules.
34+
tcp dport vmap @tcp_service_map;
35+
udp dport vmap @udp_service_map;
36+
37+
# Allow some icmpv6 to make IPv6 work (see RFC 4890). This
38+
# configuration is for an "end host firewall", protecting a
39+
# single device. In order to use the device as a router or as a
40+
# bridge, enable the relevant options as explained in the RFC.
41+
# For home gateway router use, see RFC 6092.
42+
43+
# Allow basic IPv6 functionality.
44+
ip6 nexthdr icmpv6 icmpv6 type {{
45+
destination-unreachable,
46+
packet-too-big,
47+
time-exceeded,
48+
parameter-problem,
49+
echo-request,
50+
echo-reply
51+
}} accept;
52+
53+
# Allow auto configuration support.
54+
ip6 nexthdr icmpv6 icmpv6 type {{
55+
nd-neighbor-solicit,
56+
nd-neighbor-advert,
57+
nd-router-advert,
58+
nd-router-solicit
59+
}} ip6 hoplimit 255 accept;
60+
61+
# Allow multicast listener discovery on link-local addresses.
62+
ip6 nexthdr icmpv6 icmpv6 type {{
63+
mld-listener-query,
64+
mld-listener-report,
65+
mld-listener-reduction
66+
}} ip6 saddr fe80::/10 accept;
67+
68+
# Allow multicast router discovery messages on link-local
69+
# addresses (hop limit 1).
70+
ip6 nexthdr icmpv6 icmpv6 type {{
71+
nd-router-advert,
72+
nd-router-solicit
73+
}} ip6 hoplimit 1 ip6 saddr fe80::/10 accept;
74+
}}
75+
}}
76+
77+
{service_chains}

0 commit comments

Comments
 (0)