diff options
4 files changed, 47 insertions, 12 deletions
| diff --git a/interface-definitions/include/constraint/interface-name-with-wildcard-and-inverted.xml.i b/interface-definitions/include/constraint/interface-name-with-wildcard-and-inverted.xml.i new file mode 100644 index 000000000..6a39041a3 --- /dev/null +++ b/interface-definitions/include/constraint/interface-name-with-wildcard-and-inverted.xml.i @@ -0,0 +1,4 @@ +<!-- include start from constraint/interface-name-with-wildcard-and-inverted.xml.i --> +<regex>(\!?)(bond|br|dum|en|ersp|eth|gnv|ifb|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|veth|vti|vtun|vxlan|wg|wlan|wwan)([0-9]?)(\*?)(.+)?|(\!?)lo</regex> +<validator name="file-path --lookup-path /sys/class/net --directory"/> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/firewall/match-interface.xml.i b/interface-definitions/include/firewall/match-interface.xml.i index a62bf8d89..7810f88ab 100644 --- a/interface-definitions/include/firewall/match-interface.xml.i +++ b/interface-definitions/include/firewall/match-interface.xml.i @@ -7,10 +7,18 @@      </completionHelp>      <valueHelp>        <format>txt</format> -      <description>Interface name, wildcard (*) supported</description> +      <description>Interface name</description> +    </valueHelp> +    <valueHelp> +      <format>txt*</format> +      <description>Interface name with wildcard</description> +    </valueHelp> +    <valueHelp> +      <format>!txt</format> +      <description>Inverted interface name to match</description>      </valueHelp>      <constraint> -      #include <include/constraint/interface-name-with-wildcard.xml.i> +      #include <include/constraint/interface-name-with-wildcard-and-inverted.xml.i>      </constraint>    </properties>  </leafNode> @@ -20,6 +28,14 @@      <completionHelp>        <path>firewall group interface-group</path>      </completionHelp> +    <valueHelp> +      <format>txt</format> +      <description>Interface-group name to match</description> +    </valueHelp> +    <valueHelp> +      <format>!txt</format> +      <description>Inverted interface-group name to match</description> +    </valueHelp>    </properties>  </leafNode>  <!-- include end -->
\ No newline at end of file diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index 4aa509fe2..53ff8259e 100644 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -272,20 +272,34 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):                  output.append(f'ip6 hoplimit {operator} {value}')      if 'inbound_interface' in rule_conf: +        operator = ''          if 'interface_name' in rule_conf['inbound_interface']:              iiface = rule_conf['inbound_interface']['interface_name'] -            output.append(f'iifname {{{iiface}}}') +            if iiface[0] == '!': +                operator = '!=' +                iiface = iiface[1:] +            output.append(f'iifname {operator} {{{iiface}}}')          else:              iiface = rule_conf['inbound_interface']['interface_group'] -            output.append(f'iifname @I_{iiface}') +            if iiface[0] == '!': +                operator = '!=' +                iiface = iiface[1:] +            output.append(f'iifname {operator} @I_{iiface}')      if 'outbound_interface' in rule_conf: +        operator = ''          if 'interface_name' in rule_conf['outbound_interface']:              oiface = rule_conf['outbound_interface']['interface_name'] -            output.append(f'oifname {{{oiface}}}') +            if oiface[0] == '!': +                operator = '!=' +                oiface = oiface[1:] +            output.append(f'oifname {operator} {{{oiface}}}')          else:              oiface = rule_conf['outbound_interface']['interface_group'] -            output.append(f'oifname @I_{oiface}') +            if oiface[0] == '!': +                operator = '!=' +                oiface = oiface[1:] +            output.append(f'oifname {operator} @I_{oiface}')      if 'ttl' in rule_conf:          operators = {'eq': '==', 'gt': '>', 'lt': '<'} diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 7a13f396f..b2076c077 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -137,7 +137,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'action', 'accept'])          self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '3', 'source', 'group', 'domain-group', 'smoketest_domain'])          self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'action', 'accept']) -        self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'outbound-interface', 'interface-group', 'smoketest_interface']) +        self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '4', 'outbound-interface', 'interface-group', '!smoketest_interface'])          self.cli_commit() @@ -153,7 +153,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):              ['elements = { 192.0.2.5, 192.0.2.8,'],              ['192.0.2.10, 192.0.2.11 }'],              ['ip saddr @D_smoketest_domain', 'accept'], -            ['oifname @I_smoketest_interface', 'accept'] +            ['oifname != @I_smoketest_interface', 'accept']          ]          self.verify_nftables(nftables_search, 'ip vyos_filter') @@ -192,6 +192,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):      def test_ipv4_basic_rules(self):          name = 'smoketest'          interface = 'eth0' +        interface_inv = '!eth0'          interface_wc = 'l2tp*'          mss_range = '501-1460'          conn_mark = '555' @@ -231,7 +232,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'tcp', 'flags', 'syn'])          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'tcp', 'mss', mss_range])          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'packet-type', 'broadcast']) -        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'inbound-interface', 'interface-name', interface]) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'inbound-interface', 'interface-name', interface_wc])          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'action', 'return'])          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'protocol', 'gre'])          self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '6', 'connection-mark', conn_mark]) @@ -239,7 +240,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'default-action', 'accept'])          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'action', 'drop'])          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'protocol', 'gre']) -        self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'outbound-interface', 'interface-name', interface_wc]) +        self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'outbound-interface', 'interface-name', interface_inv])          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'action', 'return'])          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'protocol', 'icmp'])          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '6', 'connection-mark', conn_mark]) @@ -255,11 +256,11 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):              ['tcp dport 22', 'add @RECENT_FWD_filter_4 { ip saddr limit rate over 10/minute burst 10 packets }', 'meta pkttype host', 'drop'],              ['chain VYOS_INPUT_filter'],              ['type filter hook input priority filter; policy accept;'], -            ['tcp flags & syn == syn', f'tcp option maxseg size {mss_range}', f'iifname "{interface}"', 'meta pkttype broadcast', 'accept'], +            ['tcp flags & syn == syn', f'tcp option maxseg size {mss_range}', f'iifname "{interface_wc}"', 'meta pkttype broadcast', 'accept'],              ['meta l4proto gre', f'ct mark {mark_hex}', 'return'],              ['chain VYOS_OUTPUT_filter'],              ['type filter hook output priority filter; policy accept;'], -            ['meta l4proto gre', f'oifname "{interface_wc}"', 'drop'], +            ['meta l4proto gre', f'oifname != "{interface}"', 'drop'],              ['meta l4proto icmp', f'ct mark {mark_hex}', 'return'],              ['chain NAME_smoketest'],              ['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[smoketest-1-A]" log level debug', 'ip ttl 15', 'accept'], | 
