SNI_proxy/config/config.go

247 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package config
import (
"fmt"
"os"
"regexp"
"gopkg.in/yaml.v3"
)
// 域名匹配规则类型
const (
MatchTypeRegexp = "regexp"
MatchTypeSuffix = "suffix"
MatchTypeKeyword = "keyword"
)
// DNS协议类型
const (
DNSProtocolUDP = "udp"
DNSProtocolTCP = "tcp"
DNSProtocolDoT = "dot" // DNS over TLS
DNSProtocolDoH = "doh" // DNS over HTTPS
DNSProtocolDoQ = "doq" // DNS over QUIC
)
// 默认配置值
const (
DefaultPort = 443
DefaultDNSProtocol = DNSProtocolUDP
DefaultDNSServer = "8.8.8.8:53"
DefaultDNSTimeout = 5
DefaultConnectTimeout = 10
DefaultReadTimeout = 30
DefaultWriteTimeout = 5
DefaultIdleTimeout = 60
DefaultLifeTime = 300
DefaultLogLevel = "info"
DefaultMaxConns = 1000
DefaultMinFragSize = 10
DefaultMaxFragSize = 100
DefaultMinDelay = 10
DefaultMaxDelay = 30
)
// 超时配置
type TimeoutConfig struct {
Connect int `yaml:"connect"` // 连接超时(秒)
Read int `yaml:"read"` // 读取超时(秒)
Write int `yaml:"write"` // 写入超时(秒)
Idle int `yaml:"idle"` // 空闲超时(秒)
LifeTime int `yaml:"lifetime"` // 连接最大生命周期(秒)
}
// TLS分片配置
type FragmentConfig struct {
Enabled bool `yaml:"enabled"` // 是否启用TLS分片
MinSize int `yaml:"min_size"` // 最小分片大小(字节)
MaxSize int `yaml:"max_size"` // 最大分片大小(字节)
DelayMin int `yaml:"delay_min"` // 分片之间的最小延迟(毫秒)
DelayMax int `yaml:"delay_max"` // 分片之间的最大延迟(毫秒)
Validate bool `yaml:"validate"` // 是否验证TLS记录完整性
}
// DNS解析器配置
type DNSResolverConfig struct {
Protocol string `yaml:"protocol"` // udp, tcp, dot, doh, doq
Server string `yaml:"server"` // 服务器地址,如 8.8.8.8:53, 1.1.1.1:853
Timeout int `yaml:"timeout"` // 超时时间(秒)
}
// 域名匹配规则
type DomainRule struct {
Type string `yaml:"type"` // regexp, suffix, keyword
Value string `yaml:"value"` // 匹配值
// 编译后的正则表达式仅当Type为regexp时使用
compiledRegexp *regexp.Regexp
}
// 代理规则
type ProxyRule struct {
Domains []DomainRule `yaml:"domains"`
Port int `yaml:"port"` // 目标端口默认为443
Fragment FragmentConfig `yaml:"fragment"`
}
// 配置结构
type Config struct {
Listen string `yaml:"listen"`
Rules []ProxyRule `yaml:"rules"`
DefaultPort int `yaml:"default_port"` // 默认目标端口,如果规则中未指定
DNS DNSResolverConfig `yaml:"dns"` // DNS解析器配置
Timeout TimeoutConfig `yaml:"timeout"` // 超时配置
LogLevel string `yaml:"log_level"` // 日志级别debug, info, warn, error
MaxConns int `yaml:"max_conns"` // 最大并发连接数
}
// 加载配置文件
func LoadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
// 设置默认值
setDefaultValues(&cfg)
// 编译正则表达式
if err := compileRegexps(&cfg); err != nil {
return nil, err
}
return &cfg, nil
}
// 设置默认值
func setDefaultValues(cfg *Config) {
// 设置默认端口
if cfg.DefaultPort == 0 {
cfg.DefaultPort = DefaultPort
}
// 设置默认DNS配置
if cfg.DNS.Protocol == "" {
cfg.DNS.Protocol = DefaultDNSProtocol
}
if cfg.DNS.Server == "" {
cfg.DNS.Server = DefaultDNSServer
}
if cfg.DNS.Timeout == 0 {
cfg.DNS.Timeout = DefaultDNSTimeout
}
// 设置默认超时配置
if cfg.Timeout.Connect == 0 {
cfg.Timeout.Connect = DefaultConnectTimeout
}
if cfg.Timeout.Read == 0 {
cfg.Timeout.Read = DefaultReadTimeout
}
if cfg.Timeout.Write == 0 {
cfg.Timeout.Write = DefaultWriteTimeout
}
if cfg.Timeout.Idle == 0 {
cfg.Timeout.Idle = DefaultIdleTimeout
}
if cfg.Timeout.LifeTime == 0 {
cfg.Timeout.LifeTime = DefaultLifeTime
}
// 设置默认日志级别
if cfg.LogLevel == "" {
cfg.LogLevel = DefaultLogLevel
}
// 设置默认最大连接数
if cfg.MaxConns == 0 {
cfg.MaxConns = DefaultMaxConns
}
// 设置规则默认值
for i := range cfg.Rules {
// 如果规则中未指定端口,使用默认端口
if cfg.Rules[i].Port == 0 {
cfg.Rules[i].Port = cfg.DefaultPort
}
// 设置TLS分片配置的默认值
if cfg.Rules[i].Fragment.Enabled {
setFragmentDefaults(&cfg.Rules[i].Fragment)
}
}
}
// 设置分片默认值
func setFragmentDefaults(frag *FragmentConfig) {
// 设置默认的分片大小范围
if frag.MinSize <= 0 {
frag.MinSize = DefaultMinFragSize
}
if frag.MaxSize <= 0 {
frag.MaxSize = DefaultMaxFragSize
}
if frag.MinSize > frag.MaxSize {
frag.MinSize = frag.MaxSize
}
// 设置默认的分片延迟范围
if frag.DelayMin <= 0 {
frag.DelayMin = DefaultMinDelay
}
if frag.DelayMax <= 0 {
frag.DelayMax = DefaultMaxDelay
}
if frag.DelayMin > frag.DelayMax {
frag.DelayMin = frag.DelayMax
}
}
// 编译正则表达式
func compileRegexps(cfg *Config) error {
for i := range cfg.Rules {
for j := range cfg.Rules[i].Domains {
if cfg.Rules[i].Domains[j].Type == MatchTypeRegexp {
re, err := regexp.Compile(cfg.Rules[i].Domains[j].Value)
if err != nil {
return fmt.Errorf("编译正则表达式失败 '%s': %w",
cfg.Rules[i].Domains[j].Value, err)
}
cfg.Rules[i].Domains[j].compiledRegexp = re
}
}
}
return nil
}
// 检查域名是否匹配规则
func (r *DomainRule) Match(domain string) bool {
switch r.Type {
case MatchTypeRegexp:
return r.compiledRegexp.MatchString(domain)
case MatchTypeSuffix:
return len(domain) >= len(r.Value) &&
domain[len(domain)-len(r.Value):] == r.Value
case MatchTypeKeyword:
return contains(domain, r.Value)
default:
return false
}
}
// 辅助函数:检查字符串是否包含子串
func contains(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}