summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/firewall/nftables.j272
-rw-r--r--data/templates/zone_policy/nftables.j2114
-rw-r--r--data/templates/zone_policy/nftables6.j277
-rw-r--r--interface-definitions/firewall.xml.in34
-rw-r--r--interface-definitions/include/firewall/name.xml.i18
-rw-r--r--interface-definitions/include/interface/interface-firewall-vif-c.xml.i79
-rw-r--r--interface-definitions/include/interface/interface-firewall-vif.xml.i79
-rw-r--r--interface-definitions/include/interface/interface-firewall.xml.i79
-rw-r--r--interface-definitions/include/interface/vif-s.xml.i2
-rw-r--r--interface-definitions/include/interface/vif.xml.i1
-rw-r--r--interface-definitions/include/version/firewall-version.xml.i2
-rw-r--r--interface-definitions/interfaces-bonding.xml.in1
-rw-r--r--interface-definitions/interfaces-bridge.xml.in1
-rw-r--r--interface-definitions/interfaces-dummy.xml.in1
-rw-r--r--interface-definitions/interfaces-ethernet.xml.in1
-rw-r--r--interface-definitions/interfaces-geneve.xml.in1
-rw-r--r--interface-definitions/interfaces-input.xml.in1
-rw-r--r--interface-definitions/interfaces-l2tpv3.xml.in1
-rw-r--r--interface-definitions/interfaces-macsec.xml.in1
-rw-r--r--interface-definitions/interfaces-openvpn.xml.in1
-rw-r--r--interface-definitions/interfaces-pppoe.xml.in1
-rw-r--r--interface-definitions/interfaces-pseudo-ethernet.xml.in1
-rw-r--r--interface-definitions/interfaces-tunnel.xml.in1
-rw-r--r--interface-definitions/interfaces-vti.xml.in1
-rw-r--r--interface-definitions/interfaces-vxlan.xml.in1
-rw-r--r--interface-definitions/interfaces-wireguard.xml.in1
-rw-r--r--interface-definitions/interfaces-wireless.xml.in1
-rw-r--r--interface-definitions/interfaces-wwan.xml.in1
-rw-r--r--interface-definitions/zone-policy.xml.in2
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py20
-rwxr-xr-xsrc/conf_mode/firewall-interface.py186
-rwxr-xr-xsrc/conf_mode/firewall.py193
-rwxr-xr-xsrc/conf_mode/zone_policy.py65
-rwxr-xr-xsrc/migration-scripts/firewall/7-to-888
34 files changed, 385 insertions, 743 deletions
diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2
index 5971e1bbc..3beb7fb92 100644
--- a/data/templates/firewall/nftables.j2
+++ b/data/templates/firewall/nftables.j2
@@ -2,24 +2,46 @@
{% import 'firewall/nftables-defines.j2' as group_tmpl %}
-{% if cleanup_commands is vyos_defined %}
-{% for command in cleanup_commands %}
-{{ command }}
-{% endfor %}
+{% if first_install is not vyos_defined %}
+delete table ip vyos_filter
{% endif %}
-
table ip filter {
-{% if first_install is vyos_defined %}
chain VYOS_FW_FORWARD {
type filter hook forward priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% if interface is vyos_defined %}
+{% for ifname, ifconf in interface.items() %}
+{% if ifconf.in is vyos_defined and ifconf.in.name is vyos_defined %}
+ iifname {{ ifname }} counter jump NAME_{{ ifconf.in.name }}
+{% endif %}
+{% if ifconf.out is vyos_defined and ifconf.out.name is vyos_defined %}
+ oifname {{ ifname }} counter jump NAME_{{ ifconf.out.name }}
+{% endif %}
+{% endfor %}
+{% endif %}
jump VYOS_POST_FW
}
chain VYOS_FW_LOCAL {
type filter hook input priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% if interface is vyos_defined %}
+{% for ifname, ifconf in interface.items() %}
+{% if ifconf.local is vyos_defined and ifconf.local.name is vyos_defined %}
+ iifname {{ ifname }} counter jump NAME_{{ ifconf.local.name }}
+{% endif %}
+{% endfor %}
+{% endif %}
jump VYOS_POST_FW
}
chain VYOS_FW_OUTPUT {
type filter hook output priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
jump VYOS_POST_FW
}
chain VYOS_POST_FW {
@@ -29,7 +51,6 @@ table ip filter {
type filter hook prerouting priority -450; policy accept;
ip frag-off & 0x3fff != 0 meta mark set 0xffff1 return
}
-{% endif %}
{% if name is vyos_defined %}
{% set ns = namespace(sets=[]) %}
{% for name_text, conf in name.items() %}
@@ -86,20 +107,51 @@ table ip filter {
return
}
{% endif %}
+{% if zone_conf is vyos_defined %}
+ include "{{ zone_conf }}"
+{% endif %}
}
+{% if first_install is not vyos_defined %}
+delete table ip6 vyos_filter
+{% endif %}
table ip6 filter {
-{% if first_install is vyos_defined %}
chain VYOS_FW6_FORWARD {
type filter hook forward priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% if interface is vyos_defined %}
+{% for ifname, ifconf in interface.items() %}
+{% if ifconf.in is vyos_defined and ifconf.in.ipv6_name is vyos_defined %}
+ iifname {{ ifname }} counter jump NAME6_{{ ifconf.in.ipv6_name }}
+{% endif %}
+{% if ifconf.out is vyos_defined and ifconf.out.ipv6_name is vyos_defined %}
+ oifname {{ ifname }} counter jump NAME6_{{ ifconf.out.ipv6_name }}
+{% endif %}
+{% endfor %}
+{% endif %}
jump VYOS_POST_FW6
}
chain VYOS_FW6_LOCAL {
type filter hook input priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% if interface is vyos_defined %}
+{% for ifname, ifconf in interface.items() %}
+{% if ifconf.local is vyos_defined and ifconf.local.ipv6_name is vyos_defined %}
+ iifname {{ ifname }} counter jump NAME6_{{ ifconf.local.ipv6_name }}
+{% endif %}
+{% endfor %}
+{% endif %}
jump VYOS_POST_FW6
}
chain VYOS_FW6_OUTPUT {
type filter hook output priority 0; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
jump VYOS_POST_FW6
}
chain VYOS_POST_FW6 {
@@ -109,7 +161,6 @@ table ip6 filter {
type filter hook prerouting priority -450; policy accept;
exthdr frag exists meta mark set 0xffff1 return
}
-{% endif %}
{% if ipv6_name is vyos_defined %}
{% set ns = namespace(sets=[]) %}
{% for name_text, conf in ipv6_name.items() %}
@@ -158,6 +209,9 @@ table ip6 filter {
return
}
{% endif %}
+{% if zone6_conf is vyos_defined %}
+ include "{{ zone6_conf }}"
+{% endif %}
}
{% if first_install is vyos_defined %}
diff --git a/data/templates/zone_policy/nftables.j2 b/data/templates/zone_policy/nftables.j2
index fe941f9f8..09140519f 100644
--- a/data/templates/zone_policy/nftables.j2
+++ b/data/templates/zone_policy/nftables.j2
@@ -1,13 +1,45 @@
#!/usr/sbin/nft -f
-{% if cleanup_commands is vyos_defined %}
-{% for command in cleanup_commands %}
-{{ command }}
-{% endfor %}
-{% endif %}
-
{% if zone is vyos_defined %}
-table ip filter {
+ chain VYOS_ZONE_FORWARD {
+ type filter hook forward priority -1; policy accept;
+{% if firewall.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv4 %}
+{% if 'local_zone' not in zone_conf %}
+ oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE_LOCAL {
+ type filter hook input priority -1; policy accept;
+{% if firewall.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv4 %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE_{{ zone_name }}_IN
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE_OUTPUT {
+ type filter hook output priority -1; policy accept;
+{% if firewall.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv4 %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE_{{ zone_name }}_OUT
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
{% for zone_name, zone_conf in zone.items() if zone_conf.ipv4 %}
{% if zone_conf.local_zone is vyos_defined %}
chain VZONE_{{ zone_name }}_IN {
@@ -42,72 +74,4 @@ table ip filter {
}
{% endif %}
{% endfor %}
-}
-
-table ip6 filter {
-{% for zone_name, zone_conf in zone.items() if zone_conf.ipv6 %}
-{% if zone_conf.local_zone is vyos_defined %}
- chain VZONE6_{{ zone_name }}_IN {
- iifname lo counter return
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
- {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
- }
- chain VZONE6_{{ zone_name }}_OUT {
- oifname lo counter return
-{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.ipv6_name is vyos_defined %}
- oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
- oifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
- {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
- }
-{% else %}
- chain VZONE6_{{ zone_name }} {
- iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=True) }}
-{% if zone_conf.intra_zone_filtering is vyos_defined %}
- iifname { {{ zone_conf.interface | join(",") }} } counter return
-{% endif %}
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
-{% if zone[from_zone].local_zone is not defined %}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
- iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endif %}
-{% endfor %}
- {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
- }
-{% endif %}
-{% endfor %}
-}
-
-{% for zone_name, zone_conf in zone.items() %}
-{% if zone_conf.ipv4 %}
-{% if 'local_zone' in zone_conf %}
-insert rule ip filter VYOS_FW_LOCAL counter jump VZONE_{{ zone_name }}_IN
-insert rule ip filter VYOS_FW_OUTPUT counter jump VZONE_{{ zone_name }}_OUT
-{% else %}
-insert rule ip filter VYOS_FW_FORWARD oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
-{% endif %}
-{% endif %}
-{% if zone_conf.ipv6 %}
-{% if 'local_zone' in zone_conf %}
-insert rule ip6 filter VYOS_FW6_LOCAL counter jump VZONE6_{{ zone_name }}_IN
-insert rule ip6 filter VYOS_FW6_OUTPUT counter jump VZONE6_{{ zone_name }}_OUT
-{% else %}
-insert rule ip6 filter VYOS_FW6_FORWARD oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE6_{{ zone_name }}
-{% endif %}
-{% endif %}
-{% endfor %}
-
-{# Ensure that state-policy rule is first in the chain #}
-{% if firewall.state_policy is vyos_defined %}
-{% for chain in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL'] %}
-insert rule ip filter {{ chain }} jump VYOS_STATE_POLICY
-{% endfor %}
-{% for chain in ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL'] %}
-insert rule ip6 filter {{ chain }} jump VYOS_STATE_POLICY6
-{% endfor %}
-{% endif %}
-
{% endif %}
diff --git a/data/templates/zone_policy/nftables6.j2 b/data/templates/zone_policy/nftables6.j2
new file mode 100644
index 000000000..f7123d63d
--- /dev/null
+++ b/data/templates/zone_policy/nftables6.j2
@@ -0,0 +1,77 @@
+#!/usr/sbin/nft -f
+
+{% if zone is vyos_defined %}
+ chain VYOS_ZONE6_FORWARD {
+ type filter hook forward priority -1; policy accept;
+{% if state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv6 %}
+{% if 'local_zone' not in zone_conf %}
+ oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE6_{{ zone_name }}
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE6_LOCAL {
+ type filter hook input priority -1; policy accept;
+{% if firewall.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv6 %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE6_{{ zone_name }}_IN
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE6_OUTPUT {
+ type filter hook output priority -1; policy accept;
+{% if firewall.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv6 %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE6_{{ zone_name }}_OUT
+{% endif %}
+{% endif %}
+{% endfor %}
+ }
+{% for zone_name, zone_conf in zone.items() if zone_conf.ipv6 %}
+{% if zone_conf.local_zone is vyos_defined %}
+ chain VZONE6_{{ zone_name }}_IN {
+ iifname lo counter return
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endfor %}
+ {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
+ }
+ chain VZONE6_{{ zone_name }}_OUT {
+ oifname lo counter return
+{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+ oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
+ oifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endfor %}
+ {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
+ }
+{% else %}
+ chain VZONE6_{{ zone_name }} {
+ iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=True) }}
+{% if zone_conf.intra_zone_filtering is vyos_defined %}
+ iifname { {{ zone_conf.interface | join(",") }} } counter return
+{% endif %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+{% if zone[from_zone].local_zone is not defined %}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endif %}
+{% endfor %}
+ {{ zone_conf | nft_default_rule('zone6_' + zone_name) }}
+ }
+{% endif %}
+{% endfor %}
+{% endif %}
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index d1497d572..fb24cd558 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -314,6 +314,40 @@
</tagNode>
</children>
</node>
+ <tagNode name="interface">
+ <properties>
+ <help>Interface name</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py</script>
+ </completionHelp>
+ </properties>
+ <children>
+ <node name="in">
+ <properties>
+ <help>Forwarded packets on inbound interface</help>
+ </properties>
+ <children>
+ #include <include/firewall/name.xml.i>
+ </children>
+ </node>
+ <node name="out">
+ <properties>
+ <help>Forwarded packets on outbound interface</help>
+ </properties>
+ <children>
+ #include <include/firewall/name.xml.i>
+ </children>
+ </node>
+ <node name="local">
+ <properties>
+ <help>Packets destined for this router</help>
+ </properties>
+ <children>
+ #include <include/firewall/name.xml.i>
+ </children>
+ </node>
+ </children>
+ </tagNode>
<leafNode name="ip-src-route">
<properties>
<help>Policy for handling IPv4 packets with source route option</help>
diff --git a/interface-definitions/include/firewall/name.xml.i b/interface-definitions/include/firewall/name.xml.i
new file mode 100644
index 000000000..231b9b144
--- /dev/null
+++ b/interface-definitions/include/firewall/name.xml.i
@@ -0,0 +1,18 @@
+<!-- include start from firewall/name.xml.i -->
+<leafNode name="name">
+ <properties>
+ <help>Local IPv4 firewall ruleset name for interface</help>
+ <completionHelp>
+ <path>firewall name</path>
+ </completionHelp>
+ </properties>
+</leafNode>
+<leafNode name="ipv6-name">
+ <properties>
+ <help>Local IPv6 firewall ruleset name for interface</help>
+ <completionHelp>
+ <path>firewall ipv6-name</path>
+ </completionHelp>
+ </properties>
+</leafNode>
+<!-- include end from firewall/name.xml.i --> \ No newline at end of file
diff --git a/interface-definitions/include/interface/interface-firewall-vif-c.xml.i b/interface-definitions/include/interface/interface-firewall-vif-c.xml.i
deleted file mode 100644
index 1bc235fcb..000000000
--- a/interface-definitions/include/interface/interface-firewall-vif-c.xml.i
+++ /dev/null
@@ -1,79 +0,0 @@
-<!-- include start from interface/interface-firewall-vif-c.xml.i -->
-<node name="firewall" owner="${vyos_conf_scripts_dir}/firewall-interface.py $VAR(../../../@).$VAR(../../@).$VAR(../@)">
- <properties>
- <priority>615</priority>
- <help>Firewall options</help>
- </properties>
- <children>
- <node name="in">
- <properties>
- <help>forwarded packets on inbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Inbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Inbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="out">
- <properties>
- <help>forwarded packets on outbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Outbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Outbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="local">
- <properties>
- <help>packets destined for this router</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Local IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Local IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/interface/interface-firewall-vif.xml.i b/interface-definitions/include/interface/interface-firewall-vif.xml.i
deleted file mode 100644
index a37ac5c4a..000000000
--- a/interface-definitions/include/interface/interface-firewall-vif.xml.i
+++ /dev/null
@@ -1,79 +0,0 @@
-<!-- include start from interface/interface-firewall-vif.xml.i -->
-<node name="firewall" owner="${vyos_conf_scripts_dir}/firewall-interface.py $VAR(../../@).$VAR(../@)">
- <properties>
- <priority>615</priority>
- <help>Firewall options</help>
- </properties>
- <children>
- <node name="in">
- <properties>
- <help>forwarded packets on inbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Inbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Inbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="out">
- <properties>
- <help>forwarded packets on outbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Outbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Outbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="local">
- <properties>
- <help>packets destined for this router</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Local IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Local IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/interface/interface-firewall.xml.i b/interface-definitions/include/interface/interface-firewall.xml.i
deleted file mode 100644
index b3f20c3bf..000000000
--- a/interface-definitions/include/interface/interface-firewall.xml.i
+++ /dev/null
@@ -1,79 +0,0 @@
-<!-- include start from interface/interface-firewall.xml.i -->
-<node name="firewall" owner="${vyos_conf_scripts_dir}/firewall-interface.py $VAR(../@)">
- <properties>
- <priority>615</priority>
- <help>Firewall options</help>
- </properties>
- <children>
- <node name="in">
- <properties>
- <help>forwarded packets on inbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Inbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Inbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="out">
- <properties>
- <help>forwarded packets on outbound interface</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Outbound IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Outbound IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="local">
- <properties>
- <help>packets destined for this router</help>
- </properties>
- <children>
- <leafNode name="name">
- <properties>
- <help>Local IPv4 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall name</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="ipv6-name">
- <properties>
- <help>Local IPv6 firewall ruleset name for interface</help>
- <completionHelp>
- <path>firewall ipv6-name</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/interface/vif-s.xml.i b/interface-definitions/include/interface/vif-s.xml.i
index c1af9f9e3..916349ade 100644
--- a/interface-definitions/include/interface/vif-s.xml.i
+++ b/interface-definitions/include/interface/vif-s.xml.i
@@ -18,7 +18,6 @@
#include <include/interface/dhcpv6-options.xml.i>
#include <include/interface/disable-link-detect.xml.i>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall-vif.xml.i>
#include <include/interface/interface-policy-vif.xml.i>
<leafNode name="protocol">
<properties>
@@ -68,7 +67,6 @@
#include <include/interface/mtu-68-16000.xml.i>
#include <include/interface/redirect.xml.i>
#include <include/interface/vrf.xml.i>
- #include <include/interface/interface-firewall-vif-c.xml.i>
#include <include/interface/interface-policy-vif-c.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i
index 57ef8d64c..73a8c98ff 100644
--- a/interface-definitions/include/interface/vif.xml.i
+++ b/interface-definitions/include/interface/vif.xml.i
@@ -18,7 +18,6 @@
#include <include/interface/dhcpv6-options.xml.i>
#include <include/interface/disable-link-detect.xml.i>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall-vif.xml.i>
#include <include/interface/interface-policy-vif.xml.i>
<leafNode name="egress-qos">
<properties>
diff --git a/interface-definitions/include/version/firewall-version.xml.i b/interface-definitions/include/version/firewall-version.xml.i
index 059a89f24..065925319 100644
--- a/interface-definitions/include/version/firewall-version.xml.i
+++ b/interface-definitions/include/version/firewall-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/firewall-version.xml.i -->
-<syntaxVersion component='firewall' version='7'></syntaxVersion>
+<syntaxVersion component='firewall' version='8'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in
index 8b6c6ef62..41e4a68a8 100644
--- a/interface-definitions/interfaces-bonding.xml.in
+++ b/interface-definitions/interfaces-bonding.xml.in
@@ -56,7 +56,6 @@
#include <include/interface/disable.xml.i>
#include <include/interface/vrf.xml.i>
#include <include/interface/mirror.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="hash-policy">
<properties>
diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in
index 48ee1efbc..1e11cd4c6 100644
--- a/interface-definitions/interfaces-bridge.xml.in
+++ b/interface-definitions/interfaces-bridge.xml.in
@@ -41,7 +41,6 @@
#include <include/interface/disable.xml.i>
#include <include/interface/vrf.xml.i>
#include <include/interface/mtu-68-16000.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="forwarding-delay">
<properties>
diff --git a/interface-definitions/interfaces-dummy.xml.in b/interface-definitions/interfaces-dummy.xml.in
index 01438de31..fb36741f7 100644
--- a/interface-definitions/interfaces-dummy.xml.in
+++ b/interface-definitions/interfaces-dummy.xml.in
@@ -19,7 +19,6 @@
#include <include/interface/address-ipv4-ipv6.xml.i>
#include <include/interface/description.xml.i>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<node name="ip">
<properties>
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index c821f04b2..ab65a93f3 100644
--- a/interface-definitions/interfaces-ethernet.xml.in
+++ b/interface-definitions/interfaces-ethernet.xml.in
@@ -31,7 +31,6 @@
</leafNode>
#include <include/interface/disable-link-detect.xml.i>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="duplex">
<properties>
diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in
index 6e8a8fee2..b959c787d 100644
--- a/interface-definitions/interfaces-geneve.xml.in
+++ b/interface-definitions/interfaces-geneve.xml.in
@@ -23,7 +23,6 @@
#include <include/interface/ipv6-options.xml.i>
#include <include/interface/mac.xml.i>
#include <include/interface/mtu-1450-16000.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<node name="parameters">
<properties>
diff --git a/interface-definitions/interfaces-input.xml.in b/interface-definitions/interfaces-input.xml.in
index 2164bfa4e..d01c760f8 100644
--- a/interface-definitions/interfaces-input.xml.in
+++ b/interface-definitions/interfaces-input.xml.in
@@ -19,7 +19,6 @@
<children>
#include <include/interface/description.xml.i>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
#include <include/interface/redirect.xml.i>
</children>
diff --git a/interface-definitions/interfaces-l2tpv3.xml.in b/interface-definitions/interfaces-l2tpv3.xml.in
index 6a85064cd..bde68dd5a 100644
--- a/interface-definitions/interfaces-l2tpv3.xml.in
+++ b/interface-definitions/interfaces-l2tpv3.xml.in
@@ -32,7 +32,6 @@
<defaultValue>5000</defaultValue>
</leafNode>
#include <include/interface/disable.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="encapsulation">
<properties>
diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in
index adb48813f..5c9f4cd76 100644
--- a/interface-definitions/interfaces-macsec.xml.in
+++ b/interface-definitions/interfaces-macsec.xml.in
@@ -21,7 +21,6 @@
#include <include/interface/dhcpv6-options.xml.i>
#include <include/interface/ipv4-options.xml.i>
#include <include/interface/ipv6-options.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
#include <include/interface/mirror.xml.i>
<node name="security">
diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in
index 6cbd91ff4..3876e31da 100644
--- a/interface-definitions/interfaces-openvpn.xml.in
+++ b/interface-definitions/interfaces-openvpn.xml.in
@@ -34,7 +34,6 @@
</children>
</node>
#include <include/interface/description.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="device-type">
<properties>
diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in
index 9674cfc0e..84f76a7ee 100644
--- a/interface-definitions/interfaces-pppoe.xml.in
+++ b/interface-definitions/interfaces-pppoe.xml.in
@@ -19,7 +19,6 @@
#include <include/pppoe-access-concentrator.xml.i>
#include <include/interface/authentication.xml.i>
#include <include/interface/dial-on-demand.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
#include <include/interface/no-default-route.xml.i>
#include <include/interface/default-route-distance.xml.i>
diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in
index 53e6445fa..4eb9bf111 100644
--- a/interface-definitions/interfaces-pseudo-ethernet.xml.in
+++ b/interface-definitions/interfaces-pseudo-ethernet.xml.in
@@ -28,7 +28,6 @@
#include <include/source-interface-ethernet.xml.i>
#include <include/interface/mac.xml.i>
#include <include/interface/mirror.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="mode">
<properties>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index 98ff878ba..fe49d337a 100644
--- a/interface-definitions/interfaces-tunnel.xml.in
+++ b/interface-definitions/interfaces-tunnel.xml.in
@@ -29,7 +29,6 @@
#include <include/source-address-ipv4-ipv6.xml.i>
#include <include/interface/tunnel-remote.xml.i>
#include <include/source-interface.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="6rd-prefix">
<properties>
diff --git a/interface-definitions/interfaces-vti.xml.in b/interface-definitions/interfaces-vti.xml.in
index aa83a04b2..eeaea0dc3 100644
--- a/interface-definitions/interfaces-vti.xml.in
+++ b/interface-definitions/interfaces-vti.xml.in
@@ -25,7 +25,6 @@
#include <include/interface/mirror.xml.i>
#include <include/interface/redirect.xml.i>
#include <include/interface/vrf.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index faa3dd5e0..4902ff36d 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -54,7 +54,6 @@
#include <include/interface/mac.xml.i>
#include <include/interface/mtu-1200-16000.xml.i>
#include <include/interface/mirror.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<leafNode name="mtu">
<defaultValue>1450</defaultValue>
diff --git a/interface-definitions/interfaces-wireguard.xml.in b/interface-definitions/interfaces-wireguard.xml.in
index 4a1b4ac68..23f50d146 100644
--- a/interface-definitions/interfaces-wireguard.xml.in
+++ b/interface-definitions/interfaces-wireguard.xml.in
@@ -21,7 +21,6 @@
#include <include/interface/disable.xml.i>
#include <include/port-number.xml.i>
#include <include/interface/mtu-68-16000.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
#include <include/interface/mirror.xml.i>
<leafNode name="mtu">
diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in
index daee770a9..9e7fc29bc 100644
--- a/interface-definitions/interfaces-wireless.xml.in
+++ b/interface-definitions/interfaces-wireless.xml.in
@@ -20,7 +20,6 @@
</properties>
<children>
#include <include/interface/address-ipv4-ipv6-dhcp.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
<node name="capabilities">
<properties>
diff --git a/interface-definitions/interfaces-wwan.xml.in b/interface-definitions/interfaces-wwan.xml.in
index 3071e6091..b0b8367dc 100644
--- a/interface-definitions/interfaces-wwan.xml.in
+++ b/interface-definitions/interfaces-wwan.xml.in
@@ -39,7 +39,6 @@
#include <include/interface/ipv4-options.xml.i>
#include <include/interface/ipv6-options.xml.i>
#include <include/interface/dial-on-demand.xml.i>
- #include <include/interface/interface-firewall.xml.i>
#include <include/interface/interface-policy.xml.i>
#include <include/interface/redirect.xml.i>
#include <include/interface/vrf.xml.i>
diff --git a/interface-definitions/zone-policy.xml.in b/interface-definitions/zone-policy.xml.in
index dc3408c3d..cf53e2bc8 100644
--- a/interface-definitions/zone-policy.xml.in
+++ b/interface-definitions/zone-policy.xml.in
@@ -3,7 +3,7 @@
<node name="zone-policy" owner="${vyos_conf_scripts_dir}/zone_policy.py">
<properties>
<help>Configure zone-policy</help>
- <priority>250</priority>
+ <priority>198</priority>
</properties>
<children>
<tagNode name="zone">
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 49d4d6170..cc436d4d0 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -36,8 +36,6 @@ sysfs_config = {
'twa_hazards_protection': {'sysfs': '/proc/sys/net/ipv4/tcp_rfc1337', 'default': '0', 'test_value': 'enable'}
}
-eth0_addr = '172.16.10.1/24'
-
class TestFirewall(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -47,15 +45,11 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
# out the current configuration :)
cls.cli_delete(cls, ['firewall'])
- cls.cli_set(cls, ['interfaces', 'ethernet', 'eth0', 'address', eth0_addr])
-
@classmethod
def tearDownClass(cls):
- cls.cli_delete(cls, ['interfaces', 'ethernet', 'eth0', 'address', eth0_addr])
super(TestFirewall, cls).tearDownClass()
def tearDown(self):
- self.cli_delete(['interfaces', 'ethernet', 'eth0', 'firewall'])
self.cli_delete(['firewall'])
self.cli_commit()
@@ -128,7 +122,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'action', 'accept'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'source', 'group', 'domain-group', 'smoketest_domain'])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest'])
+ self.cli_set(['firewall', 'interface', 'eth0', 'in', 'name', 'smoketest'])
self.cli_commit()
nftables_search = [
@@ -160,7 +154,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port1'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'protocol', 'tcp_udp'])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest'])
+ self.cli_set(['firewall', 'interface', 'eth0', 'in', 'name', 'smoketest'])
self.cli_commit()
@@ -216,7 +210,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', name, 'rule', '5', 'tcp', 'flags', 'syn'])
self.cli_set(['firewall', 'name', name, 'rule', '5', 'tcp', 'mss', mss_range])
- self.cli_set(['interfaces', 'ethernet', interface, 'firewall', 'in', 'name', name])
+ self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
self.cli_commit()
@@ -252,7 +246,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', name, 'rule', '7', 'dscp', '3-11'])
self.cli_set(['firewall', 'name', name, 'rule', '7', 'dscp-exclude', '21-25'])
- self.cli_set(['interfaces', 'ethernet', interface, 'firewall', 'in', 'name', name])
+ self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
self.cli_commit()
@@ -282,7 +276,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'protocol', 'tcp_udp'])
self.cli_set(['firewall', 'ipv6-name', name, 'rule', '2', 'destination', 'port', '8888'])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'ipv6-name', name])
+ self.cli_set(['firewall', 'interface', interface, 'in', 'ipv6-name', name])
self.cli_commit()
@@ -315,7 +309,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'dscp', '4-14'])
self.cli_set(['firewall', 'ipv6-name', name, 'rule', '4', 'dscp-exclude', '31-35'])
- self.cli_set(['interfaces', 'ethernet', interface, 'firewall', 'in', 'ipv6-name', name])
+ self.cli_set(['firewall', 'interface', interface, 'in', 'ipv6-name', name])
self.cli_commit()
@@ -364,7 +358,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', name, 'rule', '4', 'state', 'established', 'enable'])
self.cli_set(['firewall', 'name', name, 'rule', '4', 'connection-status', 'nat', 'source'])
- self.cli_set(['interfaces', 'ethernet', interface, 'firewall', 'in', 'name', name])
+ self.cli_set(['firewall', 'interface', interface, 'in', 'name', name])
self.cli_commit()
diff --git a/src/conf_mode/firewall-interface.py b/src/conf_mode/firewall-interface.py
deleted file mode 100755
index ab1c69259..000000000
--- a/src/conf_mode/firewall-interface.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2021 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import re
-
-from sys import argv
-from sys import exit
-
-from vyos.config import Config
-from vyos.configdict import leaf_node_changed
-from vyos.ifconfig import Section
-from vyos.template import render
-from vyos.util import cmd
-from vyos.util import dict_search_args
-from vyos.util import run
-from vyos import ConfigError
-from vyos import airbag
-airbag.enable()
-
-NAME_PREFIX = 'NAME_'
-NAME6_PREFIX = 'NAME6_'
-
-NFT_CHAINS = {
- 'in': 'VYOS_FW_FORWARD',
- 'out': 'VYOS_FW_FORWARD',
- 'local': 'VYOS_FW_LOCAL'
-}
-NFT6_CHAINS = {
- 'in': 'VYOS_FW6_FORWARD',
- 'out': 'VYOS_FW6_FORWARD',
- 'local': 'VYOS_FW6_LOCAL'
-}
-
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- ifname = argv[1]
- ifpath = Section.get_config_path(ifname)
- if_firewall_path = f'interfaces {ifpath} firewall'
-
- if_firewall = conf.get_config_dict(if_firewall_path, key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- if_firewall['ifname'] = ifname
- if_firewall['firewall'] = conf.get_config_dict(['firewall'], key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- return if_firewall
-
-def verify_chain(table, chain):
- # Verify firewall applied
- code = run(f'nft list chain {table} {chain}')
- return code == 0
-
-def verify(if_firewall):
- # bail out early - looks like removal from running config
- if not if_firewall:
- return None
-
- for direction in ['in', 'out', 'local']:
- if direction in if_firewall:
- if 'name' in if_firewall[direction]:
- name = if_firewall[direction]['name']
-
- if 'name' not in if_firewall['firewall']:
- raise ConfigError('Firewall name not configured')
-
- if name not in if_firewall['firewall']['name']:
- raise ConfigError(f'Invalid firewall name "{name}"')
-
- if not verify_chain('ip filter', f'{NAME_PREFIX}{name}'):
- raise ConfigError('Firewall did not apply')
-
- if 'ipv6_name' in if_firewall[direction]:
- name = if_firewall[direction]['ipv6_name']
-
- if 'ipv6_name' not in if_firewall['firewall']:
- raise ConfigError('Firewall ipv6-name not configured')
-
- if name not in if_firewall['firewall']['ipv6_name']:
- raise ConfigError(f'Invalid firewall ipv6-name "{name}"')
-
- if not verify_chain('ip6 filter', f'{NAME6_PREFIX}{name}'):
- raise ConfigError('Firewall did not apply')
-
- return None
-
-def generate(if_firewall):
- return None
-
-def cleanup_rule(table, chain, prefix, ifname, new_name=None):
- results = cmd(f'nft -a list chain {table} {chain}').split("\n")
- retval = None
- for line in results:
- if f'{prefix}ifname "{ifname}"' in line:
- if new_name and f'jump {new_name}' in line:
- # new_name is used to clear rules for any previously referenced chains
- # returns true when rule exists and doesn't need to be created
- retval = True
- continue
-
- handle_search = re.search('handle (\d+)', line)
- if handle_search:
- run(f'nft delete rule {table} {chain} handle {handle_search[1]}')
- return retval
-
-def state_policy_handle(table, chain):
- # Find any state-policy rule to ensure interface rules are only inserted afterwards
- results = cmd(f'nft -a list chain {table} {chain}').split("\n")
- for line in results:
- if 'jump VYOS_STATE_POLICY' in line:
- handle_search = re.search('handle (\d+)', line)
- if handle_search:
- return handle_search[1]
- return None
-
-def apply(if_firewall):
- ifname = if_firewall['ifname']
-
- for direction in ['in', 'out', 'local']:
- chain = NFT_CHAINS[direction]
- ipv6_chain = NFT6_CHAINS[direction]
- if_prefix = 'i' if direction in ['in', 'local'] else 'o'
-
- name = dict_search_args(if_firewall, direction, 'name')
- if name:
- rule_exists = cleanup_rule('ip filter', chain, if_prefix, ifname, f'{NAME_PREFIX}{name}')
-
- if not rule_exists:
- rule_action = 'insert'
- rule_prefix = ''
-
- handle = state_policy_handle('ip filter', chain)
- if handle:
- rule_action = 'add'
- rule_prefix = f'position {handle}'
-
- run(f'nft {rule_action} rule ip filter {chain} {rule_prefix} {if_prefix}ifname {ifname} counter jump {NAME_PREFIX}{name}')
- else:
- cleanup_rule('ip filter', chain, if_prefix, ifname)
-
- ipv6_name = dict_search_args(if_firewall, direction, 'ipv6_name')
- if ipv6_name:
- rule_exists = cleanup_rule('ip6 filter', ipv6_chain, if_prefix, ifname, f'{NAME6_PREFIX}{ipv6_name}')
-
- if not rule_exists:
- rule_action = 'insert'
- rule_prefix = ''
-
- handle = state_policy_handle('ip6 filter', ipv6_chain)
- if handle:
- rule_action = 'add'
- rule_prefix = f'position {handle}'
-
- run(f'nft {rule_action} rule ip6 filter {ipv6_chain} {rule_prefix} {if_prefix}ifname {ifname} counter jump {NAME6_PREFIX}{ipv6_name}')
- else:
- cleanup_rule('ip6 filter', ipv6_chain, if_prefix, ifname)
-
- return None
-
-if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- exit(1)
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index f0ea1a1e5..86793ba86 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -26,6 +26,7 @@ from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configdiff import get_config_diff, Diff
+# from vyos.configverify import verify_interface_exists
from vyos.firewall import geoip_update
from vyos.firewall import get_ips_domains_dict
from vyos.firewall import nft_add_set_elements
@@ -38,7 +39,7 @@ from vyos.util import cmd
from vyos.util import dict_search_args
from vyos.util import dict_search_recursive
from vyos.util import process_named_running
-from vyos.util import run
+from vyos.util import rc_cmd
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -47,7 +48,9 @@ airbag.enable()
policy_route_conf_script = '/usr/libexec/vyos/conf_mode/policy-route.py'
nftables_conf = '/run/nftables.conf'
-nftables_defines_conf = '/run/nftables_defines.conf'
+
+nftables_zone_conf = '/run/nftables_zone.conf'
+nftables6_zone_conf = '/run/nftables_zone6.conf'
sysfs_config = {
'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'enable': '0', 'disable': '1'},
@@ -63,28 +66,6 @@ sysfs_config = {
'twa_hazards_protection': {'sysfs': '/proc/sys/net/ipv4/tcp_rfc1337'}
}
-NAME_PREFIX = 'NAME_'
-NAME6_PREFIX = 'NAME6_'
-
-preserve_chains = [
- 'INPUT',
- 'FORWARD',
- 'OUTPUT',
- 'VYOS_FW_FORWARD',
- 'VYOS_FW_LOCAL',
- 'VYOS_FW_OUTPUT',
- 'VYOS_POST_FW',
- 'VYOS_FRAG_MARK',
- 'VYOS_FW6_FORWARD',
- 'VYOS_FW6_LOCAL',
- 'VYOS_FW6_OUTPUT',
- 'VYOS_POST_FW6',
- 'VYOS_FRAG6_MARK'
-]
-
-nft_iface_chains = ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL']
-nft6_iface_chains = ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']
-
valid_groups = [
'address_group',
'domain_group',
@@ -97,16 +78,6 @@ nested_group_types = [
'port_group', 'ipv6_address_group', 'ipv6_network_group'
]
-group_set_prefix = {
- 'A_': 'address_group',
- 'A6_': 'ipv6_address_group',
- 'D_': 'domain_group',
- 'M_': 'mac_group',
- 'N_': 'network_group',
- 'N6_': 'ipv6_network_group',
- 'P_': 'port_group'
-}
-
snmp_change_type = {
'unknown': 0,
'add': 1,
@@ -117,22 +88,6 @@ snmp_event_source = 1
snmp_trap_mib = 'VYATTA-TRAP-MIB'
snmp_trap_name = 'mgmtEventTrap'
-def get_firewall_interfaces(conf):
- out = {}
- interfaces = conf.get_config_dict(['interfaces'], key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
- def find_interfaces(iftype_conf, output={}, prefix=''):
- for ifname, if_conf in iftype_conf.items():
- if 'firewall' in if_conf:
- output[prefix + ifname] = if_conf['firewall']
- for vif in ['vif', 'vif_s', 'vif_c']:
- if vif in if_conf:
- output.update(find_interfaces(if_conf[vif], output, f'{prefix}{ifname}.'))
- return output
- for iftype, iftype_conf in interfaces.items():
- out.update(find_interfaces(iftype_conf))
- return out
-
def get_firewall_zones(conf):
used_v4 = []
used_v6 = []
@@ -159,6 +114,8 @@ def get_firewall_zones(conf):
ipv6_name = dict_search_args(zone_conf, 'intra_zone_filtering', 'firewall', 'ipv6_name')
if ipv6_name:
used_v6.append(ipv6_name)
+ else:
+ return None
return {'name': used_v4, 'ipv6_name': used_v6}
@@ -232,7 +189,6 @@ def get_config(config=None):
firewall['ipv6_name'][ipv6_name])
firewall['policy_resync'] = bool('group' in firewall or node_changed(conf, base + ['group']))
- firewall['interfaces'] = get_firewall_interfaces(conf)
firewall['zone_policy'] = get_firewall_zones(conf)
if 'config_trap' in firewall and firewall['config_trap'] == 'enable':
@@ -358,109 +314,42 @@ def verify(firewall):
for name in ['name', 'ipv6_name']:
if name in firewall:
for name_id, name_conf in firewall[name].items():
- if name_id in preserve_chains:
- raise ConfigError(f'Firewall name "{name_id}" is reserved for VyOS')
-
- if name_id.startswith("VZONE"):
- raise ConfigError(f'Firewall name "{name_id}" uses reserved prefix')
-
if 'rule' in name_conf:
for rule_id, rule_conf in name_conf['rule'].items():
verify_rule(firewall, rule_conf, name == 'ipv6_name')
- for ifname, if_firewall in firewall['interfaces'].items():
- for direction in ['in', 'out', 'local']:
- name = dict_search_args(if_firewall, direction, 'name')
- ipv6_name = dict_search_args(if_firewall, direction, 'ipv6_name')
+ if 'interface' in firewall:
+ for ifname, if_firewall in firewall['interface'].items():
+ # verify ifname needs to be disabled, dynamic devices come up later
+ # verify_interface_exists(ifname)
- if name and dict_search_args(firewall, 'name', name) == None:
- raise ConfigError(f'Firewall name "{name}" is still referenced on interface {ifname}')
+ for direction in ['in', 'out', 'local']:
+ name = dict_search_args(if_firewall, direction, 'name')
+ ipv6_name = dict_search_args(if_firewall, direction, 'ipv6_name')
- if ipv6_name and dict_search_args(firewall, 'ipv6_name', ipv6_name) == None:
- raise ConfigError(f'Firewall ipv6-name "{ipv6_name}" is still referenced on interface {ifname}')
+ if name and dict_search_args(firewall, 'name', name) == None:
+ raise ConfigError(f'Invalid firewall name "{name}" referenced on interface {ifname}')
- for fw_name, used_names in firewall['zone_policy'].items():
- for name in used_names:
- if dict_search_args(firewall, fw_name, name) == None:
- raise ConfigError(f'Firewall {fw_name.replace("_", "-")} "{name}" is still referenced in zone-policy')
+ if ipv6_name and dict_search_args(firewall, 'ipv6_name', ipv6_name) == None:
+ raise ConfigError(f'Invalid firewall ipv6-name "{ipv6_name}" referenced on interface {ifname}')
- return None
+ if firewall['zone_policy']:
+ for fw_name, used_names in firewall['zone_policy'].items():
+ for name in used_names:
+ if dict_search_args(firewall, fw_name, name) == None:
+ raise ConfigError(f'Firewall {fw_name.replace("_", "-")} "{name}" is still referenced in zone-policy')
-def cleanup_commands(firewall):
- commands = []
- commands_chains = []
- commands_sets = []
- for table in ['ip filter', 'ip6 filter']:
- name_node = 'name' if table == 'ip filter' else 'ipv6_name'
- chain_prefix = NAME_PREFIX if table == 'ip filter' else NAME6_PREFIX
- state_chain = 'VYOS_STATE_POLICY' if table == 'ip filter' else 'VYOS_STATE_POLICY6'
- iface_chains = nft_iface_chains if table == 'ip filter' else nft6_iface_chains
-
- geoip_list = []
- if firewall['geoip_updated']:
- geoip_key = 'deleted_ipv6_name' if table == 'ip6 filter' else 'deleted_name'
- geoip_list = dict_search_args(firewall, 'geoip_updated', geoip_key) or []
-
- json_str = cmd(f'nft -t -j list table {table}')
- obj = loads(json_str)
-
- if 'nftables' not in obj:
- continue
-
- for item in obj['nftables']:
- if 'chain' in item:
- chain = item['chain']['name']
- if chain in preserve_chains or chain.startswith("VZONE"):
- continue
-
- if chain == state_chain:
- command = 'delete' if 'state_policy' not in firewall else 'flush'
- commands_chains.append(f'{command} chain {table} {chain}')
- elif dict_search_args(firewall, name_node, chain.replace(chain_prefix, "", 1)) != None:
- commands.append(f'flush chain {table} {chain}')
- else:
- commands_chains.append(f'delete chain {table} {chain}')
-
- if 'rule' in item:
- rule = item['rule']
- chain = rule['chain']
- handle = rule['handle']
-
- if chain in iface_chains:
- target, _ = next(dict_search_recursive(rule['expr'], 'target'))
-
- if target == state_chain and 'state_policy' not in firewall:
- commands.append(f'delete rule {table} {chain} handle {handle}')
-
- if target.startswith(chain_prefix):
- if dict_search_args(firewall, name_node, target.replace(chain_prefix, "", 1)) == None:
- commands.append(f'delete rule {table} {chain} handle {handle}')
-
- if 'set' in item:
- set_name = item['set']['name']
-
- if set_name.startswith('GEOIP_CC_') and set_name in geoip_list:
- commands_sets.append(f'delete set {table} {set_name}')
- continue
-
- if set_name.startswith("RECENT_"):
- commands_sets.append(f'delete set {table} {set_name}')
- continue
-
- for prefix, group_type in group_set_prefix.items():
- if set_name.startswith(prefix):
- group_name = set_name.replace(prefix, "", 1)
- if dict_search_args(firewall, 'group', group_type, group_name) != None:
- commands_sets.append(f'flush set {table} {set_name}')
- else:
- commands_sets.append(f'delete set {table} {set_name}')
- return commands + commands_chains + commands_sets
+ return None
def generate(firewall):
if not os.path.exists(nftables_conf):
firewall['first_install'] = True
- else:
- firewall['cleanup_commands'] = cleanup_commands(firewall)
+
+ if os.path.exists(nftables_zone_conf):
+ firewall['zone_conf'] = nftables_zone_conf
+
+ if os.path.exists(nftables6_zone_conf):
+ firewall['zone6_conf'] = nftables6_zone_conf
render(nftables_conf, 'firewall/nftables.j2', firewall)
return None
@@ -521,26 +410,21 @@ def post_apply_trap(firewall):
cmd(base_cmd + ' '.join(objects))
-def state_policy_rule_exists():
- # Determine if state policy rules already exist in nft
- search_str = cmd(f'nft list chain ip filter VYOS_FW_FORWARD')
- return 'VYOS_STATE_POLICY' in search_str
-
def resync_policy_route():
# Update policy route as firewall groups were updated
- tmp = run(policy_route_conf_script)
+ tmp, out = rc_cmd(policy_route_conf_script)
if tmp > 0:
- Warning('Failed to re-apply policy route configuration!')
+ Warning(f'Failed to re-apply policy route configuration! {out}')
def apply(firewall):
if 'first_install' in firewall:
run('nfct helper add rpc inet tcp')
run('nfct helper add rpc inet udp')
run('nfct helper add tns inet tcp')
-
- install_result = run(f'nft -f {nftables_conf}')
+
+ install_result, output = rc_cmd(f'nft -f {nftables_conf}')
if install_result == 1:
- raise ConfigError('Failed to apply firewall')
+ raise ConfigError(f'Failed to apply firewall: {output}')
# set firewall group domain-group xxx
if 'group' in firewall:
@@ -563,13 +447,6 @@ def apply(firewall):
else:
call('systemctl stop vyos-domain-group-resolve.service')
- if 'state_policy' in firewall and not state_policy_rule_exists():
- for chain in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL']:
- cmd(f'nft insert rule ip filter {chain} jump VYOS_STATE_POLICY')
-
- for chain in ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL']:
- cmd(f'nft insert rule ip6 filter {chain} jump VYOS_STATE_POLICY6')
-
apply_sysfs(firewall)
if firewall['policy_resync']:
diff --git a/src/conf_mode/zone_policy.py b/src/conf_mode/zone_policy.py
index a52c52706..c6ab4e304 100755
--- a/src/conf_mode/zone_policy.py
+++ b/src/conf_mode/zone_policy.py
@@ -21,6 +21,7 @@ from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
+from vyos.configdiff import get_config_diff
from vyos.template import render
from vyos.util import cmd
from vyos.util import dict_search_args
@@ -30,7 +31,9 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
+firewall_conf_script = '/usr/libexec/vyos/conf_mode/firewall.py'
nftables_conf = '/run/nftables_zone.conf'
+nftables6_conf = '/run/nftables_zone6.conf'
def get_config(config=None):
if config:
@@ -47,6 +50,9 @@ def get_config(config=None):
get_first_key=True,
no_tag_node_value_mangle=True)
+ diff = get_config_diff(conf)
+ zone_policy['firewall_changed'] = diff.is_node_changed(['firewall'])
+
if 'zone' in zone_policy:
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
@@ -111,20 +117,12 @@ def verify(zone_policy):
raise ConfigError(f'Zone "{zone}" refers to a non-existent or deleted zone "{from_zone}"')
v4_name = dict_search_args(from_conf, 'firewall', 'name')
- if v4_name:
- if 'name' not in zone_policy['firewall']:
- raise ConfigError(f'Firewall name "{v4_name}" does not exist')
-
- if not dict_search_args(zone_policy, 'firewall', 'name', v4_name):
- raise ConfigError(f'Firewall name "{v4_name}" does not exist')
+ 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(from_conf, 'firewall', 'v6_name')
- if v6_name:
- if 'ipv6_name' not in zone_policy['firewall']:
- raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist')
-
- if not dict_search_args(zone_policy, 'firewall', 'ipv6_name', v6_name):
- raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist')
+ 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')
return None
@@ -152,37 +150,11 @@ def get_local_from(zone_policy, local_zone_name):
out[zone] = zone_conf['from'][local_zone_name]
return out
-def cleanup_commands():
- commands = []
- for table in ['ip filter', 'ip6 filter']:
- json_str = cmd(f'nft -t -j list table {table}')
- obj = loads(json_str)
- if 'nftables' not in obj:
- continue
- for item in obj['nftables']:
- if 'rule' in item:
- chain = item['rule']['chain']
- handle = item['rule']['handle']
- if 'expr' not in item['rule']:
- continue
- for expr in item['rule']['expr']:
- target = dict_search_args(expr, 'jump', 'target')
- if not target:
- continue
- if target.startswith("VZONE") or target.startswith("VYOS_STATE_POLICY"):
- commands.append(f'delete rule {table} {chain} handle {handle}')
- for item in obj['nftables']:
- if 'chain' in item:
- if item['chain']['name'].startswith("VZONE"):
- chain = item['chain']['name']
- commands.append(f'delete chain {table} {chain}')
- return commands
-
def generate(zone_policy):
data = zone_policy or {}
- if os.path.exists(nftables_conf): # Check to see if we've run before
- data['cleanup_commands'] = cleanup_commands()
+ if not os.path.exists(nftables_conf):
+ data['first_install'] = True
if 'zone' in data:
for zone, zone_conf in data['zone'].items():
@@ -193,12 +165,19 @@ def generate(zone_policy):
zone_conf['from_local'] = get_local_from(data, zone)
render(nftables_conf, 'zone_policy/nftables.j2', data)
+ render(nftables6_conf, 'zone_policy/nftables6.j2', data)
return None
+def update_firewall():
+ # Update firewall to refresh nftables
+ tmp = run(firewall_conf_script)
+ if tmp > 0:
+ Warning('Failed to update firewall configuration!')
+
def apply(zone_policy):
- install_result = run(f'nft -f {nftables_conf}')
- if install_result != 0:
- raise ConfigError('Failed to apply zone-policy')
+ # If firewall will not update in this commit, we need to call the conf script
+ if not zone_policy['firewall_changed']:
+ update_firewall()
return None
diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8
new file mode 100755
index 000000000..6929e20a5
--- /dev/null
+++ b/src/migration-scripts/firewall/7-to-8
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# T2199: Migrate interface firewall nodes to firewall interfaces <ifname> <direction> name/ipv6-name <name>
+
+import re
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+from vyos.ifconfig import Section
+
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['firewall']
+config = ConfigTree(config_file)
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None):
+ if_path = ['interfaces', iftype, ifname]
+ ifname_full = ifname
+
+ if vif:
+ if_path += ['vif', vif]
+ ifname_full = f'{ifname}.{vif}'
+ elif vifs:
+ if_path += ['vif-s', vifs]
+ ifname_full = f'{ifname}.{vifs}'
+ if vifc:
+ if_path += ['vif-c', vifc]
+ ifname_full = f'{ifname}.{vifs}.{vifc}'
+
+ if not config.exists(if_path + ['firewall']):
+ return
+
+ if not config.exists(['firewall', 'interface']):
+ config.set(['firewall', 'interface'])
+ config.set_tag(['firewall', 'interface'])
+
+ config.copy(if_path + ['firewall'], ['firewall', 'interface', ifname_full])
+ config.delete(if_path + ['firewall'])
+
+for iftype in config.list_nodes(['interfaces']):
+ for ifname in config.list_nodes(['interfaces', iftype]):
+ migrate_interface(config, iftype, ifname)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif']):
+ for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+ migrate_interface(config, iftype, ifname, vif=vif)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+ for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+ migrate_interface(config, iftype, ifname, vifs=vifs)
+
+ if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+ migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc)
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)