Do not use custom DNS resolver to dial proxy upstreams
Fixes #439.
When `[network] dns = "tls://..."` (or "https://...") is set, the
resulting *net.Resolver gets attached to the base network's NativeDialer
and was previously also handed to golang.org/x/net/proxy.FromURL via
NewProxyNetwork. As a result, the SOCKS5 client used the user's DoT/DoH
resolver to look up the SOCKS server's own hostname (e.g. "xray" inside
a docker compose stack). Public DNS-over-TLS resolvers don't know about
docker-compose service names, k8s service DNS, /etc/hosts entries, or
corporate split-horizon DNS, so the upstream lookup returned NXDOMAIN
and the proxy chain broke with a misleading "lookup xray on
127.0.0.11:53: no such host" error.
The custom DNS resolver exists to bypass DPI poisoning when resolving
public censored names like Telegram DCs or the SNI/fronting host. Proxy
server addresses are almost always internal and should be resolved via
the system resolver instead. This change introduces proxyServerDialer,
which copies the timeout and fallback-delay from the base dialer but
leaves Resolver==nil, and uses it for the SOCKS upstream.
The new internal test asserts the structural property directly: the
returned dialer must not inherit the base's custom resolver.
Improve TCP keepalive and idle timeout for mobile clients
TCP keepalive was configured (SetKeepAlivePeriod) but never actually
enabled (SO_KEEPALIVE) on accepted client connections. Go 1.26's
SetKeepAlivePeriod only sets TCP_KEEPIDLE — it does not call
setsockopt(SO_KEEPALIVE, 1). Without SO_KEEPALIVE the kernel never
sends probe packets, so dead connections from sleeping mobile clients
linger until the idle timeout fires.
Replace SetKeepAlive + SetKeepAlivePeriod with net.KeepAliveConfig
(available since Go 1.24) for explicit per-socket control:
Idle: 30s (time before first probe)
Interval: 10s (between probes)
Count: 3 (failed probes to declare dead)
This detects dead connections in ~60s instead of relying on system
defaults (tcp_keepalive_intvl=75s, probes=9 → up to 11 minutes).
Increase the default idle timeout from 1 minute to 5 minutes.
MTProto clients send ping_delay_disconnect every ~60s, which resets
the idle timer. The previous 1-minute default created a race: if a
ping arrived even 1–2 seconds late the relay was killed. A 5-minute
window also survives typical mobile sleep periods (phone idle 2–5 min)
where the NAT mapping is still alive and the connection can resume
without reconnection.
Ref: #132
fix: ensure network.Dial and MakeHTTPClient use socks5 proxy
The package `network/v2/proxy_network.go` does not wrap `network.Dial`
and `network.MakeHTTPClient`, which causes them to bypass the SOCKS5
proxy and initiate TCP connections directly from the local machine.