2026-03-08 20:19:40 +08:00
|
|
|
package starnet
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/tls"
|
|
|
|
|
"net"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// GetConfigForClientFunc selects TLS config by hostname/SNI.
|
|
|
|
|
type GetConfigForClientFunc func(hostname string) (*tls.Config, error)
|
|
|
|
|
|
2026-03-27 12:05:23 +08:00
|
|
|
// ClientHelloMeta carries sniffed TLS metadata and connection context.
|
|
|
|
|
type ClientHelloMeta struct {
|
|
|
|
|
ServerName string
|
|
|
|
|
LocalAddr net.Addr
|
|
|
|
|
RemoteAddr net.Addr
|
|
|
|
|
SupportedProtos []string
|
|
|
|
|
SupportedVersions []uint16
|
|
|
|
|
CipherSuites []uint16
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clone returns a detached copy safe for callers to mutate.
|
|
|
|
|
func (m *ClientHelloMeta) Clone() *ClientHelloMeta {
|
|
|
|
|
if m == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
out := *m
|
|
|
|
|
if m.SupportedProtos != nil {
|
|
|
|
|
out.SupportedProtos = append([]string(nil), m.SupportedProtos...)
|
|
|
|
|
}
|
|
|
|
|
if m.SupportedVersions != nil {
|
|
|
|
|
out.SupportedVersions = append([]uint16(nil), m.SupportedVersions...)
|
|
|
|
|
}
|
|
|
|
|
if m.CipherSuites != nil {
|
|
|
|
|
out.CipherSuites = append([]uint16(nil), m.CipherSuites...)
|
|
|
|
|
}
|
|
|
|
|
return &out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetConfigForClientHelloFunc selects TLS config by sniffed TLS metadata.
|
|
|
|
|
type GetConfigForClientHelloFunc func(hello *ClientHelloMeta) (*tls.Config, error)
|
|
|
|
|
|
2026-03-08 20:19:40 +08:00
|
|
|
// ListenerConfig controls listener behavior.
|
|
|
|
|
type ListenerConfig struct {
|
|
|
|
|
// BaseTLSConfig is used for TLS when dynamic selection returns nil.
|
|
|
|
|
BaseTLSConfig *tls.Config
|
|
|
|
|
|
2026-03-27 12:05:23 +08:00
|
|
|
// GetConfigForClient selects TLS config for a hostname/SNI.
|
|
|
|
|
// Deprecated: prefer GetConfigForClientHello for richer context.
|
2026-03-08 20:19:40 +08:00
|
|
|
GetConfigForClient GetConfigForClientFunc
|
|
|
|
|
|
2026-03-27 12:05:23 +08:00
|
|
|
// GetConfigForClientHello selects TLS config for sniffed TLS metadata.
|
|
|
|
|
GetConfigForClientHello GetConfigForClientHelloFunc
|
|
|
|
|
|
2026-03-08 20:19:40 +08:00
|
|
|
// AllowNonTLS allows plain TCP fallback.
|
|
|
|
|
AllowNonTLS bool
|
|
|
|
|
|
|
|
|
|
// SniffTimeout bounds protocol sniffing time. 0 means no timeout.
|
|
|
|
|
SniffTimeout time.Duration
|
|
|
|
|
|
|
|
|
|
// MaxClientHelloBytes limits buffered sniff data.
|
|
|
|
|
// If <= 0, default 64KiB.
|
|
|
|
|
MaxClientHelloBytes int
|
|
|
|
|
|
|
|
|
|
// Logger is optional.
|
|
|
|
|
Logger Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultListenerConfig returns a conservative default config.
|
|
|
|
|
func DefaultListenerConfig() ListenerConfig {
|
|
|
|
|
return ListenerConfig{
|
|
|
|
|
AllowNonTLS: false,
|
|
|
|
|
SniffTimeout: 5 * time.Second,
|
|
|
|
|
MaxClientHelloBytes: 64 * 1024,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TLSDefaults returns a TLS config baseline.
|
|
|
|
|
// Caller should set Certificates / GetCertificate as needed.
|
|
|
|
|
func TLSDefaults() *tls.Config {
|
|
|
|
|
return &tls.Config{
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DialConfig controls dialing behavior.
|
|
|
|
|
type DialConfig struct {
|
|
|
|
|
Timeout time.Duration
|
|
|
|
|
LocalAddr net.Addr
|
|
|
|
|
}
|