first commit
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped

This commit is contained in:
Rogee
2025-09-28 10:05:07 +08:00
commit 7fcabe0225
481 changed files with 125127 additions and 0 deletions

511
internal/config/proxy.go Normal file
View File

@@ -0,0 +1,511 @@
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
}