81db46b725
- Fix dead-code branch in bind.go host assignment (always use endpoint hash) - Return descriptive error on bypass match in connect.go (was masking as success) - Update bypass test in connect_test.go for new error behavior - Extract entrypoint subpackage from monolithic entrypoint.go (6 files) - Fix observeStats event-loss bug (break -> fallthrough on retry success) - Add 47 unit tests across handler, connect, bind, metadata packages - Add architecture doc comments to all key files - Build and vet clean, 173 tests pass with -race
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package entrypoint
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/hex"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-gost/core/logger"
|
|
dissector "github.com/go-gost/tls-dissector"
|
|
ictx "github.com/go-gost/x/internal/ctx"
|
|
xio "github.com/go-gost/x/internal/io"
|
|
xnet "github.com/go-gost/x/internal/net"
|
|
tls_util "github.com/go-gost/x/internal/util/tls"
|
|
xrecorder "github.com/go-gost/x/recorder"
|
|
)
|
|
|
|
// handleTLS processes a TLS connection arriving at the entrypoint.
|
|
//
|
|
// Flow:
|
|
// 1. Parse ClientHello (tee-reads first bytes for recording).
|
|
// 2. Extract SNI hostname → ingress lookup → tunnelID.
|
|
// 3. ep.dial() → Dialer.Dial() → mux stream (or SD TCP connection).
|
|
// 4. Write buffered ClientHello bytes to the mux stream.
|
|
// 5. Parse ServerHello from the mux stream (for TLS recording).
|
|
// 6. Write ServerHello bytes back to the public connection.
|
|
// 7. Pipe(publicConn, muxStream) — bidirectional TLS passthrough.
|
|
func (ep *Entrypoint) handleTLS(ctx context.Context, conn net.Conn, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
|
|
buf := new(bytes.Buffer)
|
|
clientHello, err := dissector.ParseClientHello(io.TeeReader(conn, buf))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ro.TLS = &xrecorder.TLSRecorderObject{
|
|
ServerName: clientHello.ServerName,
|
|
ClientHello: hex.EncodeToString(buf.Bytes()),
|
|
}
|
|
if len(clientHello.SupportedProtos) > 0 {
|
|
ro.TLS.Proto = clientHello.SupportedProtos[0]
|
|
}
|
|
|
|
host := clientHello.ServerName
|
|
if host != "" {
|
|
if _, _, err := net.SplitHostPort(host); err != nil {
|
|
host = net.JoinHostPort(strings.Trim(host, "[]"), "443")
|
|
}
|
|
ro.Host = host
|
|
}
|
|
|
|
// ctx = xctx.ContextWithClientAddr(ctx, xctx.ClientAddr(ro.RemoteAddr))
|
|
ctx = ictx.ContextWithRecorderObject(ctx, ro)
|
|
ctx = ictx.ContextWithLogger(ctx, log)
|
|
|
|
cc, err := ep.dial(ctx, "tcp", host)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer cc.Close()
|
|
|
|
if _, err := buf.WriteTo(cc); err != nil {
|
|
return err
|
|
}
|
|
|
|
xio.SetReadDeadline(cc, time.Now().Add(ep.readTimeout))
|
|
serverHello, err := dissector.ParseServerHello(io.TeeReader(cc, buf))
|
|
xio.SetReadDeadline(cc, time.Time{})
|
|
|
|
if serverHello != nil {
|
|
ro.TLS.CipherSuite = tls_util.CipherSuite(serverHello.CipherSuite).String()
|
|
ro.TLS.CompressionMethod = serverHello.CompressionMethod
|
|
if serverHello.Proto != "" {
|
|
ro.TLS.Proto = serverHello.Proto
|
|
}
|
|
if serverHello.Version > 0 {
|
|
ro.TLS.Version = tls_util.Version(serverHello.Version).String()
|
|
}
|
|
}
|
|
|
|
if buf.Len() > 0 {
|
|
ro.TLS.ServerHello = hex.EncodeToString(buf.Bytes())
|
|
}
|
|
|
|
if _, err := buf.WriteTo(conn); err != nil {
|
|
return err
|
|
}
|
|
|
|
// xnet.Transport(conn, cc)
|
|
xnet.Pipe(ctx, conn, cc)
|
|
return err
|
|
} |