diff options
author | sarthurdev <965089+sarthurdev@users.noreply.github.com> | 2022-01-18 15:29:03 +0100 |
---|---|---|
committer | sarthurdev <965089+sarthurdev@users.noreply.github.com> | 2022-01-18 20:35:03 +0100 |
commit | 0a5a78621b2b28f06af1f40c10ee8bb880f860a0 (patch) | |
tree | a984e64e7135923430bedcebefc4a824f4ff735b | |
parent | 385b72da4845e5c247aaeae9469ca04da216a4cb (diff) | |
download | vyos-1x-0a5a78621b2b28f06af1f40c10ee8bb880f860a0.tar.gz vyos-1x-0a5a78621b2b28f06af1f40c10ee8bb880f860a0.zip |
firewall: T3560: Add support for MAC address groups
-rw-r--r-- | data/templates/firewall/nftables-defines.tmpl | 5 | ||||
-rw-r--r-- | interface-definitions/firewall.xml.in | 21 | ||||
-rw-r--r-- | interface-definitions/include/firewall/common-rule.xml.i | 3 | ||||
-rw-r--r-- | interface-definitions/include/firewall/mac-group.xml.i | 10 | ||||
-rw-r--r-- | interface-definitions/include/firewall/source-destination-group-ipv6.xml.i | 1 | ||||
-rw-r--r-- | interface-definitions/include/firewall/source-destination-group.xml.i | 1 | ||||
-rw-r--r-- | interface-definitions/include/policy/route-common-rule-ipv6.xml.i | 3 | ||||
-rw-r--r-- | interface-definitions/include/policy/route-common-rule.xml.i | 3 | ||||
-rw-r--r-- | python/vyos/firewall.py | 3 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 4 | ||||
-rwxr-xr-x | src/op_mode/firewall.py | 2 | ||||
-rwxr-xr-x | src/validators/mac-address-firewall | 27 |
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><MAC address></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>!<MAC address></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>!<MAC address></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>!<MAC address></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) |