lolly/internal/proxy/proxy_ssl.go
xfy 470c82d940 style(proxy,server): 代码风格优化
- headers.go: 添加协议常量 protoHTTP/protoHTTPS
- redirect_rewrite.go: 添加模式常量,修正缩进
- proxy_ssl_test.go: 表格测试字段对齐
- server.go: 添加 ServerModeAuto 分支防御性处理

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 09:54:09 +08:00

102 lines
2.6 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 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
}