lolly/internal/proxy/proxy_ssl.go
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

119 lines
3.4 KiB
Go
Raw Permalink 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 proxy 反向代理包,为 Lolly HTTP 服务器提供反向代理功能。
//
// 该文件提供上游 SSL/TLS 配置支持,包括自定义 CA 证书、
// 客户端证书mTLS、SNI 和 TLS 版本控制。
//
// 主要功能:
// - 自定义 CA 证书验证:支持指定受信任的 CA 证书文件
// - 客户端证书认证mTLS支持双向 TLS 认证
// - SNI 支持:自动从目标 URL 提取或使用配置的主机名
// - TLS 版本控制:支持 TLSv1.0 到 TLSv1.3 的最小/最大版本限制
// - 跳过证书验证:仅测试环境使用
//
// 主要用途:
//
// 用于代理与上游服务器之间的 TLS 连接配置,支持自签名证书、
// 内部 CA 签发证书以及双向认证场景。
//
// 注意事项:
// - InsecureSkipVerify 仅建议在测试环境使用
// - 证书文件路径为绝对路径或相对于工作目录
//
// 作者xfy
package proxy
import (
"crypto/tls"
"crypto/x509"
"errors"
"os"
"strings"
"rua.plus/lolly/internal/config"
"rua.plus/lolly/internal/logging"
"rua.plus/lolly/internal/sslutil"
)
// CreateTLSConfig 从 ProxySSLConfig 创建 tls.Config。
//
// 参数:
// - cfg: 上游 SSL 配置
// - defaultServerName: 默认 SNI 名称(从目标 URL 提取)
//
// 返回值:
// - *tls.Config: TLS 配置对象
// - error: 配置错误(证书加载失败等)
//
// 注意事项:
// - cfg 为 nil 或 Enabled=false 时返回 nil
// - TrustedCA 加载失败时返回错误
// - ClientCert/ClientKey 加载失败时返回错误
func CreateTLSConfig(cfg *config.ProxySSLConfig, defaultServerName string) (*tls.Config, error) {
if cfg == nil || !cfg.Enabled {
return nil, nil
}
tlsCfg := &tls.Config{}
// SNI 配置
if cfg.ServerName != "" {
tlsCfg.ServerName = cfg.ServerName
} else if defaultServerName != "" {
tlsCfg.ServerName = defaultServerName
}
// 跳过证书验证(仅测试环境)
if cfg.InsecureSkipVerify {
tlsCfg.InsecureSkipVerify = true
}
// CA 证书验证
if cfg.TrustedCA != "" {
caData, err := os.ReadFile(cfg.TrustedCA)
if err != nil {
return nil, errors.New("failed to read CA certificate: " + err.Error())
}
caPool := x509.NewCertPool()
if !caPool.AppendCertsFromPEM(caData) {
return nil, errors.New("failed to parse CA certificate")
}
tlsCfg.RootCAs = caPool
}
// 客户端证书mTLS
if cfg.ClientCert != "" && cfg.ClientKey != "" {
cert, err := tls.LoadX509KeyPair(cfg.ClientCert, cfg.ClientKey)
if err != nil {
return nil, errors.New("failed to load client certificate: " + err.Error())
}
tlsCfg.Certificates = []tls.Certificate{cert}
}
// TLS 版本配置:默认 MinVersion = TLS 1.2
tlsCfg.MinVersion = tls.VersionTLS12
if cfg.MinVersion != "" {
version, ok := sslutil.TLSVersionMap[strings.ToUpper(cfg.MinVersion)]
if !ok {
return nil, errors.New("invalid TLS min version: " + cfg.MinVersion)
}
tlsCfg.MinVersion = version
}
// 警告TLS 1.0/1.1 已不安全,不应在生产环境使用
if tlsCfg.MinVersion < tls.VersionTLS12 {
logging.Warn().Msgf("上游 TLS MinVersion 设置为 %s低于 TLS 1.2),存在安全风险", cfg.MinVersion)
}
if cfg.MaxVersion != "" {
version, ok := sslutil.TLSVersionMap[strings.ToUpper(cfg.MaxVersion)]
if !ok {
return nil, errors.New("invalid TLS max version: " + cfg.MaxVersion)
}
tlsCfg.MaxVersion = version
}
return tlsCfg, nil
}