From 4d60041302566a914af7a3067a94f33ff70cd932 Mon Sep 17 00:00:00 2001 From: Matteo Di Lorenzi Date: Fri, 9 Oct 2026 10:32:45 +0200 Subject: [PATCH 1/4] fix(wireguard): use first free name for new peer tunnels --- packages/ns-api/files/ns.wireguard | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/ns-api/files/ns.wireguard b/packages/ns-api/files/ns.wireguard index 485405984..8c04b81bc 100644 --- a/packages/ns-api/files/ns.wireguard +++ b/packages/ns-api/files/ns.wireguard @@ -115,9 +115,8 @@ def get_instance_defaults(): listen_port = 51820 else: listen_port = 51820 + next_instance - 1 - interface = f'wg{next_instance}' ret["listen_port"] = listen_port - ret["instance"] = interface + ret["instance"] = __next_instance() # search for a free network used_networks = [] interfaces = utils.get_all_by_type(u, "network", "interface") @@ -648,6 +647,8 @@ def import_configuration(args): config_parser.read_string(data) defaults = get_instance_defaults() + if defaults['instance'] is None: + return utils.generic_error("no_free_instance") e_uci = EUci() e_uci.set('network', defaults['instance'], 'interface') @@ -745,6 +746,8 @@ def add_tunnel(args): return err defaults = get_instance_defaults() + if defaults['instance'] is None: + return utils.generic_error("no_free_instance") e_uci = EUci() e_uci.set('network', defaults['instance'], 'interface') e_uci.set('network', defaults['instance'], 'proto', 'wireguard') From 511bb38daa46323cea4daf498520b1f6d6ec2da7 Mon Sep 17 00:00:00 2001 From: Matteo Di Lorenzi Date: Fri, 9 Oct 2026 10:32:45 +0200 Subject: [PATCH 2/4] fix(wireguard): restart the right interface from wg10 on --- packages/ns-api/files/post-commit/restart-wireguard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ns-api/files/post-commit/restart-wireguard.py b/packages/ns-api/files/post-commit/restart-wireguard.py index 3d24be215..48234ac66 100644 --- a/packages/ns-api/files/post-commit/restart-wireguard.py +++ b/packages/ns-api/files/post-commit/restart-wireguard.py @@ -13,6 +13,6 @@ interfaces_to_restart = [] for entry in changes['network']: if entry[1].startswith('wg'): - interfaces_to_restart.append(entry[1][:3]) + interfaces_to_restart.append(entry[1].split('_')[0]) for item in set(interfaces_to_restart): subprocess.call(f'ifdown {item} ; ifup {item}', shell=True) From 3872cf285a2631903d218895c90ace41e78cce5f Mon Sep 17 00:00:00 2001 From: Matteo Di Lorenzi Date: Fri, 9 Oct 2026 10:32:45 +0200 Subject: [PATCH 3/4] fix(wireguard): suggest the first free listen port --- packages/ns-api/files/ns.wireguard | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/ns-api/files/ns.wireguard b/packages/ns-api/files/ns.wireguard index 8c04b81bc..ae0eefb2b 100644 --- a/packages/ns-api/files/ns.wireguard +++ b/packages/ns-api/files/ns.wireguard @@ -107,23 +107,21 @@ def list_tunnels(): def get_instance_defaults(): u = EUci() ret = {} - next_instance = 1 - for entry in u.get('network'): - if u.get('network', entry, 'proto', default='') == 'wireguard': - next_instance += 1 - if next_instance == 1: - listen_port = 51820 - else: - listen_port = 51820 + next_instance - 1 - ret["listen_port"] = listen_port - ret["instance"] = __next_instance() - # search for a free network + used_ports = [] used_networks = [] interfaces = utils.get_all_by_type(u, "network", "interface") for i in interfaces: interface = interfaces[i] if interface.get("proto") == "wireguard": - used_networks.append(u.get("network", i, "ns_network", default="")) + used_ports.append(interface.get("listen_port", "")) + used_networks.append(interface.get("ns_network", "")) + # search for the first free port + listen_port = 51820 + while str(listen_port) in used_ports: + listen_port += 1 + ret["listen_port"] = listen_port + ret["instance"] = __next_instance() + # search for a free network network = ovpn.random_network() while network in used_networks: network = ovpn.get_random_network() From e7547e05baefb8dda389cd36d1637e407e19d860 Mon Sep 17 00:00:00 2001 From: Matteo Di Lorenzi Date: Fri, 9 Oct 2026 10:32:45 +0200 Subject: [PATCH 4/4] refactor(wireguard): get the tunnel name from __next_instance() --- packages/ns-api/files/ns.wireguard | 62 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/ns-api/files/ns.wireguard b/packages/ns-api/files/ns.wireguard index ae0eefb2b..2bf0903bd 100644 --- a/packages/ns-api/files/ns.wireguard +++ b/packages/ns-api/files/ns.wireguard @@ -644,23 +644,23 @@ def import_configuration(args): config_parser = configparser.ConfigParser(allow_no_value=True) config_parser.read_string(data) - defaults = get_instance_defaults() - if defaults['instance'] is None: + instance = __next_instance() + if instance is None: return utils.generic_error("no_free_instance") e_uci = EUci() - e_uci.set('network', defaults['instance'], 'interface') - e_uci.set('network', defaults['instance'], 'proto', 'wireguard') - e_uci.set('network', defaults['instance'], 'private_key', config_parser["Interface"]["PrivateKey"]) - e_uci.set('network', defaults['instance'], 'addresses', [config_parser["Interface"]["Address"]]) + e_uci.set('network', instance, 'interface') + e_uci.set('network', instance, 'proto', 'wireguard') + e_uci.set('network', instance, 'private_key', config_parser["Interface"]["PrivateKey"]) + e_uci.set('network', instance, 'addresses', [config_parser["Interface"]["Address"]]) if 'DNS' in config_parser['Interface']: - e_uci.set('network', defaults['instance'], 'dns', [ip.strip() for ip in config_parser["Interface"]["DNS"].split(',')]) - e_uci.set('network', defaults['instance'], 'ns_type', 'tunnel') - e_uci.set('network', defaults['instance'], 'ns_name', f"imported_{defaults['instance']}") + e_uci.set('network', instance, 'dns', [ip.strip() for ip in config_parser["Interface"]["DNS"].split(',')]) + e_uci.set('network', instance, 'ns_type', 'tunnel') + e_uci.set('network', instance, 'ns_name', f"imported_{instance}") peer_id = utils.get_random_id() - peer_instance = f"{defaults['instance']}_{peer_id}_peer" - e_uci.set('network', peer_instance, f'wireguard_{defaults["instance"]}') + peer_instance = f"{instance}_{peer_id}_peer" + e_uci.set('network', peer_instance, f'wireguard_{instance}') e_uci.set('network', peer_instance, 'public_key', config_parser["Peer"]["PublicKey"]) if 'PresharedKey' in config_parser['Peer']: e_uci.set('network', peer_instance, 'preshared_key', config_parser["Peer"]["PresharedKey"]) @@ -669,11 +669,11 @@ def import_configuration(args): e_uci.set('network', peer_instance, 'endpoint_port', config_parser["Peer"]["Endpoint"].split(':')[1]) e_uci.set('network', peer_instance, 'route_allowed_ips', True) e_uci.set('network', peer_instance, 'persistent_keepalive', config_parser["Peer"].get("PersistentKeepalive", "25")) - e_uci.set('network', peer_instance, 'ns_link', f'network/{defaults["instance"]}') + e_uci.set('network', peer_instance, 'ns_link', f'network/{instance}') e_uci.save('network') - zone = f"{defaults['instance']}vpn" - firewall.add_trusted_zone(e_uci, zone, link=f"network/{defaults['instance']}") - firewall.add_interface_to_zone(e_uci, defaults['instance'], zone) + zone = f"{instance}vpn" + firewall.add_trusted_zone(e_uci, zone, link=f"network/{instance}") + firewall.add_interface_to_zone(e_uci, instance, zone) except Exception: return utils.validation_error("config", "invalid_file_format") @@ -743,21 +743,21 @@ def add_tunnel(args): if err: return err - defaults = get_instance_defaults() - if defaults['instance'] is None: + instance = __next_instance() + if instance is None: return utils.generic_error("no_free_instance") e_uci = EUci() - e_uci.set('network', defaults['instance'], 'interface') - e_uci.set('network', defaults['instance'], 'proto', 'wireguard') - e_uci.set('network', defaults['instance'], 'private_key', args['peer_private_key']) - e_uci.set('network', defaults['instance'], 'addresses', [args['reserved_ip']]) - e_uci.set('network', defaults['instance'], 'ns_type', 'tunnel') - e_uci.set('network', defaults['instance'], 'ns_name', args['name']) - e_uci.set('network', defaults['instance'], 'disabled', not args['enabled']) + e_uci.set('network', instance, 'interface') + e_uci.set('network', instance, 'proto', 'wireguard') + e_uci.set('network', instance, 'private_key', args['peer_private_key']) + e_uci.set('network', instance, 'addresses', [args['reserved_ip']]) + e_uci.set('network', instance, 'ns_type', 'tunnel') + e_uci.set('network', instance, 'ns_name', args['name']) + e_uci.set('network', instance, 'disabled', not args['enabled']) peer_id = utils.get_random_id() - peer_instance = f"{defaults['instance']}_{peer_id}_peer" - e_uci.set('network', peer_instance, f'wireguard_{defaults["instance"]}') + peer_instance = f"{instance}_{peer_id}_peer" + e_uci.set('network', peer_instance, f'wireguard_{instance}') e_uci.set('network', peer_instance, 'public_key', args['server_public_key']) if 'pre_shared_key' in args and args['pre_shared_key'] != '': e_uci.set('network', peer_instance, 'preshared_key', args['pre_shared_key']) @@ -774,13 +774,13 @@ def add_tunnel(args): e_uci.set('network', peer_instance, 'endpoint_port', args['udp_port']) e_uci.set("network", peer_instance, "route_allowed_ips", True) e_uci.set('network', peer_instance, 'persistent_keepalive', args.get('persistent_keepalive', '25')) - e_uci.set('network', peer_instance, 'ns_link', f'network/{defaults["instance"]}') + e_uci.set('network', peer_instance, 'ns_link', f'network/{instance}') if 'dns' in args: - e_uci.set('network', defaults['instance'], 'dns', args['dns']) + e_uci.set('network', instance, 'dns', args['dns']) e_uci.save('network') - zone = f"{defaults['instance']}vpn" - firewall.add_trusted_zone(e_uci, zone, link=f"network/{defaults['instance']}") - firewall.add_interface_to_zone(e_uci, defaults["instance"], zone) + zone = f"{instance}vpn" + firewall.add_trusted_zone(e_uci, zone, link=f"network/{instance}") + firewall.add_interface_to_zone(e_uci, instance, zone) return {"result": "success"}