fix: deterministic inbound link matching by port
Panel duplicate client entries across inbounds made the first-unseen matcher serve wrong links (e.g. Moscow Direct got :46457 instead of :37744), nondeterministically per cache rebuild. Match candidates by inbound port from servers.conf, falling back to legacy behavior when no port matches.
This commit is contained in:
+37
-5
@@ -526,6 +526,22 @@ def _link_protocol(link: str) -> str:
|
||||
def _get_inbound_protocol(inbound: dict) -> str:
|
||||
return inbound.get("protocol", "vless")
|
||||
|
||||
def _link_port(link: str) -> Optional[int]:
|
||||
"""Extract port number from a proxy link URI. Returns None if unparseable."""
|
||||
try:
|
||||
body = link.split('#')[0]
|
||||
# scheme://[userinfo@]host:port[?...]
|
||||
after_scheme = body.split("://", 1)[1]
|
||||
hostport = after_scheme.split("@")[-1].split("?")[0].split("/")[0]
|
||||
if ":" not in hostport:
|
||||
return None
|
||||
port_str = hostport.rsplit(":", 1)[1]
|
||||
# strip IPv6 brackets edge: [::1]:port
|
||||
port_str = port_str.rstrip("]")
|
||||
return int(port_str)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _build_hysteria_link(panel_link: str, sub_id: str, srv: dict) -> Optional[str]:
|
||||
"""Rebuild panel hysteria2://AUTH@host:port link into a working client link.
|
||||
|
||||
@@ -999,13 +1015,29 @@ async def get_subscription(request: Request, subscription_id: str, format: str =
|
||||
continue
|
||||
|
||||
ib_protocol = _get_inbound_protocol(inbound)
|
||||
ib_port = inbound.get("port")
|
||||
matched_link = None
|
||||
fallback_link = None
|
||||
for candidate in links:
|
||||
if _link_protocol(candidate) == ib_protocol:
|
||||
clean_candidate = candidate.split('#')[0]
|
||||
if clean_candidate not in seen_links:
|
||||
matched_link = candidate
|
||||
break
|
||||
if _link_protocol(candidate) != ib_protocol:
|
||||
continue
|
||||
clean_candidate = candidate.split('#')[0]
|
||||
if clean_candidate in seen_links:
|
||||
continue
|
||||
# Prefer the link whose port matches this inbound's port.
|
||||
# Duplicate client entries across inbounds otherwise make
|
||||
# the match nondeterministic (wrong port served).
|
||||
if ib_port is not None and _link_port(candidate) == ib_port:
|
||||
matched_link = candidate
|
||||
break
|
||||
if fallback_link is None:
|
||||
fallback_link = candidate
|
||||
|
||||
if matched_link is None:
|
||||
# No port match (e.g. panel changed ports and servers.conf
|
||||
# is stale): fall back to legacy first-unseen behavior so
|
||||
# the profile is still served instead of dropped.
|
||||
matched_link = fallback_link
|
||||
|
||||
if not matched_link:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user