diff options
19 files changed, 348 insertions, 88 deletions
| diff --git a/data/templates/ndppd/ndppd.conf.j2 b/data/templates/ndppd/ndppd.conf.j2 index 120fa0a64..1297f36be 100644 --- a/data/templates/ndppd/ndppd.conf.j2 +++ b/data/templates/ndppd/ndppd.conf.j2 @@ -17,12 +17,12 @@  {% set global = namespace(ndppd_interfaces = [],ndppd_prefixs = []) %}  {% if source.rule is vyos_defined %}  {%     for rule, config in source.rule.items() if config.disable is not defined %} -{%         if config.outbound_interface is vyos_defined %} -{%             if config.outbound_interface not in global.ndppd_interfaces %} -{%                 set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface] %} +{%         if config.outbound_interface.name is vyos_defined %} +{%             if config.outbound_interface.name not in global.ndppd_interfaces %} +{%                 set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface.name] %}  {%             endif   %}  {%             if config.translation.address is vyos_defined and config.translation.address | is_ip_network %} -{%                 set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface,'rule':config.translation.address}] %} +{%                 set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface.name,'rule':config.translation.address}] %}  {%             endif %}  {%         endif %}  {%     endfor %} diff --git a/interface-definitions/include/firewall/inbound-interface-no-group.xml.i b/interface-definitions/include/firewall/inbound-interface-no-group.xml.i new file mode 100644 index 000000000..bcd4c9570 --- /dev/null +++ b/interface-definitions/include/firewall/inbound-interface-no-group.xml.i @@ -0,0 +1,34 @@ +<!-- include start from firewall/inbound-interface-no-group.xml.i --> +<node name="inbound-interface"> +  <properties> +    <help>Match inbound-interface</help> +  </properties> +  <children> +    <leafNode name="name"> +      <properties> +        <help>Match interface</help> +        <completionHelp> +          <script>${vyos_completion_dir}/list_interfaces</script> +          <path>vrf name</path> +        </completionHelp> +        <valueHelp> +          <format>txt</format> +          <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> +          <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="vrf-name"/> +        </constraint> +      </properties> +    </leafNode> +  </children> +</node> +<!-- 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 7810f88ab..8be97c3ed 100644 --- a/interface-definitions/include/firewall/match-interface.xml.i +++ b/interface-definitions/include/firewall/match-interface.xml.i @@ -1,5 +1,5 @@  <!-- include start from firewall/match-interface.xml.i --> -<leafNode name="interface-name"> +<leafNode name="name">    <properties>      <help>Match interface</help>      <completionHelp> @@ -22,7 +22,7 @@      </constraint>    </properties>  </leafNode> -<leafNode name="interface-group"> +<leafNode name="group">    <properties>      <help>Match interface-group</help>      <completionHelp> diff --git a/interface-definitions/include/firewall/outbound-interface-no-group.xml.i b/interface-definitions/include/firewall/outbound-interface-no-group.xml.i new file mode 100644 index 000000000..e3bace42d --- /dev/null +++ b/interface-definitions/include/firewall/outbound-interface-no-group.xml.i @@ -0,0 +1,34 @@ +<!-- include start from firewall/outbound-interface-no-group.xml.i --> +<node name="outbound-interface"> +  <properties> +    <help>Match outbound-interface</help> +  </properties> +  <children> +    <leafNode name="name"> +      <properties> +        <help>Match interface</help> +        <completionHelp> +          <script>${vyos_completion_dir}/list_interfaces</script> +          <path>vrf name</path> +        </completionHelp> +        <valueHelp> +          <format>txt</format> +          <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> +          <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="vrf-name"/> +        </constraint> +      </properties> +    </leafNode> +  </children> +</node> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/version/firewall-version.xml.i b/interface-definitions/include/version/firewall-version.xml.i index dd21bfaca..39f0cdcba 100644 --- a/interface-definitions/include/version/firewall-version.xml.i +++ b/interface-definitions/include/version/firewall-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/firewall-version.xml.i --> -<syntaxVersion component='firewall' version='11'></syntaxVersion> +<syntaxVersion component='firewall' version='12'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/nat-version.xml.i b/interface-definitions/include/version/nat-version.xml.i index 027216a07..656da6e14 100644 --- a/interface-definitions/include/version/nat-version.xml.i +++ b/interface-definitions/include/version/nat-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/nat-version.xml.i --> -<syntaxVersion component='nat' version='5'></syntaxVersion> +<syntaxVersion component='nat' version='7'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/include/version/nat66-version.xml.i b/interface-definitions/include/version/nat66-version.xml.i index 7b7123dcc..478ca080f 100644 --- a/interface-definitions/include/version/nat66-version.xml.i +++ b/interface-definitions/include/version/nat66-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/nat66-version.xml.i --> -<syntaxVersion component='nat66' version='1'></syntaxVersion> +<syntaxVersion component='nat66' version='2'></syntaxVersion>  <!-- include end --> diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in index 7a8970bdf..a657535ba 100644 --- a/interface-definitions/nat66.xml.in +++ b/interface-definitions/nat66.xml.in @@ -38,14 +38,7 @@                    <valueless/>                  </properties>                </leafNode> -              <leafNode name="outbound-interface"> -                <properties> -                  <help>Outbound interface of NAT66 traffic</help> -                  <completionHelp> -                    <script>${vyos_completion_dir}/list_interfaces</script> -                  </completionHelp> -                </properties> -              </leafNode> +              #include <include/firewall/outbound-interface-no-group.xml.i>                #include <include/nat/protocol.xml.i>                <node name="destination">                  <properties> @@ -166,15 +159,7 @@                    <valueless/>                  </properties>                </leafNode> -              <leafNode name="inbound-interface"> -                <properties> -                  <help>Inbound interface of NAT66 traffic</help> -                  <completionHelp> -                    <list>any</list> -                    <script>${vyos_completion_dir}/list_interfaces</script> -                  </completionHelp> -                </properties> -              </leafNode> +              #include <include/firewall/inbound-interface-no-group.xml.i>                #include <include/nat/protocol.xml.i>                <node name="destination">                  <properties> diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py index 59e02a2f1..2ad93a85d 100644 --- a/python/vyos/firewall.py +++ b/python/vyos/firewall.py @@ -294,14 +294,14 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):      if 'inbound_interface' in rule_conf:          operator = '' -        if 'interface_name' in rule_conf['inbound_interface']: -            iiface = rule_conf['inbound_interface']['interface_name'] +        if 'name' in rule_conf['inbound_interface']: +            iiface = rule_conf['inbound_interface']['name']              if iiface[0] == '!':                  operator = '!='                  iiface = iiface[1:]              output.append(f'iifname {operator} {{{iiface}}}')          else: -            iiface = rule_conf['inbound_interface']['interface_group'] +            iiface = rule_conf['inbound_interface']['group']              if iiface[0] == '!':                  operator = '!='                  iiface = iiface[1:] @@ -309,14 +309,14 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):      if 'outbound_interface' in rule_conf:          operator = '' -        if 'interface_name' in rule_conf['outbound_interface']: -            oiface = rule_conf['outbound_interface']['interface_name'] +        if 'name' in rule_conf['outbound_interface']: +            oiface = rule_conf['outbound_interface']['name']              if oiface[0] == '!':                  operator = '!='                  oiface = oiface[1:]              output.append(f'oifname {operator} {{{oiface}}}')          else: -            oiface = rule_conf['outbound_interface']['interface_group'] +            oiface = rule_conf['outbound_interface']['group']              if oiface[0] == '!':                  operator = '!='                  oiface = oiface[1:] diff --git a/python/vyos/nat.py b/python/vyos/nat.py index e32b5ae74..392d38772 100644 --- a/python/vyos/nat.py +++ b/python/vyos/nat.py @@ -33,14 +33,14 @@ def parse_nat_rule(rule_conf, rule_id, nat_type, ipv6=False):      if 'inbound_interface' in rule_conf:          operator = '' -        if 'interface_name' in rule_conf['inbound_interface']: -            iiface = rule_conf['inbound_interface']['interface_name'] +        if 'name' in rule_conf['inbound_interface']: +            iiface = rule_conf['inbound_interface']['name']              if iiface[0] == '!':                  operator = '!='                  iiface = iiface[1:]              output.append(f'iifname {operator} {{{iiface}}}')          else: -            iiface = rule_conf['inbound_interface']['interface_group'] +            iiface = rule_conf['inbound_interface']['group']              if iiface[0] == '!':                  operator = '!='                  iiface = iiface[1:] @@ -48,14 +48,14 @@ def parse_nat_rule(rule_conf, rule_id, nat_type, ipv6=False):      if 'outbound_interface' in rule_conf:          operator = '' -        if 'interface_name' in rule_conf['outbound_interface']: -            oiface = rule_conf['outbound_interface']['interface_name'] +        if 'name' in rule_conf['outbound_interface']: +            oiface = rule_conf['outbound_interface']['name']              if oiface[0] == '!':                  operator = '!='                  oiface = oiface[1:]              output.append(f'oifname {operator} {{{oiface}}}')          else: -            oiface = rule_conf['outbound_interface']['interface_group'] +            oiface = rule_conf['outbound_interface']['group']              if oiface[0] == '!':                  operator = '!='                  oiface = oiface[1:] diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 92aa71e38..5f842727d 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -148,7 +148,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', 'group', '!smoketest_interface'])          self.cli_commit() @@ -244,7 +244,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_wc]) +        self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'rule', '5', 'inbound-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]) @@ -253,7 +253,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'enable-default-log'])          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_inv]) +        self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '5', 'outbound-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]) @@ -394,18 +394,18 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'action', 'reject'])          self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'protocol', 'tcp_udp'])          self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'destination', 'port', '8888']) -        self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'inbound-interface', 'interface-name', interface]) +        self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '2', 'inbound-interface', 'name', interface])          self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'default-action', 'drop'])          self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'enable-default-log'])          self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'action', 'return'])          self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'protocol', 'gre']) -        self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'outbound-interface', 'interface-name', interface]) +        self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'outbound-interface', 'name', interface])          self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'action', 'accept'])          self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'protocol', 'udp'])          self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'source', 'address', '2002::1:2']) -        self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'inbound-interface', 'interface-name', interface]) +        self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'rule', '3', 'inbound-interface', 'name', interface])          self.cli_commit() diff --git a/smoketest/scripts/cli/test_nat.py b/smoketest/scripts/cli/test_nat.py index 2f744a2f7..682fc141d 100755 --- a/smoketest/scripts/cli/test_nat.py +++ b/smoketest/scripts/cli/test_nat.py @@ -82,12 +82,12 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):              # or configured destination address for NAT              if int(rule) < 200:                  self.cli_set(src_path + ['rule', rule, 'source', 'address', network]) -                self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'interface-name', outbound_iface_100]) +                self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'name', outbound_iface_100])                  self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])                  nftables_search.append([f'saddr {network}', f'oifname "{outbound_iface_100}"', 'masquerade'])              else:                  self.cli_set(src_path + ['rule', rule, 'destination', 'address', network]) -                self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'interface-name', outbound_iface_200]) +                self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'name', outbound_iface_200])                  self.cli_set(src_path + ['rule', rule, 'exclude'])                  nftables_search.append([f'daddr {network}', f'oifname "{outbound_iface_200}"', 'return']) @@ -106,7 +106,7 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          self.cli_set(['firewall', 'group', 'interface-group', interface_group, 'interface', interface_group_member])          self.cli_set(src_path + ['rule', rule, 'source', 'group', 'address-group', address_group]) -        self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'interface-group', interface_group]) +        self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'group', interface_group])          self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])          self.cli_commit() @@ -138,12 +138,12 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):              rule_search = [f'dnat to 192.0.2.1:{port}']              if int(rule) < 200:                  self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_100]) -                self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'interface-name', inbound_iface_100]) +                self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'name', inbound_iface_100])                  rule_search.append(f'{inbound_proto_100} sport {port}')                  rule_search.append(f'iifname "{inbound_iface_100}"')              else:                  self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_200]) -                self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'interface-name', inbound_iface_200]) +                self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'name', inbound_iface_200])                  rule_search.append(f'iifname "{inbound_iface_200}"')              nftables_search.append(rule_search) @@ -169,7 +169,7 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          rule = '1000'          self.cli_set(dst_path + ['rule', rule, 'destination', 'address', '!192.0.2.1'])          self.cli_set(dst_path + ['rule', rule, 'destination', 'port', '53']) -        self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'interface-name', 'eth0']) +        self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'name', 'eth0'])          self.cli_set(dst_path + ['rule', rule, 'protocol', 'tcp_udp'])          self.cli_set(dst_path + ['rule', rule, 'source', 'address', '!192.0.2.1'])          self.cli_set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1']) @@ -188,7 +188,7 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          self.cli_commit()      def test_dnat_without_translation_address(self): -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'interface-name', 'eth1']) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'port', '443'])          self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])          self.cli_set(dst_path + ['rule', '1', 'packet-type', 'host']) @@ -238,13 +238,13 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          self.cli_set(dst_path + ['rule', '10', 'destination', 'address', dst_addr_1])          self.cli_set(dst_path + ['rule', '10', 'destination', 'port', dest_port])          self.cli_set(dst_path + ['rule', '10', 'protocol', protocol]) -        self.cli_set(dst_path + ['rule', '10', 'inbound-interface', 'interface-name', ifname]) +        self.cli_set(dst_path + ['rule', '10', 'inbound-interface', 'name', ifname])          self.cli_set(dst_path + ['rule', '10', 'translation', 'redirect', 'port', redirected_port])          self.cli_set(dst_path + ['rule', '20', 'destination', 'address', dst_addr_1])          self.cli_set(dst_path + ['rule', '20', 'destination', 'port', dest_port])          self.cli_set(dst_path + ['rule', '20', 'protocol', protocol]) -        self.cli_set(dst_path + ['rule', '20', 'inbound-interface', 'interface-name', ifname]) +        self.cli_set(dst_path + ['rule', '20', 'inbound-interface', 'name', ifname])          self.cli_set(dst_path + ['rule', '20', 'translation', 'redirect'])          self.cli_commit() @@ -268,7 +268,7 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          weight_4 = '65'          dst_port = '443' -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'interface-name', ifname]) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', ifname])          self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'port', dst_port])          self.cli_set(dst_path + ['rule', '1', 'load-balance', 'hash', 'source-address']) @@ -278,7 +278,7 @@ class TestNAT(VyOSUnitTestSHIM.TestCase):          self.cli_set(dst_path + ['rule', '1', 'load-balance', 'backend', member_1, 'weight', weight_1])          self.cli_set(dst_path + ['rule', '1', 'load-balance', 'backend', member_2, 'weight', weight_2]) -        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'interface-name', ifname]) +        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'name', ifname])          self.cli_set(src_path + ['rule', '1', 'load-balance', 'hash', 'random'])          self.cli_set(src_path + ['rule', '1', 'load-balance', 'backend', member_3, 'weight', weight_3])          self.cli_set(src_path + ['rule', '1', 'load-balance', 'backend', member_4, 'weight', weight_4]) diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py index e062f28a6..0607f6616 100755 --- a/smoketest/scripts/cli/test_nat66.py +++ b/smoketest/scripts/cli/test_nat66.py @@ -56,15 +56,15 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):      def test_source_nat66(self):          source_prefix = 'fc00::/64'          translation_prefix = 'fc01::/64' -        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'eth1']) +        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'name', 'eth1'])          self.cli_set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])          self.cli_set(src_path + ['rule', '1', 'translation', 'address', translation_prefix]) -        self.cli_set(src_path + ['rule', '2', 'outbound-interface', 'eth1']) +        self.cli_set(src_path + ['rule', '2', 'outbound-interface', 'name', 'eth1'])          self.cli_set(src_path + ['rule', '2', 'source', 'prefix', source_prefix])          self.cli_set(src_path + ['rule', '2', 'translation', 'address', 'masquerade']) -        self.cli_set(src_path + ['rule', '3', 'outbound-interface', 'eth1']) +        self.cli_set(src_path + ['rule', '3', 'outbound-interface', 'name', 'eth1'])          self.cli_set(src_path + ['rule', '3', 'source', 'prefix', source_prefix])          self.cli_set(src_path + ['rule', '3', 'exclude']) @@ -81,7 +81,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):      def test_source_nat66_address(self):          source_prefix = 'fc00::/64'          translation_address = 'fc00::1' -        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'eth1']) +        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'name', 'eth1'])          self.cli_set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])          self.cli_set(src_path + ['rule', '1', 'translation', 'address', translation_address]) @@ -98,11 +98,11 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):          destination_address = 'fc00::1'          translation_address = 'fc01::1'          source_address = 'fc02::1' -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1']) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'address', destination_address])          self.cli_set(dst_path + ['rule', '1', 'translation', 'address', translation_address]) -        self.cli_set(dst_path + ['rule', '2', 'inbound-interface', 'eth1']) +        self.cli_set(dst_path + ['rule', '2', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '2', 'destination', 'address', destination_address])          self.cli_set(dst_path + ['rule', '2', 'source', 'address', source_address])          self.cli_set(dst_path + ['rule', '2', 'exclude']) @@ -124,7 +124,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):          sport = '8080'          tport = '5555'          proto = 'tcp' -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1']) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'port', dport])          self.cli_set(dst_path + ['rule', '1', 'source', 'address', source_prefix])          self.cli_set(dst_path + ['rule', '1', 'source', 'port', sport]) @@ -144,7 +144,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):      def test_destination_nat66_prefix(self):          destination_prefix = 'fc00::/64'          translation_prefix = 'fc01::/64' -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1']) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'address', destination_prefix])          self.cli_set(dst_path + ['rule', '1', 'translation', 'address', translation_prefix]) @@ -158,7 +158,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):          self.verify_nftables(nftables_search, 'ip6 vyos_nat')      def test_destination_nat66_without_translation_address(self): -        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1']) +        self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'name', 'eth1'])          self.cli_set(dst_path + ['rule', '1', 'destination', 'port', '443'])          self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])          self.cli_set(dst_path + ['rule', '1', 'translation', 'port', '443']) @@ -180,7 +180,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):          # check validate() - outbound-interface must be defined          with self.assertRaises(ConfigSessionError):              self.cli_commit() -        self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'eth0']) +        self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'name', 'eth0'])          # check validate() - translation address not specified          with self.assertRaises(ConfigSessionError): @@ -196,7 +196,7 @@ class TestNAT66(VyOSUnitTestSHIM.TestCase):          sport = '8080'          tport = '80'          proto = 'tcp' -        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'eth1']) +        self.cli_set(src_path + ['rule', '1', 'outbound-interface', 'name', 'eth1'])          self.cli_set(src_path + ['rule', '1', 'destination', 'port', dport])          self.cli_set(src_path + ['rule', '1', 'source', 'prefix', source_prefix])          self.cli_set(src_path + ['rule', '1', 'source', 'port', sport]) diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index 1fbdde389..c66b2a7ec 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -260,8 +260,8 @@ def verify_rule(firewall, rule_conf, ipv6):      for direction in ['inbound_interface','outbound_interface']:          if direction in rule_conf: -            if 'interface_name' in rule_conf[direction] and 'interface_group' in rule_conf[direction]: -                raise ConfigError(f'Cannot specify both interface-group and interface-name for {direction}') +            if 'name' in rule_conf[direction] and 'group' in rule_conf[direction]: +                raise ConfigError(f'Cannot specify both interface group and interface name for {direction}')  def verify_nested_group(group_name, group, groups, seen):      if 'include' not in group: diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index c554c6c8c..5b7107f3c 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -197,11 +197,11 @@ def verify(nat):              err_msg = f'Source NAT configuration error in rule {rule}:'              if 'outbound_interface' in config: -                if 'interface_name' in config['outbound_interface'] and 'interface_group' in config['outbound_interface']: -                    raise ConfigError(f'Cannot specify both interface-group and interface-name for nat source rule "{rule}"') -                elif 'interface_name' in config['outbound_interface']: -                    if config['outbound_interface']['interface_name'] not in 'any' and config['outbound_interface']['interface_name'] not in interfaces(): -                        Warning(f'rule "{rule}" interface "{config["outbound_interface"]["interface_name"]}" does not exist on this system') +                if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: +                    raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') +                elif 'name' in config['outbound_interface']: +                    if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): +                        Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system')              if not dict_search('translation.address', config) and not dict_search('translation.port', config):                  if 'exclude' not in config and 'backend' not in config['load_balance']: @@ -221,11 +221,11 @@ def verify(nat):              err_msg = f'Destination NAT configuration error in rule {rule}:'              if 'inbound_interface' in config: -                if 'interface_name' in config['inbound_interface'] and 'interface_group' in config['inbound_interface']: -                    raise ConfigError(f'Cannot specify both interface-group and interface-name for destination nat rule "{rule}"') -                elif 'interface_name' in config['inbound_interface']: -                    if config['inbound_interface']['interface_name'] not in 'any' and config['inbound_interface']['interface_name'] not in interfaces(): -                        Warning(f'rule "{rule}" interface "{config["inbound_interface"]["interface_name"]}" does not exist on this system') +                if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: +                    raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') +                elif 'name' in config['inbound_interface']: +                    if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): +                        Warning(f'{err_msg} -  interface "{config["inbound_interface"]["name"]}" does not exist on this system')              if not dict_search('translation.address', config) and not dict_search('translation.port', config) and 'redirect' not in config['translation']:                  if 'exclude' not in config and 'backend' not in config['load_balance']: diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py index 4c12618bc..3f7185e67 100755 --- a/src/conf_mode/nat66.py +++ b/src/conf_mode/nat66.py @@ -102,11 +102,13 @@ def verify(nat):      if dict_search('source.rule', nat):          for rule, config in dict_search('source.rule', nat).items():              err_msg = f'Source NAT66 configuration error in rule {rule}:' -            if 'outbound_interface' not in config: -                raise ConfigError(f'{err_msg} outbound-interface not specified') -            if config['outbound_interface'] not in interfaces(): -                raise ConfigError(f'rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') +            if 'outbound_interface' in config: +                if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: +                    raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') +                elif 'name' in config['outbound_interface']: +                    if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): +                        Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system')              addr = dict_search('translation.address', config)              if addr != None: @@ -125,12 +127,12 @@ def verify(nat):          for rule, config in dict_search('destination.rule', nat).items():              err_msg = f'Destination NAT66 configuration error in rule {rule}:' -            if 'inbound_interface' not in config: -                raise ConfigError(f'{err_msg}\n' \ -                                  'inbound-interface not specified') -            else: -                if config['inbound_interface'] not in 'any' and config['inbound_interface'] not in interfaces(): -                    Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system') +            if 'inbound_interface' in config: +                if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: +                    raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') +                elif 'name' in config['inbound_interface']: +                    if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): +                        Warning(f'{err_msg} -  interface "{config["inbound_interface"]["name"]}" does not exist on this system')      return None diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12 new file mode 100755 index 000000000..51b2fa860 --- /dev/null +++ b/src/migration-scripts/firewall/11-to-12 @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From +    # set firewall ... rule <rule> [inbound-interface | outboubd-interface] interface-name <iface> +    # set firewall ... rule <rule> [inbound-interface | outboubd-interface] interface-group <iface_group> +# To +    # set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface> +    # set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group> + +import re + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.ifconfig import Section + +if len(argv) < 2: +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +base = ['firewall'] +config = ConfigTree(config_file) + +if not config.exists(base): +    # Nothing to do +    exit(0) + +## FORT +## Migration from base chains +#if config.exists(base + ['interface', iface, direction]): +for family in ['ipv4', 'ipv6']: +    if config.exists(base + [family]): +        for hook in ['forward', 'input', 'output', 'name']: +            if config.exists(base + [family, hook]): +                for priority in config.list_nodes(base + [family, hook]): +                    if config.exists(base + [family, hook, priority, 'rule']): +                        for rule in config.list_nodes(base + [family, hook, priority, 'rule']): +                            for direction in ['inbound-interface', 'outbound-interface']: +                                if config.exists(base + [family, hook, priority, 'rule', rule, direction]): +                                    if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']): +                                        iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) +                                        config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface) +                                        config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) +                                    elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']): +                                        group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) +                                        config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group) +                                        config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1)
\ No newline at end of file diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7 new file mode 100755 index 000000000..b5f6328ef --- /dev/null +++ b/src/migration-scripts/nat/6-to-7 @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From +#   'set nat [source|destination] rule X [inbound-interface|outbound interface] interface-name <iface>' +#   'set nat [source|destination] rule X [inbound-interface|outbound interface] interface-group <iface_group>' +# to +#   'set nat [source|destination] rule X [inbound-interface|outbound interface] name <iface>' +#   'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>' + +from sys import argv,exit +from vyos.configtree import ConfigTree + +if len(argv) < 2: +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +if not config.exists(['nat']): +    # Nothing to do +    exit(0) + +for direction in ['source', 'destination']: +    # If a node doesn't exist, we obviously have nothing to do. +    if not config.exists(['nat', direction]): +        continue + +    # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, +    # but there are no rules under it. +    if not config.list_nodes(['nat', direction]): +        continue + +    for rule in config.list_nodes(['nat', direction, 'rule']): +        base = ['nat', direction, 'rule', rule] +        for iface in ['inbound-interface','outbound-interface']: +            if config.exists(base + [iface]): +                if config.exists(base + [iface, 'interface-name']): +                    tmp = config.return_value(base + [iface, 'interface-name']) +                    config.delete(base + [iface, 'interface-name']) +                    config.set(base + [iface, 'name'], value=tmp) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) diff --git a/src/migration-scripts/nat66/1-to-2 b/src/migration-scripts/nat66/1-to-2 new file mode 100755 index 000000000..b7d4e3f6b --- /dev/null +++ b/src/migration-scripts/nat66/1-to-2 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From +#   'set nat66 [source|destination] rule X [inbound-interface|outbound interface] <iface>' +# to +#   'set nat66 [source|destination] rule X [inbound-interface|outbound interface] name <iface>' + +from sys import argv,exit +from vyos.configtree import ConfigTree + +if len(argv) < 2: +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) +if not config.exists(['nat66']): +    # Nothing to do +    exit(0) + +for direction in ['source', 'destination']: +    # If a node doesn't exist, we obviously have nothing to do. +    if not config.exists(['nat66', direction]): +        continue + +    # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, +    # but there are no rules under it. +    if not config.list_nodes(['nat66', direction]): +        continue + +    for rule in config.list_nodes(['nat66', direction, 'rule']): +        base = ['nat66', direction, 'rule', rule] +        for iface in ['inbound-interface','outbound-interface']: +            if config.exists(base + [iface]): +                tmp = config.return_value(base + [iface]) +                config.delete(base + [iface]) +                config.set(base + [iface, 'name'], value=tmp) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) | 
