- 新增 internal/sslutil/tlsconfig.go 统一 TLS 配置函数 - 提取 ParseTLSVersion/ParseCipherSuites/DefaultCipherSuites 等 - 更新 ssl.go/stream/ssl.go/proxy_ssl.go 使用统一函数 - 消除约 150 行重复代码 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
215 lines
4.9 KiB
Go
215 lines
4.9 KiB
Go
// Package stream 提供 TCP/UDP Stream 代理功能。
|
||
//
|
||
// 该文件实现 Stream 模块的 SSL/TLS 支持,包括:
|
||
// - 服务端 TLS 终端
|
||
// - 客户端 TLS 连接(上游 SSL)
|
||
// - 证书加载和配置
|
||
// - mTLS 客户端证书验证
|
||
//
|
||
// 作者:xfy
|
||
package stream
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"crypto/x509"
|
||
"fmt"
|
||
"sync"
|
||
|
||
"rua.plus/lolly/internal/config"
|
||
"rua.plus/lolly/internal/logging"
|
||
"rua.plus/lolly/internal/sslutil"
|
||
)
|
||
|
||
// SSLManager 管理 Stream SSL/TLS 配置。
|
||
//
|
||
// 负责加载证书、配置 TLS 连接,支持服务端和客户端两种模式。
|
||
type SSLManager struct {
|
||
cert tls.Certificate
|
||
clientCAPool *x509.CertPool
|
||
config config.StreamSSLConfig
|
||
mu sync.RWMutex
|
||
}
|
||
|
||
// ProxySSLManager 管理上游 SSL 连接。
|
||
//
|
||
// 负责创建到上游服务器的 TLS 连接,支持证书验证和客户端证书。
|
||
type ProxySSLManager struct {
|
||
cert tls.Certificate
|
||
rootCAPool *x509.CertPool
|
||
config config.StreamProxySSLConfig
|
||
mu sync.RWMutex
|
||
}
|
||
|
||
// NewSSLManager 创建 Stream SSL 管理器。
|
||
//
|
||
// 参数:
|
||
// - cfg: SSL 配置
|
||
//
|
||
// 返回值:
|
||
// - *SSLManager: SSL 管理器实例
|
||
// - error: 证书加载失败时返回错误
|
||
func NewSSLManager(cfg config.StreamSSLConfig) (*SSLManager, error) {
|
||
if !cfg.Enabled {
|
||
return &SSLManager{config: cfg}, nil
|
||
}
|
||
|
||
// 加载服务器证书
|
||
cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to load server certificate: %w", err)
|
||
}
|
||
|
||
mgr := &SSLManager{
|
||
config: cfg,
|
||
cert: cert,
|
||
}
|
||
|
||
// 加载客户端 CA 证书(mTLS)
|
||
if cfg.ClientCA != "" {
|
||
pool, err := sslutil.LoadCertPool(cfg.ClientCA, "client CA")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to load client CA: %w", err)
|
||
}
|
||
mgr.clientCAPool = pool
|
||
}
|
||
|
||
return mgr, nil
|
||
}
|
||
|
||
// NewProxySSLManager 创建上游 SSL 管理器。
|
||
//
|
||
// 参数:
|
||
// - cfg: 代理 SSL 配置
|
||
//
|
||
// 返回值:
|
||
// - *ProxySSLManager: 代理 SSL 管理器实例
|
||
// - error: 证书加载失败时返回错误
|
||
func NewProxySSLManager(cfg config.StreamProxySSLConfig) (*ProxySSLManager, error) {
|
||
if !cfg.Enabled {
|
||
return &ProxySSLManager{config: cfg}, nil
|
||
}
|
||
|
||
mgr := &ProxySSLManager{config: cfg}
|
||
|
||
// 加载客户端证书(mTLS)
|
||
if cfg.Cert != "" && cfg.Key != "" {
|
||
cert, err := tls.LoadX509KeyPair(cfg.Cert, cfg.Key)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to load client certificate: %w", err)
|
||
}
|
||
mgr.cert = cert
|
||
}
|
||
|
||
// 加载信任的 CA 证书
|
||
if cfg.TrustedCA != "" {
|
||
pool, err := sslutil.LoadCertPool(cfg.TrustedCA, "trusted CA")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to load trusted CA: %w", err)
|
||
}
|
||
mgr.rootCAPool = pool
|
||
}
|
||
|
||
return mgr, nil
|
||
}
|
||
|
||
// GetTLSConfig 获取服务端 TLS 配置。
|
||
//
|
||
// 返回值:
|
||
// - *tls.Config: TLS 配置对象
|
||
func (m *SSLManager) GetTLSConfig() *tls.Config {
|
||
m.mu.RLock()
|
||
defer m.mu.RUnlock()
|
||
|
||
if !m.config.Enabled {
|
||
return nil
|
||
}
|
||
|
||
tlsConfig := &tls.Config{
|
||
Certificates: []tls.Certificate{m.cert},
|
||
MinVersion: tls.VersionTLS12,
|
||
}
|
||
|
||
// 设置协议版本
|
||
if len(m.config.Protocols) > 0 {
|
||
tlsConfig.MinVersion = sslutil.ParseMinTLSVersion(m.config.Protocols)
|
||
}
|
||
|
||
// 设置加密套件
|
||
if len(m.config.Ciphers) > 0 {
|
||
tlsConfig.CipherSuites = sslutil.ParseCipherSuitesLenient(m.config.Ciphers)
|
||
}
|
||
|
||
// 配置客户端证书验证(mTLS)
|
||
if m.clientCAPool != nil {
|
||
tlsConfig.ClientCAs = m.clientCAPool
|
||
tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven
|
||
}
|
||
|
||
return tlsConfig
|
||
}
|
||
|
||
// GetClientTLSConfig 获取客户端 TLS 配置。
|
||
//
|
||
// 用于连接上游服务器。
|
||
//
|
||
// 参数:
|
||
// - serverName: 服务器名称(用于 SNI)
|
||
//
|
||
// 返回值:
|
||
// - *tls.Config: TLS 配置对象
|
||
func (m *ProxySSLManager) GetClientTLSConfig(serverName string) *tls.Config {
|
||
m.mu.RLock()
|
||
defer m.mu.RUnlock()
|
||
|
||
if !m.config.Enabled {
|
||
return nil
|
||
}
|
||
|
||
tlsConfig := &tls.Config{
|
||
MinVersion: tls.VersionTLS12,
|
||
}
|
||
|
||
// 设置服务器名称(SNI)
|
||
if m.config.ServerName != "" {
|
||
tlsConfig.ServerName = m.config.ServerName
|
||
} else if serverName != "" {
|
||
tlsConfig.ServerName = serverName
|
||
}
|
||
|
||
// 设置客户端证书
|
||
if m.cert.Certificate != nil {
|
||
tlsConfig.Certificates = []tls.Certificate{m.cert}
|
||
}
|
||
|
||
// 设置协议版本
|
||
if len(m.config.Protocols) > 0 {
|
||
tlsConfig.MinVersion = sslutil.ParseMinTLSVersion(m.config.Protocols)
|
||
}
|
||
|
||
// 配置服务器证书验证
|
||
if m.config.Verify && m.rootCAPool != nil {
|
||
tlsConfig.RootCAs = m.rootCAPool
|
||
} else if !m.config.Verify {
|
||
// 跳过证书验证
|
||
logging.Warn().Msg("SSL证书验证已禁用,连接可能遭受中间人攻击")
|
||
tlsConfig.InsecureSkipVerify = true
|
||
}
|
||
|
||
// 会话复用
|
||
if m.config.SessionReuse {
|
||
tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(100)
|
||
}
|
||
|
||
return tlsConfig
|
||
}
|
||
|
||
// IsEnabled 检查是否启用 SSL。
|
||
func (m *SSLManager) IsEnabled() bool {
|
||
return m.config.Enabled
|
||
}
|
||
|
||
// IsEnabled 检查是否启用代理 SSL。
|
||
func (m *ProxySSLManager) IsEnabled() bool {
|
||
return m.config.Enabled
|
||
}
|