package config import ( "encoding/base64" "encoding/json" "fmt" "net/url" "strconv" "strings" ) // ProxyConfig 表示代理节点的配置 // 该结构体包含各种代理协议的通用和特定配置 type ProxyConfig struct { // 基本信息 Name string `yaml:"name" json:"name"` Type string `yaml:"type" json:"type"` // ss, ssr, vmess, trojan, http, socks5 // 服务器信息 Server string `yaml:"server" json:"server"` Port int `yaml:"port" json:"port"` Password string `yaml:"password" json:"password,omitempty"` // 加密和协议 Method string `yaml:"method" json:"method,omitempty"` // ss, ssr Protocol string `yaml:"protocol" json:"protocol,omitempty"` // ssr Obfs string `yaml:"obfs" json:"obfs,omitempty"` // ssr ObfsParam string `yaml:"obfs_param" json:"obfs_param,omitempty"` // ssr SSRProtocol string `yaml:"ssr_protocol" json:"ssr_protocol,omitempty"` // ssr (兼容性字段) // VMess特定配置 VMessConfig *VMessConfig `yaml:"vmess_config,omitempty" json:"vmess_config,omitempty"` // TLS配置 TLS bool `yaml:"tls" json:"tls"` SNI string `yaml:"sni" json:"sni,omitempty"` Alpn string `yaml:"alpn" json:"alpn,omitempty"` SkipVerify bool `yaml:"skip_verify" json:"skip_verify"` // WebSocket配置 WSPath string `yaml:"ws_path" json:"ws_path,omitempty"` WSHeaders map[string]string `yaml:"ws_headers" json:"ws_headers,omitempty"` // HTTP/2配置 H2Host string `yaml:"h2_host" json:"h2_host,omitempty"` H2Path string `yaml:"h2_path" json:"h2_path,omitempty"` // QUIC配置 QUICSecurity string `yaml:"quic_security" json:"quic_security,omitempty"` QUICKey string `yaml:"quic_key" json:"quic_key,omitempty"` // gRPC配置 GRPCServiceName string `yaml:"grpc_service_name" json:"grpc_service_name,omitempty"` GRPCMultiMode bool `yaml:"grpc_multi_mode" json:"grpc_multi_mode,omitempty"` // 其他配置 UDP bool `yaml:"udp" json:"udp"` TFO bool `yaml:"tfo" json:"tfo"` // TCP Fast Open Mux bool `yaml:"mux" json:"mux"` // 多路复用 Scramble bool `yaml:"scramble" json:"scramble"` Plugin string `yaml:"plugin" json:"plugin,omitempty"` PluginOpts string `yaml:"plugin_opts" json:"plugin_opts,omitempty"` // 节点属性 Location string `yaml:"location" json:"location,omitempty"` Provider string `yaml:"provider" json:"provider,omitempty"` Ping int `yaml:"ping" json:"ping,omitempty"` // 延迟(ms) } // VMessConfig VMess协议特定配置 type VMessConfig struct { VMessUUID string `yaml:"vmess_uuid" json:"vmess_uuid"` VMessAlterID string `yaml:"vmess_alter_id" json:"vmess_alter_id"` VMessSecurity string `yaml:"vmess_security" json:"vmess_security"` } // NewProxyConfig 创建新的代理配置 // 返回包含基本默认值的ProxyConfig结构体 func NewProxyConfig() *ProxyConfig { return &ProxyConfig{ Name: "", Type: "", Server: "", Port: 0, Password: "", Method: "", Protocol: "", Obfs: "", ObfsParam: "", TLS: false, SNI: "", Alpn: "", SkipVerify: false, WSPath: "", WSHeaders: make(map[string]string), H2Host: "", H2Path: "", QUICSecurity: "", QUICKey: "", GRPCServiceName: "", GRPCMultiMode: false, UDP: false, TFO: false, Mux: false, Scramble: false, Plugin: "", PluginOpts: "", Location: "", Provider: "", Ping: 0, } } // Validate 验证代理配置的有效性 // 返回error如果配置无效,nil表示配置有效 func (p *ProxyConfig) Validate() error { // 基本字段验证 if p.Name == "" { return fmt.Errorf("proxy name cannot be empty") } if p.Type == "" { return fmt.Errorf("proxy type cannot be empty") } if p.Server == "" { return fmt.Errorf("proxy server cannot be empty") } if p.Port < 1 || p.Port > 65535 { return fmt.Errorf("proxy port must be between 1 and 65535, got: %d", p.Port) } // 根据类型验证特定字段 switch strings.ToLower(p.Type) { case "ss", "shadowsocks": if p.Password == "" { return fmt.Errorf("shadowsocks password cannot be empty") } if p.Method == "" { return fmt.Errorf("shadowsocks method cannot be empty") } case "ssr", "shadowsocksr": if p.Password == "" { return fmt.Errorf("shadowsocksr password cannot be empty") } if p.Method == "" { return fmt.Errorf("shadowsocksr method cannot be empty") } if p.Protocol == "" { return fmt.Errorf("shadowsocksr protocol cannot be empty") } case "vmess": if p.VMessConfig == nil || p.VMessConfig.VMessUUID == "" { return fmt.Errorf("vmess uuid cannot be empty") } if p.VMessConfig.VMessAlterID == "" { return fmt.Errorf("vmess alter id cannot be empty") } if p.VMessConfig.VMessSecurity == "" { return fmt.Errorf("vmess security cannot be empty") } case "trojan": if p.Password == "" { return fmt.Errorf("trojan password cannot be empty") } case "http", "https": if p.Password == "" && p.Type == "https" { return fmt.Errorf("https proxy requires authentication") } case "socks5": // SOCKS5可以无认证 default: return fmt.Errorf("unsupported proxy type: %s", p.Type) } // TLS配置验证 if p.TLS { if p.SNI == "" { p.SNI = p.Server // 默认使用服务器地址作为SNI } } // WebSocket配置验证 if p.WSPath != "" && p.WSHeaders == nil { p.WSHeaders = make(map[string]string) } // HTTP/2配置验证 if p.H2Path != "" && p.H2Host == "" { return fmt.Errorf("h2 host cannot be empty when h2 path is specified") } // QUIC配置验证 if p.QUICKey != "" && p.QUICSecurity == "" { return fmt.Errorf("quic security cannot be empty when quic key is specified") } // gRPC配置验证 if p.GRPCServiceName != "" && !p.TLS { return fmt.Errorf("grpc requires tls to be enabled") } return nil } // ToURL 将代理配置转换为URL格式 // 返回代理URL字符串,适用于分享和导入 func (p *ProxyConfig) ToURL() (string, error) { switch strings.ToLower(p.Type) { case "ss", "shadowsocks": return p.toSSURL() case "ssr", "shadowsocksr": return p.toSSRURL() case "vmess": return p.toVMessURL() case "trojan": return p.toTrojanURL() case "http", "https": return p.toHTTPURL() case "socks5": return p.toSocks5URL() default: return "", fmt.Errorf("unsupported proxy type: %s", p.Type) } } // FromURL 从URL解析代理配置 // 根据URL类型自动识别并解析代理配置 func (p *ProxyConfig) FromURL(proxyURL string) error { u, err := url.Parse(proxyURL) if err != nil { return fmt.Errorf("failed to parse proxy URL: %v", err) } switch u.Scheme { case "ss": return p.fromSSURL(u) case "ssr": return p.fromSSRURL(u) case "vmess": return p.fromVMessURL(u) case "trojan": return p.fromTrojanURL(u) case "http", "https": return p.fromHTTPURL(u) case "socks5": return p.fromSocks5URL(u) default: return fmt.Errorf("unsupported proxy URL scheme: %s", u.Scheme) } } // toSSURL 转换为SS URL格式 func (p *ProxyConfig) toSSURL() (string, error) { if p.Type != "ss" && p.Type != "shadowsocks" { return "", fmt.Errorf("not a shadowsocks proxy") } // SS URL格式: ss://method:password@server:port#name host := fmt.Sprintf("%s:%d", p.Server, p.Port) u := &url.URL{ Scheme: "ss", User: url.UserPassword(p.Method, p.Password), Host: host, } if p.Name != "" { u.Fragment = p.Name } return u.String(), nil } // toSSRURL 转换为SSR URL格式 func (p *ProxyConfig) toSSRURL() (string, error) { if p.Type != "ssr" && p.Type != "shadowsocksr" { return "", fmt.Errorf("not a shadowsocksr proxy") } // SSR URL格式: ssr://base64(server:port:protocol:method:obfs:password/?obfsparam=...&protoparam=...&remarks=...) params := make(url.Values) params.Set("obfsparam", p.ObfsParam) params.Set("protoparam", "") params.Set("remarks", p.Name) params.Set("group", "") params.Set("udpport", "0") params.Set("uot", "0") baseInfo := fmt.Sprintf("%s:%d:%s:%s:%s:%s", p.Server, p.Port, p.Protocol, p.Method, p.Obfs, p.Password) encodedInfo := url.QueryEscape(base64Encode(baseInfo)) encodedParams := url.QueryEscape(params.Encode()) return fmt.Sprintf("ssr://%s/?%s", encodedInfo, encodedParams), nil } // toVMessURL 转换为VMess URL格式 func (p *ProxyConfig) toVMessURL() (string, error) { if p.Type != "vmess" { return "", fmt.Errorf("not a vmess proxy") } // VMess URL格式: vmess://base64(json_config) config := map[string]interface{}{ "v": "2", "ps": p.Name, "add": p.Server, "port": p.Port, "id": p.VMessConfig.VMessUUID, "aid": p.VMessConfig.VMessAlterID, "net": "tcp", // 简化版本 "type": "none", "host": "", "path": "", "tls": "", } if p.TLS { config["tls"] = "tls" } configJSON, err := json.Marshal(config) if err != nil { return "", fmt.Errorf("failed to marshal vmess config: %v", err) } return "vmess://" + base64Encode(string(configJSON)), nil } // toTrojanURL 转换为Trojan URL格式 func (p *ProxyConfig) toTrojanURL() (string, error) { if p.Type != "trojan" { return "", fmt.Errorf("not a trojan proxy") } // Trojan URL格式: trojan://password@server:port?allowinsecure=1#name u := &url.URL{ Scheme: "trojan", User: url.UserPassword(p.Password, ""), Host: fmt.Sprintf("%s:%d", p.Server, p.Port), } params := u.Query() if p.SkipVerify { params.Set("allowinsecure", "1") } if p.SNI != "" { params.Set("sni", p.SNI) } u.RawQuery = params.Encode() if p.Name != "" { u.Fragment = p.Name } return u.String(), nil } // toHTTPURL 转换为HTTP/HTTPS URL格式 func (p *ProxyConfig) toHTTPURL() (string, error) { if p.Type != "http" && p.Type != "https" { return "", fmt.Errorf("not an http proxy") } scheme := "http" if p.Type == "https" { scheme = "https" } u := &url.URL{ Scheme: scheme, Host: fmt.Sprintf("%s:%d", p.Server, p.Port), } if p.Password != "" { u.User = url.UserPassword("", p.Password) } if p.Name != "" { u.Fragment = p.Name } return u.String(), nil } // toSocks5URL 转换为SOCKS5 URL格式 func (p *ProxyConfig) toSocks5URL() (string, error) { if p.Type != "socks5" { return "", fmt.Errorf("not a socks5 proxy") } u := &url.URL{ Scheme: "socks5", Host: fmt.Sprintf("%s:%d", p.Server, p.Port), } if p.Password != "" { u.User = url.UserPassword("", p.Password) } if p.Name != "" { u.Fragment = p.Name } return u.String(), nil } // 以下是FromURL的各种实现方法,由于篇幅限制,这里只提供框架 func (p *ProxyConfig) fromSSURL(u *url.URL) error { // 解析SS URL的实现 p.Type = "ss" p.Server = u.Hostname() if port, err := strconv.Atoi(u.Port()); err == nil { p.Port = port } p.Name = u.Fragment if u.User != nil { p.Method = u.User.Username() if password, ok := u.User.Password(); ok { p.Password = password } } return p.Validate() } func (p *ProxyConfig) fromSSRURL(u *url.URL) error { // 解析SSR URL的实现 p.Type = "ssr" // 实现SSR URL解析逻辑 return p.Validate() } func (p *ProxyConfig) fromVMessURL(u *url.URL) error { // 解析VMess URL的实现 p.Type = "vmess" // 实现VMess URL解析逻辑 return p.Validate() } func (p *ProxyConfig) fromTrojanURL(u *url.URL) error { // 解析Trojan URL的实现 p.Type = "trojan" p.Server = u.Hostname() if port, err := strconv.Atoi(u.Port()); err == nil { p.Port = port } p.Name = u.Fragment if u.User != nil { p.Password = u.User.Username() } return p.Validate() } func (p *ProxyConfig) fromHTTPURL(u *url.URL) error { // 解析HTTP URL的实现 p.Type = u.Scheme p.Server = u.Hostname() if port, err := strconv.Atoi(u.Port()); err == nil { p.Port = port } p.Name = u.Fragment if u.User != nil { if password, ok := u.User.Password(); ok { p.Password = password } } return p.Validate() } func (p *ProxyConfig) fromSocks5URL(u *url.URL) error { // 解析SOCKS5 URL的实现 p.Type = "socks5" p.Server = u.Hostname() if port, err := strconv.Atoi(u.Port()); err == nil { p.Port = port } p.Name = u.Fragment if u.User != nil { if password, ok := u.User.Password(); ok { p.Password = password } } return p.Validate() } // 辅助函数 func base64Encode(s string) string { return base64.StdEncoding.EncodeToString([]byte(s)) } func base64Decode(s string) (string, error) { data, err := base64.StdEncoding.DecodeString(s) return string(data), err }