247 lines
6.1 KiB
Go
247 lines
6.1 KiB
Go
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
|
||
}
|