resident P0+P1: DNS-level SSRF pin, batch budget, daily cap/cooldown/retention, PG schema/migration, dual-connection deadlock isolation, retarget baseline reset, proxy and structured failures, metrics
- DNS 级 SSRF pin:解析后 pin IP 建连,防 DNS 重绑定 - 批量总预算与每日上限/抖动冷却/保留期 - PG schema 与迁移清单 - 双连接死锁隔离 - 改目标重置基线 - 显式代理配置与结构化失败原因 - /metrics resident 口径
This commit is contained in:
1 parent
60997b138f
commit
b391fe9320
9 files changed
+1906
-74
No files matched your search
@@ -16,6 +16,7 @@ from types import SimpleNamespace
|
||||
try:
|
||||
import cloud.resident as resident_module
|
||||
from cloud.resident import (
|
||||
SSRFBlockedError,
|
||||
claim_due_watch,
|
||||
create_watch,
|
||||
default_fetch,
|
||||
@@ -36,6 +37,7 @@ except ImportError: # discover -s cloud/tests 时把项目根目录补进 sys.p
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
import cloud.resident as resident_module
|
||||
from cloud.resident import (
|
||||
SSRFBlockedError,
|
||||
claim_due_watch,
|
||||
create_watch,
|
||||
default_fetch,
|
||||
@@ -416,8 +418,13 @@ class ResidentTestCase(unittest.TestCase):
|
||||
|
||||
|
||||
class RedirectFetchTestCase(unittest.TestCase):
|
||||
"""重定向校验:只把 redirect-test.test 指到本地,其它主机
|
||||
走原始解析;no_proxy 同款处理,tearDown 全部还原。"""
|
||||
"""重定向与 DNS 门校验:默认解析器下 redirect-test.test
|
||||
经 getaddrinfo 补丁指到本地(127.0.0.1),DNS 门必须拦
|
||||
住它(私网解析结果);相对跳转的跟随逻辑走注入的测试
|
||||
resolver(返回公网测试 IP,门正常放行)+ socket 层重定向
|
||||
(测试进程内把该公网 IP:端口指回本地服务——门与 pin
|
||||
逻辑全程真实跑,只有传输层终点是测试替身);no_proxy
|
||||
同款处理,tearDown 全部还原。"""
|
||||
|
||||
HOST = "redirect-test.test"
|
||||
|
||||
@@ -459,6 +466,18 @@ class RedirectFetchTestCase(unittest.TestCase):
|
||||
host, port, family, type, proto, flags)
|
||||
|
||||
socket.getaddrinfo = patched
|
||||
# socket 层测试替身:只重定向公网测试 IP 到本地服务端口,
|
||||
# 其它地址一律走原始 create_connection。
|
||||
self._orig_create_connection = socket.create_connection
|
||||
test_port = self.port
|
||||
|
||||
def patched_create_connection(address, *args, **kwargs):
|
||||
if address[0] == "93.184.216.34" \
|
||||
and address[1] == test_port:
|
||||
address = ("127.0.0.1", test_port)
|
||||
return self._orig_create_connection(address, *args, **kwargs)
|
||||
|
||||
socket.create_connection = patched_create_connection
|
||||
self._old_no_proxy = os.environ.get("no_proxy")
|
||||
self._old_NO_PROXY = os.environ.get("NO_PROXY")
|
||||
os.environ["no_proxy"] = (
|
||||
@@ -469,6 +488,7 @@ class RedirectFetchTestCase(unittest.TestCase):
|
||||
else "") + self.HOST
|
||||
|
||||
def tearDown(self):
|
||||
socket.create_connection = self._orig_create_connection
|
||||
socket.getaddrinfo = self._orig_getaddrinfo
|
||||
if self._old_no_proxy is None:
|
||||
os.environ.pop("no_proxy", None)
|
||||
@@ -484,9 +504,26 @@ class RedirectFetchTestCase(unittest.TestCase):
|
||||
|
||||
def test_relative_redirect_followed_and_private_blocked(self):
|
||||
base = "http://%s:%d" % (self.HOST, self.port)
|
||||
self.assertEqual(default_fetch(base + "/go", 10), "final-body")
|
||||
# 注入 resolver 的跟随路径:解析门放行公网测试 IP,
|
||||
# socket 替身把建连指回本地,相对跳转 /go -> /final 走通。
|
||||
def test_resolver(host, port):
|
||||
return ["93.184.216.34"]
|
||||
|
||||
self.assertEqual(
|
||||
default_fetch(base + "/go", 10, resolver=test_resolver),
|
||||
"final-body")
|
||||
# 默认 DNS 门:测试主机名解析到 127.0.0.1,直接拦住。
|
||||
with self.assertRaises(SSRFBlockedError):
|
||||
default_fetch(base + "/go", 10)
|
||||
# 重定向跳本身:跳转目标是字面私网 IP,逐跳校验拦住。
|
||||
with self.assertRaises(ValueError):
|
||||
default_fetch(base + "/bad", 10)
|
||||
default_fetch(base + "/bad", 10, resolver=test_resolver)
|
||||
# 混合解析结果:任一地址私网即整批拒绝,不取公网那个蒙混。
|
||||
def mixed(host, port):
|
||||
return ["93.184.216.34", "127.0.0.1"]
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
default_fetch(base + "/go", 10, resolver=mixed)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user