summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/firewall/nftables-defines.tmpl5
-rw-r--r--interface-definitions/firewall.xml.in21
-rw-r--r--interface-definitions/include/firewall/common-rule.xml.i3
-rw-r--r--interface-definitions/include/firewall/mac-group.xml.i10
-rw-r--r--interface-definitions/include/firewall/source-destination-group-ipv6.xml.i1
-rw-r--r--interface-definitions/include/firewall/source-destination-group.xml.i1
-rw-r--r--interface-definitions/include/policy/route-common-rule-ipv6.xml.i3
-rw-r--r--interface-definitions/include/policy/route-common-rule.xml.i3
-rw-r--r--python/vyos/firewall.py3
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py4
-rwxr-xr-xsrc/op_mode/firewall.py2
-rwxr-xr-xsrc/validators/mac-address-firewall27
12 files changed, 83 insertions, 0 deletions
diff --git a/data/templates/firewall/nftables-defines.tmpl b/data/templates/firewall/nftables-defines.tmpl
index 3578a9dc5..d9eb7c199 100644
--- a/data/templates/firewall/nftables-defines.tmpl
+++ b/data/templates/firewall/nftables-defines.tmpl
@@ -9,6 +9,11 @@ define A_{{ group_name }} = { {{ group_conf.address | join(",") }} }
define A6_{{ group_name }} = { {{ group_conf.address | join(",") }} }
{% endfor %}
{% endif %}
+{% if group.mac_group is defined %}
+{% for group_name, group_conf in group.mac_group.items() %}
+define M_{{ group_name }} = { {{ group_conf.mac_address | join(",") }} }
+{% endfor %}
+{% endif %}
{% if group.network_group is defined %}
{% for group_name, group_conf in group.network_group.items() %}
define N_{{ group_name }} = { {{ group_conf.network | join(",") }} }
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index fd98ae138..987ccaca6 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -144,6 +144,27 @@
</leafNode>
</children>
</tagNode>
+ <tagNode name="mac-group">
+ <properties>
+ <help>Firewall mac-group</help>
+ </properties>
+ <children>
+ #include <include/generic-description.xml.i>
+ <leafNode name="mac-address">
+ <properties>
+ <help>Mac-group member</help>
+ <valueHelp>
+ <format>&lt;MAC address&gt;</format>
+ <description>MAC address to match</description>
+ </valueHelp>
+ <constraint>
+ <validator name="mac-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
<tagNode name="network-group">
<properties>
<help>Firewall network-group</help>
diff --git a/interface-definitions/include/firewall/common-rule.xml.i b/interface-definitions/include/firewall/common-rule.xml.i
index 5ffbd639c..521fe54f2 100644
--- a/interface-definitions/include/firewall/common-rule.xml.i
+++ b/interface-definitions/include/firewall/common-rule.xml.i
@@ -176,6 +176,9 @@
<format>!&lt;MAC address&gt;</format>
<description>Match everything except the specified MAC address</description>
</valueHelp>
+ <constraint>
+ <validator name="mac-address-firewall"/>
+ </constraint>
</properties>
</leafNode>
#include <include/firewall/port.xml.i>
diff --git a/interface-definitions/include/firewall/mac-group.xml.i b/interface-definitions/include/firewall/mac-group.xml.i
new file mode 100644
index 000000000..dbce3fc88
--- /dev/null
+++ b/interface-definitions/include/firewall/mac-group.xml.i
@@ -0,0 +1,10 @@
+<!-- include start from firewall/mac-group.xml.i -->
+<leafNode name="mac-group">
+ <properties>
+ <help>Group of MAC addresses</help>
+ <completionHelp>
+ <path>firewall group mac-group</path>
+ </completionHelp>
+ </properties>
+</leafNode>
+<!-- include start from firewall/mac-group.xml.i --> \ No newline at end of file
diff --git a/interface-definitions/include/firewall/source-destination-group-ipv6.xml.i b/interface-definitions/include/firewall/source-destination-group-ipv6.xml.i
index 7815b78d4..c2cc7edb3 100644
--- a/interface-definitions/include/firewall/source-destination-group-ipv6.xml.i
+++ b/interface-definitions/include/firewall/source-destination-group-ipv6.xml.i
@@ -12,6 +12,7 @@
</completionHelp>
</properties>
</leafNode>
+ #include <include/firewall/mac-group.xml.i>
<leafNode name="network-group">
<properties>
<help>Group of networks</help>
diff --git a/interface-definitions/include/firewall/source-destination-group.xml.i b/interface-definitions/include/firewall/source-destination-group.xml.i
index 9a9bed0fe..ab11e89e9 100644
--- a/interface-definitions/include/firewall/source-destination-group.xml.i
+++ b/interface-definitions/include/firewall/source-destination-group.xml.i
@@ -12,6 +12,7 @@
</completionHelp>
</properties>
</leafNode>
+ #include <include/firewall/mac-group.xml.i>
<leafNode name="network-group">
<properties>
<help>Group of networks</help>
diff --git a/interface-definitions/include/policy/route-common-rule-ipv6.xml.i b/interface-definitions/include/policy/route-common-rule-ipv6.xml.i
index 735edbd48..406125e55 100644
--- a/interface-definitions/include/policy/route-common-rule-ipv6.xml.i
+++ b/interface-definitions/include/policy/route-common-rule-ipv6.xml.i
@@ -232,6 +232,9 @@
<format>!&lt;MAC address&gt;</format>
<description>Match everything except the specified MAC address</description>
</valueHelp>
+ <constraint>
+ <validator name="mac-address-firewall"/>
+ </constraint>
</properties>
</leafNode>
#include <include/firewall/port.xml.i>
diff --git a/interface-definitions/include/policy/route-common-rule.xml.i b/interface-definitions/include/policy/route-common-rule.xml.i
index 4452f78fc..33c4ba77c 100644
--- a/interface-definitions/include/policy/route-common-rule.xml.i
+++ b/interface-definitions/include/policy/route-common-rule.xml.i
@@ -232,6 +232,9 @@
<format>!&lt;MAC address&gt;</format>
<description>Match everything except the specified MAC address</description>
</valueHelp>
+ <constraint>
+ <validator name="mac-address-firewall"/>
+ </constraint>
</properties>
</leafNode>
#include <include/firewall/port.xml.i>
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index ad84393df..2ab78ff18 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -108,6 +108,9 @@ def parse_rule(rule_conf, fw_name, rule_id, ip_name):
elif 'network_group' in group:
group_name = group['network_group']
output.append(f'{ip_name} {prefix}addr $N{def_suffix}_{group_name}')
+ if 'mac_group' in group:
+ group_name = group['mac_group']
+ output.append(f'ether {prefix}addr $M_{group_name}')
if 'port_group' in group:
proto = rule_conf['protocol']
group_name = group['port_group']
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index c70743a9f..6b74e6c92 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -46,6 +46,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
def test_groups(self):
+ self.cli_set(['firewall', 'group', 'mac-group', 'smoketest_mac', 'mac-address', '00:01:02:03:04:05'])
self.cli_set(['firewall', 'group', 'network-group', 'smoketest_network', 'network', '172.16.99.0/24'])
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port', 'port', '53'])
self.cli_set(['firewall', 'group', 'port-group', 'smoketest_port', 'port', '123'])
@@ -54,6 +55,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'destination', 'group', 'port-group', 'smoketest_port'])
self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'protocol', 'tcp_udp'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'source', 'group', 'mac-group', 'smoketest_mac'])
self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest'])
@@ -62,6 +65,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_search = [
['iifname "eth0"', 'jump smoketest'],
['ip saddr { 172.16.99.0/24 }', 'ip daddr 172.16.10.10', 'th dport { 53, 123 }', 'return'],
+ ['ether saddr { 00:01:02:03:04:05 }', 'return']
]
nftables_output = cmd('sudo nft list table ip filter')
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 030a9b19a..b6bb5b802 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -272,6 +272,8 @@ def show_firewall_group(name=None):
row.append("\n".join(sorted(group_conf['address'], key=ipaddress.ip_address)))
elif 'network' in group_conf:
row.append("\n".join(sorted(group_conf['network'], key=ipaddress.ip_network)))
+ elif 'mac_address' in group_conf:
+ row.append("\n".join(sorted(group_conf['mac_address'])))
elif 'port' in group_conf:
row.append("\n".join(sorted(group_conf['port'])))
else:
diff --git a/src/validators/mac-address-firewall b/src/validators/mac-address-firewall
new file mode 100755
index 000000000..70551f86d
--- /dev/null
+++ b/src/validators/mac-address-firewall
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018-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/>.
+
+import re
+import sys
+
+pattern = "^!?([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$"
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ sys.exit(1)
+ if not re.match(pattern, sys.argv[1]):
+ sys.exit(1)
+ sys.exit(0)