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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user