This commit is contained in:
2026-01-14 14:32:46 -08:00
parent 187a230e98
commit 7def5c4464
2 changed files with 101 additions and 82 deletions

View File

@@ -404,6 +404,27 @@ def get_assigned_addresses(network_id: str) -> List[str]:
return []
def get_assigned_subnets(network_id: str) -> List[str]:
"""Return CIDR subnets (e.g. '10.147.17.0/24') for the given network."""
network_id = str(network_id or "").strip()
if not network_id:
return []
subnets = []
for n in list_networks():
if n.id == network_id:
for addr in n.assigned_addresses:
if addr and "/" in addr:
# Calculate subnet base
try:
import ipaddress
net = ipaddress.ip_network(addr, strict=False)
subnets.append(str(net))
except Exception:
pass
return subnets
def fetch_central_members(network_id: str, api_token: str) -> List[Dict[str, Any]]:
"""Fetch member details from ZeroTier Central API.
@@ -518,17 +539,30 @@ def discover_services_on_network(
addr = str(ip).split("/")[0]
if addr not in addresses:
addresses.append(addr)
else:
# Fallback: if no Central token, and we are on a likely /24 subnet,
# we can try to guess/probe peers on that same subnet.
subnets = get_assigned_subnets(net)
for subnet_str in subnets:
try:
import ipaddress
subnet = ipaddress.ip_network(subnet_str, strict=False)
# Only scan if subnet is reasonably small (e.g. <= /24 = 256 hosts)
if subnet.num_addresses <= 256:
for ip in subnet.hosts():
addr = str(ip)
if addr not in addresses:
addresses.append(addr)
except Exception:
pass
probes: List[ZeroTierServiceProbe] = []
for addr in addresses:
host = str(addr or "").strip()
if not host:
continue
# Performance optimization: if we have many addresses, skip those clearly not on our ZT subnet
# (Though fetch_central_members already filters for this network)
# Parallelize probes to make subnet scanning feasible
import concurrent.futures
def do_probe(host):
host_probes = []
for port in ports:
# Try HTTP first as it's the common case for local storage
for scheme in ("http", "https"):
@@ -550,7 +584,7 @@ def discover_services_on_network(
except Exception:
pass
probes.append(ZeroTierServiceProbe(
host_probes.append(ZeroTierServiceProbe(
address=host,
port=int(port),
path=path,
@@ -562,6 +596,18 @@ def discover_services_on_network(
))
# Stop probing other schemes/paths for this host/port
break
return host_probes
# Use ThreadPoolExecutor for concurrent I/O probes
max_workers = min(50, len(addresses) or 1)
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_addr = {executor.submit(do_probe, addr): addr for addr in addresses}
for future in concurrent.futures.as_completed(future_to_addr):
try:
probes.extend(future.result())
except Exception:
pass
return probes