diff --git a/data/templates/accel-ppp/config_ip_pool.j2 b/data/templates/accel-ppp/config_ip_pool.j2
index 6ac04e1a1..8e66486e6 100644
--- a/data/templates/accel-ppp/config_ip_pool.j2
+++ b/data/templates/accel-ppp/config_ip_pool.j2
@@ -1,28 +1,32 @@
 {% if ordered_named_pools is vyos_defined %}
 [ip-pool]
 {%     if gateway_address is vyos_defined %}
 {%         if server_type == 'ipoe' %}
 {%             for gw in gateway_address %}
 {%                 set host_address, _ = gw.split('/') %}
 gw-ip-address={{ host_address }}
 {%             endfor %}
 {%         else %}
 gw-ip-address={{ gateway_address }}
 {%         endif %}
 {%     endif %}
 {%     for pool in ordered_named_pools %}
 {%         for pool_name, pool_config in pool.items() %}
-{%             set iprange_str = pool_config.range %}
-{%             set iprange_list = pool_config.range.split('-') %}
-{%             if iprange_list | length == 2 %}
-{%                 set last_ip_oct = iprange_list[1].split('.') %}
-{%                 set iprange_str = iprange_list[0] + '-' + last_ip_oct[last_ip_oct | length - 1] %}
-{%             endif %}
-{%             if pool_config.next_pool is vyos_defined %}
+{%             if pool_config.range is vyos_defined %}
+{%                 for range in pool_config.range %}
+{%                     set iprange_str = range %}
+{%                     set iprange_list = range.split('-') %}
+{%                     if iprange_list | length == 2 %}
+{%                         set last_ip_oct = iprange_list[1].split('.') %}
+{%                         set iprange_str = iprange_list[0] + '-' + last_ip_oct[last_ip_oct | length - 1] %}
+{%                     endif %}
+{%                     if loop.last and pool_config.next_pool is vyos_defined %}
 {{ iprange_str }},name={{ pool_name }},next={{ pool_config.next_pool }}
-{%             else %}
+{%                     else %}
 {{ iprange_str }},name={{ pool_name }}
+{%                     endif %}
+{%                 endfor %}
 {%             endif %}
 {%         endfor %}
 {%     endfor %}
 {% endif %}
\ No newline at end of file
diff --git a/interface-definitions/include/accel-ppp/client-ip-pool.xml.i b/interface-definitions/include/accel-ppp/client-ip-pool.xml.i
index 71fe69f8d..b30a5ee01 100644
--- a/interface-definitions/include/accel-ppp/client-ip-pool.xml.i
+++ b/interface-definitions/include/accel-ppp/client-ip-pool.xml.i
@@ -1,46 +1,50 @@
 <!-- include start from accel-ppp/client-ip-pool.xml.i -->
 <tagNode name="client-ip-pool">
   <properties>
     <help>Client IP pool</help>
     <valueHelp>
       <format>txt</format>
       <description>Name of IP pool</description>
     </valueHelp>
     <constraint>
       #include <include/constraint/alpha-numeric-hyphen-underscore-dot.xml.i>
     </constraint>
   </properties>
   <children>
     <leafNode name="range">
       <properties>
         <help>Range of IP addresses</help>
         <valueHelp>
           <format>ipv4net</format>
           <description>IPv4 prefix</description>
         </valueHelp>
         <valueHelp>
           <format>ipv4range</format>
           <description>IPv4 address range inside /24 network</description>
         </valueHelp>
         <constraint>
           <validator name="ipv4-prefix"/>
           <validator name="ipv4-host"/>
           <validator name="ipv4-range-mask"  argument="-m 24 -r"/>
         </constraint>
+        <multi/>
       </properties>
     </leafNode>
     <leafNode name="next-pool">
       <properties>
         <help>Next pool name</help>
+        <completionHelp>
+          <path>${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-4}</path>
+        </completionHelp>
         <valueHelp>
           <format>txt</format>
           <description>Name of IP pool</description>
         </valueHelp>
         <constraint>
           #include <include/constraint/alpha-numeric-hyphen-underscore-dot.xml.i>
         </constraint>
       </properties>
     </leafNode>
   </children>
 </tagNode>
 <!-- include end -->
diff --git a/interface-definitions/include/accel-ppp/default-pool.xml.i b/interface-definitions/include/accel-ppp/default-pool.xml.i
index a08b066b1..e06642c37 100644
--- a/interface-definitions/include/accel-ppp/default-pool.xml.i
+++ b/interface-definitions/include/accel-ppp/default-pool.xml.i
@@ -1,14 +1,17 @@
 <!-- include start from accel-ppp/default-pool.xml.i -->
 <leafNode name="default-pool">
   <properties>
     <help>Default client IP pool name</help>
+    <completionHelp>
+      <path>${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-3} client-ip-pool</path>
+    </completionHelp>
     <valueHelp>
       <format>txt</format>
       <description>Default IP pool</description>
     </valueHelp>
     <constraint>
       #include <include/constraint/alpha-numeric-hyphen-underscore-dot.xml.i>
     </constraint>
   </properties>
 </leafNode>
 <!-- include end -->
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 03a27d3cd..1a91951b4 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -1,123 +1,123 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2019-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/>.
 
 import os
 
 from sys import exit
 
 from vyos.config import Config
 from vyos.configdict import get_accel_dict
 from vyos.template import render
 from vyos.utils.process import call
 from vyos.utils.dict import dict_search
 from vyos.accel_ppp_util import verify_accel_ppp_base_service
 from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
 from vyos.accel_ppp_util import get_pools_in_order
 from vyos.base import Warning
 from vyos import ConfigError
 
 from vyos import airbag
 airbag.enable()
 
 
 l2tp_conf = '/run/accel-pppd/l2tp.conf'
 l2tp_chap_secrets = '/run/accel-pppd/l2tp.chap-secrets'
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['vpn', 'l2tp', 'remote-access']
     if not conf.exists(base):
         return None
 
     # retrieve common dictionary keys
     l2tp = get_accel_dict(conf, base, l2tp_chap_secrets)
     if dict_search('client_ip_pool', l2tp):
         # Multiple named pools require ordered values T5099
         l2tp['ordered_named_pools'] = get_pools_in_order(
             dict_search('client_ip_pool', l2tp))
     l2tp['ip6_column'] = []
     if dict_search('client_ipv6_pool.prefix', l2tp):
         l2tp['ip6_column'].append('ipv6')
     if dict_search('client_ipv6_pool.delegate', l2tp):
         l2tp['ip6_column'].append('ip6-db')
     l2tp['server_type'] = 'l2tp'
     return l2tp
 
 
 def verify(l2tp):
     if not l2tp:
         return None
 
     verify_accel_ppp_base_service(l2tp)
 
     if dict_search('authentication.radius.dynamic_author.server', l2tp):
         if not dict_search('authentication.radius.dynamic_author.key', l2tp):
             raise ConfigError('DA/CoE server key required!')
 
     if dict_search('authentication.mode', l2tp) in ['local', 'noauth']:
-        if not l2tp['client_ip_pool'] and not l2tp['client_ipv6_pool']:
+        if not dict_search('client_ip_pool', l2tp) and not dict_search('client_ipv6_pool', l2tp):
             raise ConfigError(
                 "L2TP local auth mode requires local client-ip-pool or client-ipv6-pool to be configured!")
         if dict_search('client_ip_pool', l2tp) and not dict_search('default_pool', l2tp):
             Warning("'default-pool' is not defined")
 
     verify_accel_ppp_ip_pool(l2tp)
 
     if 'wins_server' in l2tp and len(l2tp['wins_server']) > 2:
         raise ConfigError(
             'Not more then two WINS name-servers can be configured')
 
     return None
 
 
 def generate(l2tp):
     if not l2tp:
         return None
 
     render(l2tp_conf, 'accel-ppp/l2tp.config.j2', l2tp)
 
     if dict_search('authentication.mode', l2tp) == 'local':
         render(l2tp_chap_secrets, 'accel-ppp/chap-secrets.config_dict.j2',
                l2tp, permission=0o640)
 
     return None
 
 
 def apply(l2tp):
     if not l2tp:
         call('systemctl stop accel-ppp@l2tp.service')
         for file in [l2tp_chap_secrets, l2tp_conf]:
             if os.path.exists(file):
                 os.unlink(file)
 
         return None
 
     call('systemctl restart accel-ppp@l2tp.service')
 
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
 
     except ConfigError as e:
         print(e)
         exit(1)
diff --git a/src/migration-scripts/ipoe-server/1-to-2 b/src/migration-scripts/ipoe-server/1-to-2
index c8cec6835..11d7911e9 100755
--- a/src/migration-scripts/ipoe-server/1-to-2
+++ b/src/migration-scripts/ipoe-server/1-to-2
@@ -1,87 +1,87 @@
 #!/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/>.
 
 # - changed cli of all named pools
 # - moved gateway-address from pool to global configuration with / netmask
 #   gateway can exist without pool if radius is used
 #   and Framed-ip-address is transmited
 # - There are several gateway-addresses in ipoe
 # - default-pool by migration.
 #       1. The first pool that contains next-poll.
 #       2. Else, the first pool in the list
 
 import os
 
 from sys import argv
 from sys import 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)
 base = ['service', 'ipoe-server']
 pool_base = base + ['client-ip-pool']
 if not config.exists(base):
     exit(0)
 
 if not config.exists(pool_base):
     exit(0)
 default_pool = ''
 gateway = ''
 
 #named pool migration
 namedpools_base = pool_base + ['name']
 
 for pool_name in config.list_nodes(namedpools_base):
     pool_path = namedpools_base + [pool_name]
     if config.exists(pool_path + ['subnet']):
         subnet = config.return_value(pool_path + ['subnet'])
-        config.set(pool_base + [pool_name, 'range'], value=subnet)
+        config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
         # Get netmask from subnet
         mask = subnet.split("/")[1]
     if config.exists(pool_path + ['next-pool']):
         next_pool = config.return_value(pool_path + ['next-pool'])
         config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
         if not default_pool:
             default_pool = pool_name
     if config.exists(pool_path + ['gateway-address']) and mask:
         gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
         config.set(base + ['gateway-address'], value=gateway, replace=False)
 
 if not default_pool and config.list_nodes(namedpools_base):
     default_pool = config.list_nodes(namedpools_base)[0]
 
 config.delete(namedpools_base)
 
 if default_pool:
     config.set(base + ['default-pool'], value=default_pool)
 # format as tag node
 config.set_tag(pool_base)
 
 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/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5
index 496dc83d6..3176f895a 100755
--- a/src/migration-scripts/l2tp/4-to-5
+++ b/src/migration-scripts/l2tp/4-to-5
@@ -1,87 +1,87 @@
 #!/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/>.
 
 # - move all pool to named pools
 #       'start-stop' migrate to namedpool 'default-range-pool'
 #       'subnet' migrate to namedpool 'default-subnet-pool'
 #       'default-subnet-pool' is the next pool for 'default-range-pool'
 
 import os
 
 from sys import argv
 from sys import exit
 from vyos.configtree import ConfigTree
-
+from vyos.base import Warning
 
 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)
 base = ['vpn', 'l2tp', 'remote-access']
 pool_base = base + ['client-ip-pool']
 if not config.exists(base):
     exit(0)
 
 if not config.exists(pool_base):
     exit(0)
 default_pool = ''
 range_pool_name = 'default-range-pool'
-subnet_base_name = 'default-subnet-pool'
-number = 1
-subnet_pool_name = f'{subnet_base_name}-{number}'
-prev_subnet_pool = subnet_pool_name
-if config.exists(pool_base + ['subnet']):
-    default_pool = subnet_pool_name
-    for subnet in config.return_values(pool_base + ['subnet']):
-        config.set(pool_base + [subnet_pool_name, 'range'], value=subnet)
-        if prev_subnet_pool != subnet_pool_name:
-            config.set(pool_base + [prev_subnet_pool, 'next-pool'],
-                       value=subnet_pool_name)
-            prev_subnet_pool = subnet_pool_name
-        number += 1
-        subnet_pool_name = f'{subnet_base_name}-{number}'
-
-    config.delete(pool_base + ['subnet'])
 
 if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+    def is_legalrange(ip1: str, ip2: str, mask: str):
+        from ipaddress import IPv4Interface
+        interface1 = IPv4Interface(f'{ip1}/{mask}')
+
+        interface2 = IPv4Interface(f'{ip2}/{mask}')
+        return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
     start_ip = config.return_value(pool_base + ['start'])
     stop_ip = config.return_value(pool_base + ['stop'])
-    ip_range = f'{start_ip}-{stop_ip}'
+    if is_legalrange(start_ip, stop_ip,'24'):
+        ip_range = f'{start_ip}-{stop_ip}'
+        config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+        default_pool = range_pool_name
+    else:
+        Warning(
+            f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+
     config.delete(pool_base + ['start'])
     config.delete(pool_base + ['stop'])
-    config.set(pool_base + [range_pool_name, 'range'], value=ip_range)
-    if default_pool:
-        config.set(pool_base + [range_pool_name, 'next-pool'],
-                   value=default_pool)
+
+if config.exists(pool_base + ['subnet']):
+    for subnet in config.return_values(pool_base + ['subnet']):
+        config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+
+    config.delete(pool_base + ['subnet'])
     default_pool = range_pool_name
 
 if default_pool:
     config.set(base + ['default-pool'], value=default_pool)
 # format as tag node
 config.set_tag(pool_base)
 
 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/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7
index d856c1f34..b94ce57f9 100755
--- a/src/migration-scripts/pppoe-server/6-to-7
+++ b/src/migration-scripts/pppoe-server/6-to-7
@@ -1,122 +1,119 @@
 #!/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/>.
 
 # - move all pool to named pools
 #       'start-stop' migrate to namedpool 'default-range-pool'
 #       'subnet' migrate to namedpool 'default-subnet-pool'
 #       'default-subnet-pool' is the next pool for 'default-range-pool'
 # - There is only one gateway-address, take the first which is configured
 # - default-pool by migration.
 #       1. If authentication mode = 'local' then it is first named pool.
 #       If there are not named pools, namedless pool will be default.
 #       2. If authentication mode = 'radius' then namedless pool will be default
 
 import os
 
 from sys import argv
 from sys import exit
 from vyos.configtree import ConfigTree
-
+from vyos.base import Warning
 
 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)
 base = ['service', 'pppoe-server']
 pool_base = base + ['client-ip-pool']
 if not config.exists(base):
     exit(0)
 
 if not config.exists(pool_base):
     exit(0)
+
 default_pool = ''
 range_pool_name = 'default-range-pool'
 
-subnet_base_name = 'default-subnet-pool'
-number = 1
-subnet_pool_name = f'{subnet_base_name}-{number}'
-prev_subnet_pool = subnet_pool_name
 #Default nameless pools migrations
-if config.exists(pool_base + ['subnet']):
-    default_pool = subnet_pool_name
-    for subnet in config.return_values(pool_base + ['subnet']):
-        config.set(pool_base + [subnet_pool_name, 'range'], value=subnet)
-        if prev_subnet_pool != subnet_pool_name:
-            config.set(pool_base + [prev_subnet_pool, 'next-pool'],
-                       value=subnet_pool_name)
-            prev_subnet_pool = subnet_pool_name
-        number += 1
-        subnet_pool_name = f'{subnet_base_name}-{number}'
-
-    config.delete(pool_base + ['subnet'])
-
 if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+    def is_legalrange(ip1: str, ip2: str, mask: str):
+        from ipaddress import IPv4Interface
+        interface1 = IPv4Interface(f'{ip1}/{mask}')
+        interface2 = IPv4Interface(f'{ip2}/{mask}')
+        return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
     start_ip = config.return_value(pool_base + ['start'])
     stop_ip = config.return_value(pool_base + ['stop'])
-    ip_range = f'{start_ip}-{stop_ip}'
+    if is_legalrange(start_ip, stop_ip, '24'):
+        ip_range = f'{start_ip}-{stop_ip}'
+        config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+        default_pool = range_pool_name
+    else:
+        Warning(
+            f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
     config.delete(pool_base + ['start'])
     config.delete(pool_base + ['stop'])
-    config.set(pool_base + [range_pool_name, 'range'], value=ip_range)
-    if default_pool:
-        config.set(pool_base + [range_pool_name, 'next-pool'],
-                   value=default_pool)
+
+if config.exists(pool_base + ['subnet']):
     default_pool = range_pool_name
+    for subnet in config.return_values(pool_base + ['subnet']):
+        config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
+    config.delete(pool_base + ['subnet'])
 
 gateway = ''
 if config.exists(base + ['gateway-address']):
     gateway = config.return_value(base + ['gateway-address'])
 
 #named pool migration
 namedpools_base = pool_base + ['name']
 if config.exists(namedpools_base):
     if config.exists(base + ['authentication', 'mode']):
         if config.return_value(base + ['authentication', 'mode']) == 'local':
             if config.list_nodes(namedpools_base):
                 default_pool = config.list_nodes(namedpools_base)[0]
 
     for pool_name in config.list_nodes(namedpools_base):
         pool_path = namedpools_base + [pool_name]
         if config.exists(pool_path + ['subnet']):
             subnet = config.return_value(pool_path + ['subnet'])
-            config.set(pool_base + [pool_name, 'range'], value=subnet)
+            config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
         if config.exists(pool_path + ['next-pool']):
             next_pool = config.return_value(pool_path + ['next-pool'])
             config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
         if not gateway:
             if config.exists(pool_path + ['gateway-address']):
                 gateway = config.return_value(pool_path + ['gateway-address'])
 
     config.delete(namedpools_base)
 
 if gateway:
     config.set(base + ['gateway-address'], value=gateway)
 if default_pool:
     config.set(base + ['default-pool'], value=default_pool)
 # format as tag node
 config.set_tag(pool_base)
 
 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/pptp/2-to-3 b/src/migration-scripts/pptp/2-to-3
index 98dc5c2a6..091cb68ec 100755
--- a/src/migration-scripts/pptp/2-to-3
+++ b/src/migration-scripts/pptp/2-to-3
@@ -1,64 +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/>.
 
 # - move all pool to named pools
 #       'start-stop' migrate to namedpool 'default-range-pool'
 #       'default-subnet-pool' is the next pool for 'default-range-pool'
 
 import os
 
 from sys import argv
 from sys import exit
 from vyos.configtree import ConfigTree
-
+from vyos.base import Warning
 
 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)
 base = ['vpn', 'pptp', 'remote-access']
 pool_base = base + ['client-ip-pool']
 if not config.exists(base):
     exit(0)
 
 if not config.exists(pool_base):
     exit(0)
 
 range_pool_name = 'default-range-pool'
 
 if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']):
+    def is_legalrange(ip1: str, ip2: str, mask: str):
+        from ipaddress import IPv4Interface
+        interface1 = IPv4Interface(f'{ip1}/{mask}')
+        interface2 = IPv4Interface(f'{ip2}/{mask}')
+        return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip
+
     start_ip = config.return_value(pool_base + ['start'])
     stop_ip = config.return_value(pool_base + ['stop'])
-    ip_range = f'{start_ip}-{stop_ip}'
+    if is_legalrange(start_ip, stop_ip, '24'):
+        ip_range = f'{start_ip}-{stop_ip}'
+        config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False)
+        config.set(base + ['default-pool'], value=range_pool_name)
+    else:
+        Warning(
+            f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.')
+
     config.delete(pool_base + ['start'])
     config.delete(pool_base + ['stop'])
-    config.set(pool_base + [range_pool_name, 'range'], value=ip_range)
-    config.set(base + ['default-pool'], value=range_pool_name)
 # format as tag node
 config.set_tag(pool_base)
 
 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/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5
index 3a86c79ec..95e482713 100755
--- a/src/migration-scripts/sstp/4-to-5
+++ b/src/migration-scripts/sstp/4-to-5
@@ -1,71 +1,62 @@
 #!/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/>.
 
 # - move all pool to named pools
 #       'subnet' migrate to namedpool 'default-subnet-pool'
 #       'default-subnet-pool' is the next pool for 'default-range-pool'
 
 import os
 
 from sys import argv
 from sys import 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)
 base = ['vpn', 'sstp']
 pool_base = base + ['client-ip-pool']
 if not config.exists(base):
     exit(0)
 
 if not config.exists(pool_base):
     exit(0)
 
-subnet_base_name = 'default-subnet-pool'
-number = 1
-subnet_pool_name = f'{subnet_base_name}-{number}'
-prev_subnet_pool = subnet_pool_name
+range_pool_name = 'default-range-pool'
+
 if config.exists(pool_base + ['subnet']):
-    default_pool = subnet_pool_name
+    default_pool = range_pool_name
     for subnet in config.return_values(pool_base + ['subnet']):
-        config.set(pool_base + [subnet_pool_name, 'range'], value=subnet)
-        if prev_subnet_pool != subnet_pool_name:
-            config.set(pool_base + [prev_subnet_pool, 'next-pool'],
-                       value=subnet_pool_name)
-            prev_subnet_pool = subnet_pool_name
-        number += 1
-        subnet_pool_name = f'{subnet_base_name}-{number}'
-
+        config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False)
     config.delete(pool_base + ['subnet'])
     config.set(base + ['default-pool'], value=default_pool)
 # format as tag node
 config.set_tag(pool_base)
 
 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/validators/ipv4-range-mask b/src/validators/ipv4-range-mask
index 7bb4539af..9373328ff 100755
--- a/src/validators/ipv4-range-mask
+++ b/src/validators/ipv4-range-mask
@@ -1,59 +1,27 @@
 #!/bin/bash
 
-# snippet from https://stackoverflow.com/questions/10768160/ip-address-converter
-ip2dec () {
-    local a b c d ip=$@
-    IFS=. read -r a b c d <<< "$ip"
-    printf '%d\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
-}
-
 error_exit() {
   echo "Error: $1 is not a valid IPv4 address range or these IPs are not under /$2"
   exit 1
 }
 
 # Check if address range is under the same netmask
 # -m - mask
 # -r - IP range in format x.x.x.x-y.y.y.y
 while getopts m:r: flag
 do
     case "${flag}" in
         m) mask=${OPTARG};;
         r) range=${OPTARG}
     esac
 done
-if [[ "${range}" =~ "-" ]]&&[[ ! -z ${mask} ]]; then
-  # This only works with real bash (<<<) - split IP addresses into array with
-  # hyphen as delimiter
-  readarray -d - -t strarr <<< ${range}
-
-  ipaddrcheck --is-ipv4-single ${strarr[0]}
-  if [ $? -gt 0 ]; then
-    error_exit ${range} ${mask}
-  fi
 
-  ipaddrcheck --is-ipv4-single ${strarr[1]}
+if [[ "${range}" =~ "-" ]]&&[[ ! -z ${mask} ]]; then
+  ipaddrcheck --range-prefix-length ${mask} --is-ipv4-range ${range}
   if [ $? -gt 0 ]; then
     error_exit ${range} ${mask}
   fi
-
-  ${vyos_validators_dir}/numeric --range 0-32 ${mask} > /dev/null
-   if [ $? -ne 0 ]; then
-     error_exit ${range} ${mask}
-   fi
-
-  is_in_24=$( grepcidr ${strarr[0]}"/"${mask} <(echo ${strarr[1]}) )
-  if [ -z $is_in_24 ]; then
-    error_exit ${range} ${mask}
-  fi
-
-  start=$(ip2dec ${strarr[0]})
-  stop=$(ip2dec ${strarr[1]})
-  if [ $start -ge $stop ]; then
-    error_exit ${range} ${mask}
-  fi
-
   exit 0
 fi
 
 error_exit ${range} ${mask}