mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-09 01:31:05 +08:00
fix(security): release SSRF DNS inflight lock outside async with block (#5834)
This commit is contained in:
@@ -210,7 +210,11 @@ class SecurityUtils:
|
||||
def _release_inflight_lock(hostname: str, lock: asyncio.Lock) -> None:
|
||||
"""
|
||||
请求结束后清理 in-flight 锁,避免长期持有大量已闲置的 `asyncio.Lock`。
|
||||
只有当前 lock 仍是字典里登记的那把、且没有其它协程在等待时才删除。
|
||||
|
||||
仅当字典中登记的仍是当前 lock,且 `lock.locked()` 为 False 时才删除。
|
||||
`asyncio.Lock` 公平 FIFO:持有者释放后若仍有等待者,锁会立刻被下一个
|
||||
等待者接走、`locked()` 重新变为 True,因此该守卫可同时排除"仍有持有者"
|
||||
与"刚被等待者接走"两种情况,避免误删后续协程仍在使用的字典条目。
|
||||
"""
|
||||
with _dns_inflight_meta_lock:
|
||||
current = _dns_inflight_locks.get(hostname)
|
||||
@@ -238,26 +242,28 @@ class SecurityUtils:
|
||||
return value
|
||||
|
||||
lock = SecurityUtils._get_inflight_lock(hostname)
|
||||
async with lock:
|
||||
# 等到锁后再查一次缓存,前一个持锁者可能已经回填结果
|
||||
hit, value = SecurityUtils._cache_lookup(hostname)
|
||||
if hit:
|
||||
SecurityUtils._release_inflight_lock(hostname, lock)
|
||||
return value
|
||||
try:
|
||||
async with lock:
|
||||
# 等到锁后再查一次缓存,前一个持锁者可能已经回填结果
|
||||
hit, value = SecurityUtils._cache_lookup(hostname)
|
||||
if hit:
|
||||
return value
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
try:
|
||||
address_infos = await loop.getaddrinfo(
|
||||
hostname, None, type=socket.SOCK_STREAM
|
||||
)
|
||||
except socket.gaierror:
|
||||
SecurityUtils._cache_store(hostname, None)
|
||||
SecurityUtils._release_inflight_lock(hostname, lock)
|
||||
return None
|
||||
addresses = _resolve_addrinfo_to_ips(address_infos)
|
||||
SecurityUtils._cache_store(hostname, addresses)
|
||||
SecurityUtils._release_inflight_lock(hostname, lock)
|
||||
return addresses
|
||||
loop = asyncio.get_running_loop()
|
||||
try:
|
||||
address_infos = await loop.getaddrinfo(
|
||||
hostname, None, type=socket.SOCK_STREAM
|
||||
)
|
||||
except socket.gaierror:
|
||||
SecurityUtils._cache_store(hostname, None)
|
||||
return None
|
||||
addresses = _resolve_addrinfo_to_ips(address_infos)
|
||||
SecurityUtils._cache_store(hostname, addresses)
|
||||
return addresses
|
||||
finally:
|
||||
# 必须在 `async with` 释放锁之后再清理字典:`_release_inflight_lock`
|
||||
# 以 `not lock.locked()` 为清理守卫,持锁状态下调用会跳过 pop。
|
||||
SecurityUtils._release_inflight_lock(hostname, lock)
|
||||
|
||||
@staticmethod
|
||||
def _addresses_all_global(
|
||||
|
||||
Reference in New Issue
Block a user