From 0a5a78621b2b28f06af1f40c10ee8bb880f860a0 Mon Sep 17 00:00:00 2001 From: sarthurdev <965089+sarthurdev@users.noreply.github.com> Date: Tue, 18 Jan 2022 15:29:03 +0100 Subject: firewall: T3560: Add support for MAC address groups --- data/templates/firewall/nftables-defines.tmpl | 5 ++++ interface-definitions/firewall.xml.in | 21 +++++++++++++++++ .../include/firewall/common-rule.xml.i | 3 +++ .../include/firewall/mac-group.xml.i | 10 ++++++++ .../firewall/source-destination-group-ipv6.xml.i | 1 + .../firewall/source-destination-group.xml.i | 1 + .../include/policy/route-common-rule-ipv6.xml.i | 3 +++ .../include/policy/route-common-rule.xml.i | 3 +++ python/vyos/firewall.py | 3 +++ smoketest/scripts/cli/test_firewall.py | 4 ++++ src/op_mode/firewall.py | 2 ++ src/validators/mac-address-firewall | 27 ++++++++++++++++++++++ 12 files changed, 83 insertions(+) create mode 100644 interface-definitions/include/firewall/mac-group.xml.i create mode 100755 src/validators/mac-address-firewall 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 @@ + + + Firewall mac-group + + + #include + + + Mac-group member + + <MAC address> + MAC address to match + + + + + + + + + Firewall network-group 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 @@ !<MAC address> Match everything except the specified MAC address + + + #include 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 @@ + + + + Group of MAC addresses + + firewall group mac-group + + + + \ 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 @@ + #include Group of networks 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 @@ + #include Group of networks 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 @@ !<MAC address> Match everything except the specified MAC address + + + #include 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 @@ !<MAC address> Match everything except the specified MAC address + + + #include 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 . + +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) -- cgit v1.2.3