fix(sniffing): re-dial upstream on HTTP Host change + surface no-SNI errors

sniffer_http:
When DNS override directs multiple domains to the same proxy IP, the
browser may reuse a keep-alive connection for a different host. The
HTTP keep-alive loop now detects Host header changes and re-dials a
new upstream connection with correct node selection, preventing CDN
errors (Fastly unknown domain, CloudFront 403).

sniffer_tls:
Return a descriptive error when TLS ClientHello has no SNI, instead
of silently returning nil. This makes the connection drop visible in
logs and recorder output.

Fixes go-gost/gost#479
This commit is contained in:
ginuerzh
2026-06-21 16:37:47 +08:00
parent a102f9c6cf
commit e814852ca1
4 changed files with 64 additions and 4 deletions
+23 -1
View File
@@ -93,7 +93,9 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, network string, conn net.Conn,
if err != nil {
return err
}
defer cc.Close()
defer func() { cc.Close() }()
upstreamHost := host
log = log.WithFields(map[string]any{"src": cc.LocalAddr().String(), "dst": cc.RemoteAddr().String()})
@@ -122,6 +124,26 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, network string, conn net.Conn,
log.Trace(string(dump))
}
// When DNS override directs multiple domains to the same proxy IP,
// the browser may reuse a keep-alive connection for a different host.
// Re-dial to ensure requests reach the correct upstream.
if reqHost := normalizeHost(req.Host, "80"); reqHost != upstreamHost {
cc.Close()
cc, err = dial(ctx, network, reqHost)
if err != nil {
return err
}
upstreamHost = reqHost
ro.Host = reqHost
ro.SrcAddr = cc.LocalAddr().String()
ro.DstAddr = cc.RemoteAddr().String()
log = log.WithFields(map[string]any{
"host": reqHost,
"src": cc.LocalAddr().String(),
"dst": cc.RemoteAddr().String(),
})
}
if shouldClose, err := h.httpRoundTrip(ctx, xio.NewReadWriteCloser(br, conn, conn), cc, req, readTimeout, ro, &pStats, log); err != nil || shouldClose {
return err
}
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/hex"
"errors"
"io"
"net"
"time"
@@ -52,7 +53,7 @@ func (h *Sniffer) HandleTLS(ctx context.Context, network string, conn net.Conn,
if log != nil {
log.Debugf("no sni in clienthello from %s", conn.RemoteAddr())
}
return nil
return errors.New("tls: sni is empty, closing connection")
}
ro.Host = host