xfy 6b8b00c900 refactor(ssl): extract TLS config generation to sslutil
- 新增 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>
2026-04-29 18:18:33 +08:00

215 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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
}