Skip to content

feat(telegram): auto-discover fallback IPs via DoH when api.telegram.org is unreachable#3376

Merged
teknium1 merged 3 commits intomainfrom
hermes/hermes-140430f8
Mar 27, 2026
Merged

feat(telegram): auto-discover fallback IPs via DoH when api.telegram.org is unreachable#3376
teknium1 merged 3 commits intomainfrom
hermes/hermes-140430f8

Conversation

@teknium1
Copy link
Copy Markdown
Contributor

Summary

Salvaged from PR #3129 by @Gavin-Qiao. Closes #3128.

On restricted networks (university, corporate), api.telegram.org may resolve to an IP that is unreachable due to routing or firewall rules. This PR adds automatic fallback IP discovery via DNS-over-HTTPS so the Telegram adapter can find and use an alternative endpoint.

How it works

  1. On gateway startup, the Telegram adapter queries Google DoH (dns.google/resolve) and Cloudflare DoH (cloudflare-dns.com/dns-query) in parallel for api.telegram.org A records
  2. System-DNS-resolved IPs are excluded (they're presumably the unreachable ones)
  3. Remaining IPs become fallback candidates
  4. If DoH is also blocked, falls back to a seed IP (149.154.167.220 — verified in Telegram's 149.154.160.0/20 range, AS62041)
  5. A custom TelegramFallbackTransport (httpx async transport) tries the primary endpoint first, then sticks to the first working fallback IP

Security audit

Verified safe:

  • TLS cert verification preserved: sni_hostname extension controls both SNI and certificate hostname verification in httpx → httpcore → Python ssl. A malicious IP would fail the TLS handshake (no valid cert for api.telegram.org)
  • No verify=False anywhere — default httpx TLS verification used
  • DoH endpoints verified: dns.google/resolve and cloudflare-dns.com/dns-query confirmed via official Google/Cloudflare developer docs
  • Seed IP verified: 149.154.167.220 is in Telegram's official CIDR range (core.telegram.org/resources/cidr.txt), announced by AS62041 with valid RPKI/ROA

On healthy networks, behavior is unchanged — the primary connection succeeds immediately.

Files changed

File Change
gateway/platforms/telegram_network.py New — fallback transport, DoH discovery, IP validation (233 lines)
gateway/platforms/telegram.py Wire fallback transport into Application builder
gateway/config.py TELEGRAM_FALLBACK_IPS env var support
tests/gateway/test_telegram_network.py New — 44 tests for transport + discovery
5 existing test files Add telegram.request mock + _no_auto_discovery fixture

Follow-up fixes (on top of cherry-pick)

  • Added telegram.request mock to test_dm_topics.py and test_telegram_network_reconnect.py (missed by original PR)
  • Added _no_auto_discovery fixture to reconnect test (reconnect handler calls connect() which now invokes discover_fallback_ips())

Test plan

  • 224 telegram-specific tests passed, 0 failures

Gavin-Qiao and others added 3 commits March 27, 2026 03:56
…org is unreachable

On some networks (university, corporate), api.telegram.org resolves to a
valid Telegram IP that is unreachable due to routing/firewall rules. A
different IP in the same Telegram-owned 149.154.160.0/20 block works fine.

This adds automatic fallback IP discovery at connect time:
1. Query Google and Cloudflare DNS-over-HTTPS for api.telegram.org A records
2. Exclude the system-DNS IP (the unreachable one), use the rest as fallbacks
3. If DoH is also blocked, fall back to a seed list (149.154.167.220)
4. TelegramFallbackTransport tries primary first, sticks to whichever works

No configuration needed — works automatically. TELEGRAM_FALLBACK_IPS env var
still available as manual override. Zero impact on healthy networks (primary
path succeeds on first attempt, fallback never exercised).

No new dependencies (uses httpx already in deps + stdlib socket).
- Use single TelegramFallbackTransport shared between request and
  get_updates_request so sticky IP is shared across polling and API calls
- Keep separate HTTPXRequest instances (different timeout settings)
- Downgrade "using seed fallback IPs" from warning to info to avoid
  noisy logs on healthy networks
…t files

The original PR missed test_dm_topics.py and
test_telegram_network_reconnect.py — both need the telegram.request
mock module. The reconnect test also needs _no_auto_discovery since
_handle_polling_network_error calls connect() which now invokes
discover_fallback_ips().
@teknium1 teknium1 merged commit 75fcbc4 into main Mar 27, 2026
2 checks passed
StreamOfRon pushed a commit to StreamOfRon/hermes-agent that referenced this pull request Mar 29, 2026
…org is unreachable (NousResearch#3376)

* feat(telegram): auto-discover fallback IPs via DoH when api.telegram.org is unreachable

On some networks (university, corporate), api.telegram.org resolves to a
valid Telegram IP that is unreachable due to routing/firewall rules. A
different IP in the same Telegram-owned 149.154.160.0/20 block works fine.

This adds automatic fallback IP discovery at connect time:
1. Query Google and Cloudflare DNS-over-HTTPS for api.telegram.org A records
2. Exclude the system-DNS IP (the unreachable one), use the rest as fallbacks
3. If DoH is also blocked, fall back to a seed list (149.154.167.220)
4. TelegramFallbackTransport tries primary first, sticks to whichever works

No configuration needed — works automatically. TELEGRAM_FALLBACK_IPS env var
still available as manual override. Zero impact on healthy networks (primary
path succeeds on first attempt, fallback never exercised).

No new dependencies (uses httpx already in deps + stdlib socket).

* fix: share transport instance and downgrade seed fallback log to info

- Use single TelegramFallbackTransport shared between request and
  get_updates_request so sticky IP is shared across polling and API calls
- Keep separate HTTPXRequest instances (different timeout settings)
- Downgrade "using seed fallback IPs" from warning to info to avoid
  noisy logs on healthy networks

* fix: add telegram.request mock and discovery fixture to remaining test files

The original PR missed test_dm_topics.py and
test_telegram_network_reconnect.py — both need the telegram.request
mock module. The reconnect test also needs _no_auto_discovery since
_handle_polling_network_error calls connect() which now invokes
discover_fallback_ips().

---------

Co-authored-by: Mohan Qiao <Gavin-Qiao@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Auto-discover working Telegram API endpoints when primary IP is unreachable

2 participants