summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/firewall/nftables-policy.j231
-rw-r--r--interface-definitions/include/interface/interface-policy-vif-c.xml.i26
-rw-r--r--interface-definitions/include/interface/interface-policy-vif.xml.i26
-rw-r--r--interface-definitions/include/interface/interface-policy.xml.i26
-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/policy-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/policy-route.xml.in2
-rwxr-xr-xsmoketest/scripts/cli/test_policy_route.py58
-rwxr-xr-xsrc/conf_mode/policy-route-interface.py132
-rwxr-xr-xsrc/conf_mode/policy-route.py106
-rwxr-xr-xsrc/helpers/vyos-domain-resolver.py4
-rwxr-xr-xsrc/migration-scripts/policy/4-to-592
-rwxr-xr-xsrc/op_mode/policy_route.py42
31 files changed, 154 insertions, 413 deletions
diff --git a/data/templates/firewall/nftables-policy.j2 b/data/templates/firewall/nftables-policy.j2
index 40118930b..6cb3b2f95 100644
--- a/data/templates/firewall/nftables-policy.j2
+++ b/data/templates/firewall/nftables-policy.j2
@@ -2,21 +2,24 @@
{% 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_mangle
+delete table ip6 vyos_mangle
{% endif %}
-
-table ip mangle {
-{% if first_install is vyos_defined %}
+table ip vyos_mangle {
chain VYOS_PBR_PREROUTING {
type filter hook prerouting priority -150; policy accept;
+{% if route is vyos_defined %}
+{% for route_text, conf in route.items() if conf.interface is vyos_defined %}
+ iifname { {{ ",".join(conf.interface) }} } counter jump VYOS_PBR_{{ route_text }}
+{% endfor %}
+{% endif %}
}
+
chain VYOS_PBR_POSTROUTING {
type filter hook postrouting priority -150; policy accept;
}
-{% endif %}
+
{% if route is vyos_defined %}
{% for route_text, conf in route.items() %}
chain VYOS_PBR_{{ route_text }} {
@@ -32,15 +35,20 @@ table ip mangle {
{{ group_tmpl.groups(firewall_group, False) }}
}
-table ip6 mangle {
-{% if first_install is vyos_defined %}
+table ip6 vyos_mangle {
chain VYOS_PBR6_PREROUTING {
type filter hook prerouting priority -150; policy accept;
+{% if route6 is vyos_defined %}
+{% for route_text, conf in route6.items() if conf.interface is vyos_defined %}
+ iifname { {{ ",".join(conf.interface) }} } counter jump VYOS_PBR6_{{ route_text }}
+{% endfor %}
+{% endif %}
}
+
chain VYOS_PBR6_POSTROUTING {
type filter hook postrouting priority -150; policy accept;
}
-{% endif %}
+
{% if route6 is vyos_defined %}
{% for route_text, conf in route6.items() %}
chain VYOS_PBR6_{{ route_text }} {
@@ -52,5 +60,6 @@ table ip6 mangle {
}
{% endfor %}
{% endif %}
+
{{ group_tmpl.groups(firewall_group, True) }}
}
diff --git a/interface-definitions/include/interface/interface-policy-vif-c.xml.i b/interface-definitions/include/interface/interface-policy-vif-c.xml.i
deleted file mode 100644
index 866fcd5c0..000000000
--- a/interface-definitions/include/interface/interface-policy-vif-c.xml.i
+++ /dev/null
@@ -1,26 +0,0 @@
-<!-- include start from interface/interface-policy-vif-c.xml.i -->
-<node name="policy" owner="${vyos_conf_scripts_dir}/policy-route-interface.py $VAR(../../../@).$VAR(../../@).$VAR(../@)">
- <properties>
- <priority>620</priority>
- <help>Policy route options</help>
- </properties>
- <children>
- <leafNode name="route">
- <properties>
- <help>IPv4 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="route6">
- <properties>
- <help>IPv6 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route6</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/interface/interface-policy-vif.xml.i b/interface-definitions/include/interface/interface-policy-vif.xml.i
deleted file mode 100644
index 83510fe59..000000000
--- a/interface-definitions/include/interface/interface-policy-vif.xml.i
+++ /dev/null
@@ -1,26 +0,0 @@
-<!-- include start from interface/interface-policy-vif.xml.i -->
-<node name="policy" owner="${vyos_conf_scripts_dir}/policy-route-interface.py $VAR(../../@).$VAR(../@)">
- <properties>
- <priority>620</priority>
- <help>Policy route options</help>
- </properties>
- <children>
- <leafNode name="route">
- <properties>
- <help>IPv4 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="route6">
- <properties>
- <help>IPv6 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route6</path>
- </completionHelp>
- </properties>
- </leafNode>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/interface/interface-policy.xml.i b/interface-definitions/include/interface/interface-policy.xml.i
deleted file mode 100644
index 42a8fd009..000000000
--- a/interface-definitions/include/interface/interface-policy.xml.i
+++ /dev/null
@@ -1,26 +0,0 @@
-<!-- include start from interface/interface-policy.xml.i -->
-<node name="policy" owner="${vyos_conf_scripts_dir}/policy-route-interface.py $VAR(../@)">
- <properties>
- <priority>620</priority>
- <help>Policy route options</help>
- </properties>
- <children>
- <leafNode name="route">
- <properties>
- <help>IPv4 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route</path>
- </completionHelp>
- </properties>
- </leafNode>
- <leafNode name="route6">
- <properties>
- <help>IPv6 policy route ruleset for interface</help>
- <completionHelp>
- <path>policy route6</path>
- </completionHelp>
- </properties>
- </leafNode>
- </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 916349ade..6d50d7238 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-policy-vif.xml.i>
<leafNode name="protocol">
<properties>
<help>Protocol used for service VLAN (default: 802.1ad)</help>
@@ -67,7 +66,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-policy-vif-c.xml.i>
</children>
</tagNode>
#include <include/interface/redirect.xml.i>
diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i
index 73a8c98ff..3f8f113ea 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-policy-vif.xml.i>
<leafNode name="egress-qos">
<properties>
<help>VLAN egress QoS</help>
diff --git a/interface-definitions/include/version/policy-version.xml.i b/interface-definitions/include/version/policy-version.xml.i
index 89bde20c7..f1494eaa3 100644
--- a/interface-definitions/include/version/policy-version.xml.i
+++ b/interface-definitions/include/version/policy-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/policy-version.xml.i -->
-<syntaxVersion component='policy' version='4'></syntaxVersion>
+<syntaxVersion component='policy' version='5'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in
index 41e4a68a8..96e0e5d89 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-policy.xml.i>
<leafNode name="hash-policy">
<properties>
<help>Bonding transmit hash policy</help>
diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in
index d633077d9..d52e213b6 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-policy.xml.i>
<leafNode name="forwarding-delay">
<properties>
<help>Forwarding delay</help>
diff --git a/interface-definitions/interfaces-dummy.xml.in b/interface-definitions/interfaces-dummy.xml.in
index fb36741f7..eb525b547 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-policy.xml.i>
<node name="ip">
<properties>
<help>IPv4 routing parameters</help>
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index 77f130e1c..e9ae0acfe 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-policy.xml.i>
<leafNode name="duplex">
<properties>
<help>Duplex mode</help>
diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in
index b959c787d..f8e9909f8 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-policy.xml.i>
<node name="parameters">
<properties>
<help>GENEVE tunnel parameters</help>
diff --git a/interface-definitions/interfaces-input.xml.in b/interface-definitions/interfaces-input.xml.in
index d01c760f8..97502d954 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-policy.xml.i>
#include <include/interface/redirect.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/interfaces-l2tpv3.xml.in b/interface-definitions/interfaces-l2tpv3.xml.in
index bde68dd5a..0ebc3253d 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-policy.xml.i>
<leafNode name="encapsulation">
<properties>
<help>Encapsulation type</help>
diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in
index 5c9f4cd76..441236ec2 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-policy.xml.i>
#include <include/interface/mirror.xml.i>
<node name="security">
<properties>
diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in
index 3876e31da..7cfb9ee7a 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-policy.xml.i>
<leafNode name="device-type">
<properties>
<help>OpenVPN interface device-type</help>
diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in
index 84f76a7ee..719060fa9 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-policy.xml.i>
#include <include/interface/no-default-route.xml.i>
#include <include/interface/default-route-distance.xml.i>
#include <include/interface/dhcpv6-options.xml.i>
diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in
index 4eb9bf111..2fe07ffd5 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-policy.xml.i>
<leafNode name="mode">
<properties>
<help>Receive mode (default: private)</help>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index fe49d337a..333a5b178 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-policy.xml.i>
<leafNode name="6rd-prefix">
<properties>
<help>6rd network prefix</help>
diff --git a/interface-definitions/interfaces-vti.xml.in b/interface-definitions/interfaces-vti.xml.in
index eeaea0dc3..11f001dc0 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-policy.xml.i>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index 4902ff36d..331f930d3 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-policy.xml.i>
<leafNode name="mtu">
<defaultValue>1450</defaultValue>
</leafNode>
diff --git a/interface-definitions/interfaces-wireguard.xml.in b/interface-definitions/interfaces-wireguard.xml.in
index 23f50d146..35e223588 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-policy.xml.i>
#include <include/interface/mirror.xml.i>
<leafNode name="mtu">
<defaultValue>1420</defaultValue>
diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in
index 9e7fc29bc..5271df624 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-policy.xml.i>
<node name="capabilities">
<properties>
<help>HT and VHT capabilities for your card</help>
diff --git a/interface-definitions/interfaces-wwan.xml.in b/interface-definitions/interfaces-wwan.xml.in
index b0b8367dc..758784540 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-policy.xml.i>
#include <include/interface/redirect.xml.i>
#include <include/interface/vrf.xml.i>
</children>
diff --git a/interface-definitions/policy-route.xml.in b/interface-definitions/policy-route.xml.in
index 44b96c2e6..48a5bf7d1 100644
--- a/interface-definitions/policy-route.xml.in
+++ b/interface-definitions/policy-route.xml.in
@@ -12,6 +12,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
+ #include <include/generic-interface-multi.xml.i>
#include <include/firewall/enable-default-log.xml.i>
<tagNode name="rule">
<properties>
@@ -65,6 +66,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
+ #include <include/generic-interface-multi.xml.i>
#include <include/firewall/enable-default-log.xml.i>
<tagNode name="rule">
<properties>
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 046e385bb..11b3c678e 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -42,18 +42,25 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
super(TestPolicyRoute, cls).tearDownClass()
def tearDown(self):
- self.cli_delete(['interfaces', 'ethernet', interface, 'policy'])
self.cli_delete(['policy', 'route'])
self.cli_delete(['policy', 'route6'])
self.cli_commit()
+ # Verify nftables cleanup
nftables_search = [
['set N_smoketest_network'],
['set N_smoketest_network1'],
['chain VYOS_PBR_smoketest']
]
- self.verify_nftables(nftables_search, 'ip mangle', inverse=True)
+ self.verify_nftables(nftables_search, 'ip vyos_mangle', inverse=True)
+
+ # Verify ip rule cleanup
+ ip_rule_search = [
+ ['fwmark ' + hex(table_mark_offset - int(table_id)), 'lookup ' + table_id]
+ ]
+
+ self.verify_rules(ip_rule_search, inverse=True)
def verify_nftables(self, nftables_search, table, inverse=False):
nftables_output = cmd(f'sudo nft list table {table}')
@@ -66,6 +73,17 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
break
self.assertTrue(not matched if inverse else matched, msg=search)
+ def verify_rules(self, rules_search, inverse=False):
+ rule_output = cmd('ip rule show')
+
+ for search in rules_search:
+ matched = False
+ for line in rule_output.split("\n"):
+ if all(item in line for item in search):
+ matched = True
+ break
+ self.assertTrue(not matched if inverse else matched, msg=search)
+
def test_pbr_group(self):
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network', 'network', '172.16.99.0/24'])
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network1', 'network', '172.16.101.0/24'])
@@ -74,8 +92,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'group', 'network-group', 'smoketest_network'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'group', 'network-group', 'smoketest_network1'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'mark', mark])
-
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
@@ -84,7 +101,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['ip daddr @N_smoketest_network1', 'ip saddr @N_smoketest_network'],
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
self.cli_delete(['firewall'])
@@ -92,8 +109,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'source', 'address', '172.16.20.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'mark', mark])
-
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
self.cli_commit()
@@ -104,7 +120,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['ip daddr 172.16.10.10', 'ip saddr 172.16.20.10', 'meta mark set ' + mark_hex],
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
def test_pbr_table(self):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'protocol', 'tcp'])
@@ -116,8 +132,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'set', 'table', table_id])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
+ self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface])
self.cli_commit()
@@ -130,7 +146,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['tcp flags syn / syn,ack', 'tcp dport 8888', 'meta mark set ' + mark_hex]
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
@@ -139,7 +155,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['meta l4proto { tcp, udp }', 'th dport 8888', 'meta mark set ' + mark_hex]
]
- self.verify_nftables(nftables6_search, 'ip6 mangle')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
# IP rule fwmark -> table
@@ -147,15 +163,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['fwmark ' + hex(table_mark_offset - int(table_id)), 'lookup ' + table_id]
]
- ip_rule_output = cmd('ip rule show')
-
- for search in ip_rule_search:
- matched = False
- for line in ip_rule_output.split("\n"):
- if all(item in line for item in search):
- matched = True
- break
- self.assertTrue(matched)
+ self.verify_rules(ip_rule_search)
def test_pbr_matching_criteria(self):
@@ -203,8 +211,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'dscp-exclude', '14-19'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '5', 'set', 'table', table_id])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
- self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
+ self.cli_set(['policy', 'route', 'smoketest', 'interface', interface])
+ self.cli_set(['policy', 'route6', 'smoketest6', 'interface', interface])
self.cli_commit()
@@ -220,7 +228,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['ip dscp { 0x29, 0x39-0x3b }', 'meta mark set ' + mark_hex]
]
- self.verify_nftables(nftables_search, 'ip mangle')
+ self.verify_nftables(nftables_search, 'ip vyos_mangle')
# IPv6
nftables6_search = [
@@ -232,7 +240,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['ip6 dscp != { 0x0e-0x13, 0x3d }', 'meta mark set ' + mark_hex]
]
- self.verify_nftables(nftables6_search, 'ip6 mangle')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_mangle')
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/policy-route-interface.py b/src/conf_mode/policy-route-interface.py
deleted file mode 100755
index 58c5fd93d..000000000
--- a/src/conf_mode/policy-route-interface.py
+++ /dev/null
@@ -1,132 +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.ifconfig import Section
-from vyos.template import render
-from vyos.util import cmd
-from vyos.util import run
-from vyos import ConfigError
-from vyos import airbag
-airbag.enable()
-
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- ifname = argv[1]
- ifpath = Section.get_config_path(ifname)
- if_policy_path = f'interfaces {ifpath} policy'
-
- if_policy = conf.get_config_dict(if_policy_path, key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- if_policy['ifname'] = ifname
- if_policy['policy'] = conf.get_config_dict(['policy'], key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- return if_policy
-
-def verify_chain(table, chain):
- # Verify policy route applied
- code = run(f'nft list chain {table} {chain}')
- return code == 0
-
-def verify(if_policy):
- # bail out early - looks like removal from running config
- if not if_policy:
- return None
-
- for route in ['route', 'route6']:
- if route in if_policy:
- if route not in if_policy['policy']:
- raise ConfigError('Policy route not configured')
-
- route_name = if_policy[route]
-
- if route_name not in if_policy['policy'][route]:
- raise ConfigError(f'Invalid policy route name "{name}"')
-
- nft_prefix = 'VYOS_PBR6_' if route == 'route6' else 'VYOS_PBR_'
- nft_table = 'ip6 mangle' if route == 'route6' else 'ip mangle'
-
- if not verify_chain(nft_table, nft_prefix + route_name):
- raise ConfigError('Policy route did not apply')
-
- return None
-
-def generate(if_policy):
- return None
-
-def cleanup_rule(table, chain, ifname, new_name=None):
- results = cmd(f'nft -a list chain {table} {chain}').split("\n")
- retval = None
- for line in results:
- if f'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:
- cmd(f'nft delete rule {table} {chain} handle {handle_search[1]}')
- return retval
-
-def apply(if_policy):
- ifname = if_policy['ifname']
-
- route_chain = 'VYOS_PBR_PREROUTING'
- ipv6_route_chain = 'VYOS_PBR6_PREROUTING'
-
- if 'route' in if_policy:
- name = 'VYOS_PBR_' + if_policy['route']
- rule_exists = cleanup_rule('ip mangle', route_chain, ifname, name)
-
- if not rule_exists:
- cmd(f'nft insert rule ip mangle {route_chain} iifname {ifname} counter jump {name}')
- else:
- cleanup_rule('ip mangle', route_chain, ifname)
-
- if 'route6' in if_policy:
- name = 'VYOS_PBR6_' + if_policy['route6']
- rule_exists = cleanup_rule('ip6 mangle', ipv6_route_chain, ifname, name)
-
- if not rule_exists:
- cmd(f'nft insert rule ip6 mangle {ipv6_route_chain} iifname {ifname} counter jump {name}')
- else:
- cleanup_rule('ip6 mangle', ipv6_route_chain, 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/policy-route.py b/src/conf_mode/policy-route.py
index 00539b9c7..1d016695e 100755
--- a/src/conf_mode/policy-route.py
+++ b/src/conf_mode/policy-route.py
@@ -15,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
from json import loads
from sys import exit
@@ -25,7 +24,6 @@ from vyos.config import Config
from vyos.template import render
from vyos.util import cmd
from vyos.util import dict_search_args
-from vyos.util import dict_search_recursive
from vyos.util import run
from vyos import ConfigError
from vyos import airbag
@@ -34,48 +32,13 @@ airbag.enable()
mark_offset = 0x7FFFFFFF
nftables_conf = '/run/nftables_policy.conf'
-ROUTE_PREFIX = 'VYOS_PBR_'
-ROUTE6_PREFIX = 'VYOS_PBR6_'
-
-preserve_chains = [
- 'VYOS_PBR_PREROUTING',
- 'VYOS_PBR_POSTROUTING',
- 'VYOS_PBR6_PREROUTING',
- 'VYOS_PBR6_POSTROUTING'
-]
-
valid_groups = [
'address_group',
+ 'domain_group',
'network_group',
'port_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'
-}
-
-def get_policy_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 'policy' in if_conf:
- output[prefix + ifname] = if_conf['policy']
- 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_config(config=None):
if config:
conf = config
@@ -88,7 +51,6 @@ def get_config(config=None):
policy['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,
no_tag_node_value_mangle=True)
- policy['interfaces'] = get_policy_interfaces(conf)
return policy
@@ -132,8 +94,8 @@ def verify_rule(policy, name, rule_conf, ipv6, rule_id):
side_conf = rule_conf[side]
if 'group' in side_conf:
- if {'address_group', 'network_group'} <= set(side_conf['group']):
- raise ConfigError('Only one address-group or network-group can be specified')
+ if len({'address_group', 'domain_group', 'network_group'} & set(side_conf['group'])) > 1:
+ raise ConfigError('Only one address-group, domain-group or network-group can be specified')
for group in valid_groups:
if group in side_conf['group']:
@@ -168,73 +130,11 @@ def verify(policy):
for rule_id, rule_conf in pol_conf['rule'].items():
verify_rule(policy, name, rule_conf, ipv6, rule_id)
- for ifname, if_policy in policy['interfaces'].items():
- name = dict_search_args(if_policy, 'route')
- ipv6_name = dict_search_args(if_policy, 'route6')
-
- if name and not dict_search_args(policy, 'route', name):
- raise ConfigError(f'Policy route "{name}" is still referenced on interface {ifname}')
-
- if ipv6_name and not dict_search_args(policy, 'route6', ipv6_name):
- raise ConfigError(f'Policy route6 "{ipv6_name}" is still referenced on interface {ifname}')
-
return None
-def cleanup_commands(policy):
- commands = []
- commands_chains = []
- commands_sets = []
- for table in ['ip mangle', 'ip6 mangle']:
- route_node = 'route' if table == 'ip mangle' else 'route6'
- chain_prefix = ROUTE_PREFIX if table == 'ip mangle' else ROUTE6_PREFIX
-
- 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 not chain.startswith("VYOS_PBR"):
- continue
-
- if dict_search_args(policy, route_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 not in preserve_chains:
- continue
-
- target, _ = next(dict_search_recursive(rule['expr'], 'target'))
-
- if target.startswith(chain_prefix):
- if dict_search_args(policy, route_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']
-
- 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(policy, '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
-
def generate(policy):
if not os.path.exists(nftables_conf):
policy['first_install'] = True
- else:
- policy['cleanup_commands'] = cleanup_commands(policy)
render(nftables_conf, 'firewall/nftables-policy.j2', policy)
return None
diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py
index 035c208b2..e31d9238e 100755
--- a/src/helpers/vyos-domain-resolver.py
+++ b/src/helpers/vyos-domain-resolver.py
@@ -35,13 +35,13 @@ cache = False
domain_state = {}
ipv4_tables = {
- 'ip mangle',
+ 'ip vyos_mangle',
'ip vyos_filter',
'ip vyos_nat'
}
ipv6_tables = {
- 'ip6 mangle',
+ 'ip6 vyos_mangle',
'ip6 vyos_filter'
}
diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
new file mode 100755
index 000000000..33c9e6ade
--- /dev/null
+++ b/src/migration-scripts/policy/4-to-5
@@ -0,0 +1,92 @@
+#!/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 policy nodes to policy route <name> interface <ifname>
+
+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()
+
+base4 = ['policy', 'route']
+base6 = ['policy', 'route6']
+config = ConfigTree(config_file)
+
+if not config.exists(base4) and not config.exists(base6):
+ # 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 + ['policy']):
+ return
+
+ if config.exists(if_path + ['policy', 'route']):
+ route_name = config.return_value(if_path + ['policy', 'route'])
+ config.set(base4 + [route_name, 'interface'], value=ifname_full, replace=False)
+
+ if config.exists(if_path + ['policy', 'route6']):
+ route_name = config.return_value(if_path + ['policy', 'route6'])
+ config.set(base6 + [route_name, 'interface'], value=ifname_full, replace=False)
+
+ config.delete(if_path + ['policy'])
+
+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)
diff --git a/src/op_mode/policy_route.py b/src/op_mode/policy_route.py
index 5be40082f..5953786f3 100755
--- a/src/op_mode/policy_route.py
+++ b/src/op_mode/policy_route.py
@@ -22,53 +22,13 @@ from vyos.config import Config
from vyos.util import cmd
from vyos.util import dict_search_args
-def get_policy_interfaces(conf, policy, name=None, ipv6=False):
- interfaces = conf.get_config_dict(['interfaces'], key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
-
- routes = ['route', 'route6']
-
- def parse_if(ifname, if_conf):
- if 'policy' in if_conf:
- for route in routes:
- if route in if_conf['policy']:
- route_name = if_conf['policy'][route]
- name_str = f'({ifname},{route})'
-
- if not name:
- policy[route][route_name]['interface'].append(name_str)
- elif not ipv6 and name == route_name:
- policy['interface'].append(name_str)
-
- for iftype in ['vif', 'vif_s', 'vif_c']:
- if iftype in if_conf:
- for vifname, vif_conf in if_conf[iftype].items():
- parse_if(f'{ifname}.{vifname}', vif_conf)
-
- for iftype, iftype_conf in interfaces.items():
- for ifname, if_conf in iftype_conf.items():
- parse_if(ifname, if_conf)
-
-def get_config_policy(conf, name=None, ipv6=False, interfaces=True):
+def get_config_policy(conf, name=None, ipv6=False):
config_path = ['policy']
if name:
config_path += ['route6' if ipv6 else 'route', name]
policy = conf.get_config_dict(config_path, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
- if policy and interfaces:
- if name:
- policy['interface'] = []
- else:
- if 'route' in policy:
- for route_name, route_conf in policy['route'].items():
- route_conf['interface'] = []
-
- if 'route6' in policy:
- for route_name, route_conf in policy['route6'].items():
- route_conf['interface'] = []
-
- get_policy_interfaces(conf, policy, name, ipv6)
return policy