From 28b285b4791aece18fe1bbd76f3d555370545006 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Sun, 31 Oct 2021 21:24:40 +0100
Subject: zone_policy: T3873: Implement intra-zone-filtering
---
data/templates/zone_policy/nftables.tmpl | 4 +--
interface-definitions/zone-policy.xml.in | 49 ++++++++++++++++++++++++++++++++
python/vyos/template.py | 15 ++++++++++
src/conf_mode/zone_policy.py | 20 +++++++++++++
4 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/data/templates/zone_policy/nftables.tmpl b/data/templates/zone_policy/nftables.tmpl
index 4575a721c..21230c688 100644
--- a/data/templates/zone_policy/nftables.tmpl
+++ b/data/templates/zone_policy/nftables.tmpl
@@ -28,7 +28,7 @@ table ip filter {
}
{% else %}
chain VZONE_{{ zone_name }} {
- iifname { {{ zone_conf.interface | join(",") }} } counter return
+ iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=False) }}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.name is defined %}
{% if zone[from_zone].local_zone is not defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump {{ from_conf.firewall.name }}
@@ -62,7 +62,7 @@ table ip6 filter {
}
{% else %}
chain VZONE6_{{ zone_name }} {
- iifname { {{ zone_conf.interface | join(",") }} } counter return
+ iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=True) }}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is defined %}
{% if zone[from_zone].local_zone is not defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump {{ from_conf.firewall.ipv6_name }}
diff --git a/interface-definitions/zone-policy.xml.in b/interface-definitions/zone-policy.xml.in
index 52fd73f15..dd64c7c16 100644
--- a/interface-definitions/zone-policy.xml.in
+++ b/interface-definitions/zone-policy.xml.in
@@ -81,6 +81,55 @@
+
+
+ Intra-zone filtering
+
+
+
+
+ Action for intra-zone traffic
+
+ accept drop
+
+
+ accept
+ Accept traffic (default)
+
+
+ drop
+ Drop silently
+
+
+ ^(accept|drop)$
+
+
+
+
+
+ Use the specified firewall chain
+
+
+
+
+ IPv6 firewall ruleset
+
+ firewall ipv6-name
+
+
+
+
+
+ IPv4 firewall ruleset
+
+ firewall name
+
+
+
+
+
+
+
Zone to be local-zone
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 55bd04136..e20890e25 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -505,3 +505,18 @@ def nft_state_policy(conf, state):
out.append(conf['action'])
return " ".join(out)
+
+@register_filter('nft_intra_zone_action')
+def nft_intra_zone_action(zone_conf, ipv6=False):
+ if 'intra_zone_filtering' in zone_conf:
+ intra_zone = zone_conf['intra_zone_filtering']
+ fw_name = 'ipv6_name' if ipv6 else 'name'
+
+ if 'action' in intra_zone:
+ if intra_zone['action'] == 'accept':
+ return 'return'
+ return intra_zone['action']
+ elif dict_search_args(intra_zone, 'firewall', fw_name):
+ name = dict_search_args(intra_zone, 'firewall', fw_name)
+ return f'jump {name}'
+ return 'return'
diff --git a/src/conf_mode/zone_policy.py b/src/conf_mode/zone_policy.py
index 92f5624c2..2535ea33b 100755
--- a/src/conf_mode/zone_policy.py
+++ b/src/conf_mode/zone_policy.py
@@ -63,6 +63,8 @@ def verify(zone_policy):
raise ConfigError('There cannot be multiple local zones')
if 'interface' in zone_conf:
raise ConfigError('Local zone cannot have interfaces assigned')
+ if 'intra_zone_filtering' in zone_conf:
+ raise ConfigError('Local zone cannot use intra-zone-filtering')
local_zone = True
if 'interface' in zone_conf:
@@ -73,6 +75,24 @@ def verify(zone_policy):
interfaces += zone_conf['interface']
+ if 'intra_zone_filtering' in zone_conf:
+ intra_zone = zone_conf['intra_zone_filtering']
+
+ if len(intra_zone) > 1:
+ raise ConfigError('Only one intra-zone-filtering action must be specified')
+
+ if 'firewall' in intra_zone:
+ v4_name = dict_search_args(intra_zone, 'firewall', 'name')
+ if v4_name and not dict_search_args(zone_policy, 'firewall', 'name', v4_name):
+ raise ConfigError(f'Firewall name "{v4_name}" does not exist')
+
+ v6_name = dict_search_args(intra_zone, 'firewall', 'ipv6-name')
+ if v6_name and not dict_search_args(zone_policy, 'firewall', 'ipv6-name', v6_name):
+ raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist')
+
+ if not v4_name and not v6_name:
+ raise ConfigError('No firewall names specified for intra-zone-filtering')
+
if 'from' in zone_conf:
for from_zone, from_conf in zone_conf['from'].items():
v4_name = dict_search_args(from_conf, 'firewall', 'name')
--
cgit v1.2.3