Releases: Scratch-net/telego
v0.3.5
Highlights
Critical Fix: Hybrid TLS Mode Broken with TLS 1.2 Mask Hosts
Hybrid ServerHello mode was sending the entire server TLS response (ServerHello + Certificate + ServerKeyExchange + ServerHelloDone + ChangeCipherSpec + Finished) instead of just the ServerHello record. Telegram clients verify an HMAC over the response structure and expect ServerHello + ChangeCipherSpec + ApplicationData — the extra records caused HMAC verification to fail, disconnecting every client immediately after handshake.
Symptoms: Clients authenticate successfully (matched secret) but disconnect within 1-2ms. Logs show DC 0 closed (1ms) with no "dialing DC" message.
Fix
ServerHelloFetchernow captures only the first TLS record (ServerHello) from the mask hostbuildHybridServerHelloappends synthetic ChangeCipherSpec + ApplicationData after the real ServerHello record, matching the packet structure Telegram clients expect
This fix restores compatibility with TLS 1.2 mask hosts (where the server response includes multiple handshake records). TLS 1.3 hosts were less likely to be affected since they naturally produce the ServerHello + CCS + AppData pattern.
Full Changelog: v0.3.4...v0.3.5
v0.3.4
Highlights
Connection Leak Fix
Discovered that gnet's SetReadDeadline is epoll-based and only fires on read attempts. Connections that never send data (probes, scanners, bots) stayed open indefinitely, accumulating until the proxy stopped accepting new connections.
Fixed with an active time.AfterFunc timer that closes any connection still in pre-auth state after the handshake deadline.
Per-IP Limiting Covers All Connections
max-connections-per-ip previously only applied after authentication. Now enforced at TCP accept time — unauthenticated floods from a single IP are blocked before any protocol work begins.
Splice Idle Timeout
Spliced (unrecognized) connections now have a dedicated shorter idle timeout (default 30s) instead of sharing the authenticated connection timeout (5m).
What's Changed
Fixes
- Silent connections (no data sent) are now actively killed after handshake timeout
- Per-IP connection limit enforced in
OnOpenbefore authentication - Splice path now clears handshake deadline and sets its own idle timeout
New Config Options
handshake-timeout— max time for handshake before dropping (default5s, was hardcoded30s)splice-idle-timeout— idle timeout for spliced connections (default30s)
Full Changelog: v0.3.3...v0.3.4
v0.3.3
Highlights
DD (Direct Data) Mode
Proxy now accepts both EE (fake TLS) and DD (raw obfuscated2) connections on the same port. Protocol is auto-detected from the first bytes — no configuration needed.
DD mode skips the TLS layer entirely, which can help in environments where TLS-in-TLS is problematic. Both modes work simultaneously on the same port.
DD Link Generation
telego generate now outputs both EE and DD proxy links, so users can pick whichever works best for their setup.
ARMv7 Support
CI now builds for ARMv7 (32-bit ARM), expanding support to older Raspberry Pi and similar devices.
What's Changed
New Features
- Auto-detect EE vs DD protocol from first bytes of connection
- DD frame handler and relay pipeline
BuildDDSecretfor DD link generationtelego generateoutputs both EE and DD links- ARMv7 build target in CI
Full Changelog: v0.3.2...v0.3.3
v0.3.2
What's Changed
Fixes
- Fixed version indicator not displaying correctly in CLI output
Full Changelog: v0.3.1...v0.3.2
v0.3.1
Highlights
Hybrid TLS Mode
Real ServerHello from mask host is now fetched and used during handshake, making the TLS fingerprint indistinguishable from a genuine connection to the mask domain.
Improved Metrics
- More accurate per-user connection counting in stats
- Better traffic statistics tracking even with limiting disabled
CI & Testing
- GitHub Actions pipeline: build, test, lint, coverage
- Comprehensive test suite expansion across all packages
- Codecov integration for coverage tracking
What's Changed
Fixes
- Hybrid TLS handshake using real ServerHello from mask host
- More accurate connection counting in
UserIPLimiter.Stats() - Removed unused
cachedHellofield
Infrastructure
- CI pipeline with GitHub Actions
- Expanded test coverage
- Bumped codecov/codecov-action from v5 to v6
Full Changelog: v0.3.0...v0.3.1
v0.3.0
Highlights
Per-User IP Limiting
Prevent secret sharing by limiting how many unique IPs can use each secret. When a user exceeds the limit, old IPs are blocked temporarily.
max-ips-per-user = 3 # Max 3 devices/locations per secret
ip-block-timeout = "5m" # Blocked IPs can retry after 5 minutesSmart IP Blocking
Users who legitimately disconnect (close the app) won't be blocked when evicted. Only IPs with active connections are blocked — so switching between WiFi and mobile works naturally.
Enhanced Metrics
- Per-user traffic stats now available via Prometheus
- Active and blocked IP lists exposed in metrics
- Stats tracking works even when limiting is disabled
What's Changed
New Features
max-ips-per-userconfig option replaces the old per-IP limiterip-block-timeoutcontrols how long blocked IPs stay blocked- Per-user IP lists in Prometheus metrics
Improvements
- Smart blocking: disconnected IPs aren't blocked on eviction
- Backpressure with hysteresis prevents oscillation at thresholds
- Cross-event-loop safety improvements for gnet architecture
Full Changelog: v0.2.1...v0.3.0
v0.2.1
Stability Release
Bug fixes and stability improvements.
Fixed
- Crash fixes — Resolved panic conditions that could occur under certain edge cases
- Dependency updates — Updated internal packages for better compatibility
Changed
- Docker images now update
:latesttag on every push for easier deployment
Full Changelog: v0.2.0...v0.2.1
v0.2.0
Async I/O & IPv6 Fixes
Critical stability fixes for the gnet event-driven architecture.
Fixed
- Concurrent map crash — Switched to
AsyncWritefor cross-event-loop writes, preventing race conditions that caused crashes under load - IPv6 probe via SOCKS5 — Skip IPv6 DC probing when using SOCKS5 upstream (most SOCKS5 proxies don't support IPv6)
- IP preference respected —
prefer-ipv4/prefer-ipv6settings now correctly affect DC dial order
Technical Details
Using sync Write() on a connection from a different event loop could trigger c.loop.close() from the wrong goroutine, causing concurrent map writes in gnet's connMatrix. AsyncWrite queues the operation to the owning event loop via poller.Trigger().
Full Changelog: v0.1.9...v0.2.0
v0.1.9
Smarter DC Probing
Improved datacenter selection and another async write fix.
Changed
- Probe via handshake, not ping — DC probing now uses actual MTProto handshake instead of ICMP ping. This gives more accurate RTT measurements and works through firewalls that block ping.
Fixed
- AsyncWrite for DC→client — Prevents concurrent map crash when forwarding data from Telegram DC to client connection (same class of bug fixed more completely in v0.2.0)
Full Changelog: v0.1.8...v0.1.9
v0.1.8
Backpressure & Memory Optimization
Major performance release focused on handling slow clients without running out of memory.
New Features
- Backpressure flow control — Automatically throttles data from Telegram when client can't keep up. Prevents OOM on slow connections (mobile, congested networks).
- Security improvements — Ported hardening measures from telemt (Rust MTProxy)
Fixed
- Memory leak — Resolved buffer accumulation issues under sustained load
- Reduced allocations — Sync writes optimization cuts memory churn in hot paths
Technical Details
Backpressure uses soft/hard buffer limits:
- Above soft limit (2MB): throttle to 64KB chunks
- Above hard limit (4MB): trickle mode at 16KB chunks
- TCP backpressure naturally propagates to Telegram DC
Full Changelog: v0.1.7...v0.1.8