- ProxySSLConfig: 支持自定义 CA、客户端证书(mTLS)、SNI、TLS 版本控制 - ProxyCacheValidConfig: 按 HTTP 状态码分段配置缓存有效期 - proxy_ssl.go: 实现 CreateTLSConfig 和 TLS 版本解析 - proxy.go: 集成 SSL 配置到 HostClient,实现 getCacheDuration 分段缓存 - 测试文件适配新配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
101 lines
2.6 KiB
Go
101 lines
2.6 KiB
Go
// Package proxy 反向代理包,为 Lolly HTTP 服务器提供反向代理功能。
|
||
//
|
||
// 该文件提供上游 SSL/TLS 配置支持,包括自定义 CA 证书、
|
||
// 客户端证书(mTLS)、SNI 和 TLS 版本控制。
|
||
package proxy
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"crypto/x509"
|
||
"errors"
|
||
"os"
|
||
"strings"
|
||
|
||
"rua.plus/lolly/internal/config"
|
||
)
|
||
|
||
// TLS 版本字符串到 tls 常量的映射。
|
||
// 支持 TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3 格式(大小写不敏感)
|
||
var tlsVersionMap = map[string]uint16{
|
||
"TLSV1.0": tls.VersionTLS10,
|
||
"TLSV1.1": tls.VersionTLS11,
|
||
"TLSV1.2": tls.VersionTLS12,
|
||
"TLSV1.3": tls.VersionTLS13,
|
||
"": 0, // 空字符串表示使用默认
|
||
}
|
||
|
||
// 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 版本配置
|
||
if cfg.MinVersion != "" {
|
||
version, ok := tlsVersionMap[strings.ToUpper(cfg.MinVersion)]
|
||
if !ok {
|
||
return nil, errors.New("invalid TLS min version: " + cfg.MinVersion)
|
||
}
|
||
tlsCfg.MinVersion = version
|
||
}
|
||
|
||
if cfg.MaxVersion != "" {
|
||
version, ok := tlsVersionMap[strings.ToUpper(cfg.MaxVersion)]
|
||
if !ok {
|
||
return nil, errors.New("invalid TLS max version: " + cfg.MaxVersion)
|
||
}
|
||
tlsCfg.MaxVersion = version
|
||
}
|
||
|
||
return tlsCfg, nil
|
||
} |