fix(gateway): keep DoH-confirmed Telegram IPs that match system DNS (#14520)

discover_fallback_ips() filtered out any DoH-resolved IP that also appeared
in the system resolver's answer set, on the assumption that the system IP
was unreachable. When DoH and system DNS agreed (a common case), the
function returned the hardcoded _SEED_FALLBACK_IPS list instead — and on
networks where those seed addresses are not routable, the Telegram fallback
transport had nothing usable to retry against and polling failed.

Drop the system_ips exclusion so DoH-confirmed IPs are preserved regardless
of system DNS overlap. The TelegramFallbackTransport already tries the
primary path first via system DNS, then falls through to the IP-rewrite
path on connect failure; including the same IP in both lanes lets a
transient primary failure recover via the explicit IP route instead of
escalating to seed addresses.

Update the two tests that codified the old exclusion to reflect the new,
inclusion-by-default behaviour.

Fixes #14520
This commit is contained in:
0xsir0000 2026-04-28 22:06:50 +08:00 committed by Teknium
parent aacf36e943
commit f6b68f0f50
2 changed files with 27 additions and 13 deletions

View file

@ -534,15 +534,20 @@ class TestDiscoverFallbackIps:
assert "149.154.167.221" in ips
@pytest.mark.asyncio
async def test_system_dns_ip_excluded(self, monkeypatch):
"""The IP from system DNS is the one that doesn't work — exclude it."""
async def test_system_dns_ip_kept_when_doh_confirms(self, monkeypatch):
"""DoH-confirmed IPs are kept even when they match system DNS (#14520).
The system-DNS IP is often the most reliable path; including it as a
fallback lets the IP-rewrite retry recover from transient primary-path
failures instead of jumping straight to the hardcoded seed list.
"""
self._patch_doh(monkeypatch, {
"https://dns.google": (200, _doh_answer("149.154.166.110", "149.154.167.220")),
"https://cloudflare-dns.com": (200, _doh_answer("149.154.166.110")),
}, system_dns_ips=["149.154.166.110"])
ips = await tnet.discover_fallback_ips()
assert ips == ["149.154.167.220"]
assert ips == ["149.154.166.110", "149.154.167.220"]
@pytest.mark.asyncio
async def test_doh_results_deduplicated(self, monkeypatch):
@ -607,15 +612,21 @@ class TestDiscoverFallbackIps:
assert "149.154.167.220" in ips
@pytest.mark.asyncio
async def test_all_doh_ips_same_as_system_dns_uses_seed(self, monkeypatch):
"""DoH returns only the same blocked IP — seed list is the fallback."""
async def test_all_doh_ips_same_as_system_dns_kept(self, monkeypatch):
"""DoH agrees with system DNS — keep that IP instead of seed list (#14520).
Previous behavior fell through to ``_SEED_FALLBACK_IPS`` here, but the
seed addresses are not routable on every network. When DoH confirms
the system IP, that IP is the best candidate we have and should be
used as the fallback target.
"""
self._patch_doh(monkeypatch, {
"https://dns.google": (200, _doh_answer("149.154.166.110")),
"https://cloudflare-dns.com": (200, _doh_answer("149.154.166.110")),
}, system_dns_ips=["149.154.166.110"])
ips = await tnet.discover_fallback_ips()
assert ips == tnet._SEED_FALLBACK_IPS
assert ips == ["149.154.166.110"]
@pytest.mark.asyncio
async def test_cloudflare_gets_accept_header(self, monkeypatch):