diff options
| -rwxr-xr-x | data/templates/firewall/nftables.j2 | 8 | ||||
| -rwxr-xr-x[-rw-r--r--] | interface-definitions/include/firewall/common-rule-bridge.xml.i | 1 | ||||
| -rwxr-xr-x[-rw-r--r--] | interface-definitions/include/firewall/global-options.xml.i | 6 | ||||
| -rwxr-xr-x | interface-definitions/include/firewall/match-ether-type.xml.i | 30 | ||||
| -rwxr-xr-x | python/vyos/firewall.py | 14 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 11 | 
6 files changed, 68 insertions, 2 deletions
| diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2 index 155b7f4d0..034328400 100755 --- a/data/templates/firewall/nftables.j2 +++ b/data/templates/firewall/nftables.j2 @@ -376,8 +376,14 @@ table bridge vyos_filter {  {%     if bridge.output is vyos_defined %}  {%         for prior, conf in bridge.output.items() %} -    chain VYOS_OUTUT_{{ prior }} { +    chain VYOS_OUTPUT_{{ prior }} {          type filter hook output priority {{ prior }}; policy accept; +{%             if global_options.apply_to_bridged_traffic is vyos_defined %} +{%                 if 'invalid_connections' in global_options.apply_to_bridged_traffic %} +        ct state invalid udp sport 67 udp dport 68 counter accept +        ct state invalid ether type arp counter accept +{%                 endif %} +{%             endif %}  {%             if global_options.state_policy is vyos_defined %}          jump VYOS_STATE_POLICY  {%             endif %} diff --git a/interface-definitions/include/firewall/common-rule-bridge.xml.i b/interface-definitions/include/firewall/common-rule-bridge.xml.i index 9ae28f7be..80088bbec 100644..100755 --- a/interface-definitions/include/firewall/common-rule-bridge.xml.i +++ b/interface-definitions/include/firewall/common-rule-bridge.xml.i @@ -10,6 +10,7 @@  #include <include/firewall/limit.xml.i>  #include <include/firewall/log.xml.i>  #include <include/firewall/log-options.xml.i> +#include <include/firewall/match-ether-type.xml.i>  #include <include/firewall/match-ipsec.xml.i>  #include <include/firewall/match-vlan.xml.i>  #include <include/firewall/nft-queue.xml.i> diff --git a/interface-definitions/include/firewall/global-options.xml.i b/interface-definitions/include/firewall/global-options.xml.i index cee8f1854..05fdd75cb 100644..100755 --- a/interface-definitions/include/firewall/global-options.xml.i +++ b/interface-definitions/include/firewall/global-options.xml.i @@ -49,6 +49,12 @@          <help>Apply configured firewall rules to traffic switched by bridges</help>        </properties>        <children> +        <leafNode name="invalid-connections"> +          <properties> +            <help>Accept ARP and DHCP despite they are marked as invalid connection</help> +            <valueless/> +          </properties> +        </leafNode>          <leafNode name="ipv4">            <properties>              <help>Apply configured IPv4 firewall rules</help> diff --git a/interface-definitions/include/firewall/match-ether-type.xml.i b/interface-definitions/include/firewall/match-ether-type.xml.i new file mode 100755 index 000000000..abfa9034d --- /dev/null +++ b/interface-definitions/include/firewall/match-ether-type.xml.i @@ -0,0 +1,30 @@ +<!-- include start from firewall/match-ether-type.xml.i --> +<leafNode name="ethernet-type"> +  <properties> +    <help>Ethernet type</help> +    <completionHelp> +      <list>802.1q 802.1ad arp ipv4 ipv6</list> +    </completionHelp> +    <valueHelp> +      <format>802.1q</format> +      <description>Customer VLAN tag type</description> +    </valueHelp> +    <valueHelp> +      <format>802.1ad</format> +      <description>Service VLAN tag type</description> +    </valueHelp> +    <valueHelp> +      <format>arp</format> +      <description>Adress Resolution Protocol</description> +    </valueHelp> +    <valueHelp> +      <format>_ipv4</format> +      <description>Internet Protocol version 4</description> +    </valueHelp> +    <valueHelp> +      <format>_ipv6</format> +      <description>Internet Protocol version 6</description> +    </valueHelp> +  </properties> +</leafNode> +<!-- include end --> diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index f0cf3c924..b1978c1fa 100755 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -151,6 +151,20 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):              proto = '{tcp, udp}'          output.append(f'meta l4proto {operator} {proto}') +    if 'ethernet_type' in rule_conf: +        ether_type_mapping = { +            '802.1q': '8021q', +            '802.1ad': '8021ad', +            'ipv6': 'ip6', +            'ipv4': 'ip', +            'arp': 'arp' +        } +        ether_type = rule_conf['ethernet_type'] +        operator = '!=' if ether_type.startswith('!') else '' +        ether_type = ether_type.lstrip('!') +        ether_type = ether_type_mapping.get(ether_type, ether_type) +        output.append(f'ether type {operator} {ether_type}') +      for side in ['destination', 'source']:          if side in rule_conf:              prefix = side[0] diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index b8031eed0..e4f9b14be 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -707,6 +707,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'group', 'ipv6-address-group', 'AGV6', 'address', '2001:db1::1'])          self.cli_set(['firewall', 'global-options', 'state-policy', 'established', 'action', 'accept'])          self.cli_set(['firewall', 'global-options', 'apply-to-bridged-traffic', 'ipv4']) +        self.cli_set(['firewall', 'global-options', 'apply-to-bridged-traffic', 'invalid-connections'])          self.cli_set(['firewall', 'bridge', 'name', name, 'default-action', 'accept'])          self.cli_set(['firewall', 'bridge', 'name', name, 'default-log']) @@ -731,6 +732,9 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'bridge', 'prerouting', 'filter', 'rule', '1', 'action', 'notrack'])          self.cli_set(['firewall', 'bridge', 'prerouting', 'filter', 'rule', '1', 'destination', 'group', 'ipv6-address-group', 'AGV6']) +        self.cli_set(['firewall', 'bridge', 'prerouting', 'filter', 'rule', '2', 'ethernet-type', 'arp']) +        self.cli_set(['firewall', 'bridge', 'prerouting', 'filter', 'rule', '2', 'action', 'accept']) +          self.cli_commit() @@ -750,9 +754,14 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):              ['chain VYOS_INPUT_filter'],              ['type filter hook input priority filter; policy accept;'],              ['ct state new', 'ip saddr 192.0.2.2', f'iifname "{interface_in}"', 'accept'], +            ['chain VYOS_OUTPUT_filter'], +            ['type filter hook output priority filter; policy accept;'], +            ['ct state invalid', 'udp sport 67', 'udp dport 68', 'accept'], +            ['ct state invalid', 'ether type arp', 'accept'],              ['chain VYOS_PREROUTING_filter'],              ['type filter hook prerouting priority filter; policy accept;'], -            ['ip6 daddr @A6_AGV6', 'notrack'] +            ['ip6 daddr @A6_AGV6', 'notrack'], +            ['ether type arp', 'accept']          ]          self.verify_nftables(nftables_search, 'bridge vyos_filter') | 
