- 新增 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>
119 lines
3.4 KiB
Go
119 lines
3.4 KiB
Go
// 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
|
||
}
|