starnet/tlsconfig.go
starainrt 9ac9b65bc5
fix(starnet): 收紧 TLS ClientHello 嗅探并补齐边界测试
- 用轻量 ClientHello 解析替代假握手式 TLS 嗅探
  - 保留截断和 max-bytes 场景下的 TLS 分类与缓冲回放能力
  - 拒绝首个 record 完整但并非 ClientHello 的伪 TLS 流量
  - 为动态 TLS 配置选择透出更完整的 ClientHello 元数据
  - 拆分 TLS 初始化失败统计为 sniff/config/plain rejected
  - 补充正常、分片、截断、限长、伪 TLS 等回归测试
2026-03-27 12:05:23 +08:00

91 lines
2.4 KiB
Go

package starnet
import (
"crypto/tls"
"net"
"time"
)
// GetConfigForClientFunc selects TLS config by hostname/SNI.
type GetConfigForClientFunc func(hostname string) (*tls.Config, error)
// 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)
// ListenerConfig controls listener behavior.
type ListenerConfig struct {
// BaseTLSConfig is used for TLS when dynamic selection returns nil.
BaseTLSConfig *tls.Config
// GetConfigForClient selects TLS config for a hostname/SNI.
// Deprecated: prefer GetConfigForClientHello for richer context.
GetConfigForClient GetConfigForClientFunc
// GetConfigForClientHello selects TLS config for sniffed TLS metadata.
GetConfigForClientHello GetConfigForClientHelloFunc
// 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
}