package parser import ( "fmt" "net/url" "strconv" "strings" "github.com/subconverter-go/internal/logging" ) // Socks5Parser Socks5协议解析器 // 实现Socks5代理配置的解析功能 type Socks5Parser struct { logger *logging.Logger } // NewSocks5Parser 创建新的Socks5解析器 // 返回初始化好的Socks5Parser实例 func NewSocks5Parser(logger *logging.Logger) *Socks5Parser { return &Socks5Parser{ logger: logger, } } // Parse 解析Socks5配置 // 支持标准URL格式 func (p *Socks5Parser) Parse(input string) (*ProxyConfig, error) { p.logger.Debugf("Parsing Socks5 configuration") normalized, err := p.normalizeInput(input) if err != nil { return nil, err } // 去除前缀 trimmed := strings.TrimPrefix(normalized, "socks5://") // 解析URL parsedURL, err := url.Parse("socks5://" + trimmed) if err != nil { return nil, fmt.Errorf("failed to parse Socks5 URL: %v", err) } config := &ProxyConfig{ Type: "socks5", Protocol: "socks5", Server: parsedURL.Hostname(), } // 解析端口 port, err := strconv.Atoi(parsedURL.Port()) if err != nil { return nil, fmt.Errorf("invalid port number: %v", err) } config.Port = port // 解析用户名和密码 var username, password string if parsedURL.User != nil { username = parsedURL.User.Username() password, _ = parsedURL.User.Password() } // 解析备注 if parsedURL.Fragment != "" { config.Name = parsedURL.Fragment } else { config.Name = fmt.Sprintf("socks5-%s:%d", config.Server, config.Port) } // 创建设置映射 settings := map[string]interface{}{ "udp": true, } // 添加认证信息 if username != "" { settings["username"] = username if password != "" { settings["password"] = password } } config.Settings = settings config.UDP = true p.logger.Infof("Successfully parsed Socks5 configuration for server: %s:%d", config.Server, config.Port) return config, nil } func (p *Socks5Parser) normalizeInput(input string) (string, error) { trimmed := strings.TrimSpace(input) if trimmed == "" { return "", fmt.Errorf("empty socks proxy string") } lower := strings.ToLower(trimmed) switch { case strings.HasPrefix(lower, "socks5://"): return trimmed, nil case strings.HasPrefix(lower, "socks://"): return "socks5://" + trimmed[len("socks://"):], nil case strings.HasPrefix(lower, "tg://socks"), strings.HasPrefix(lower, "https://t.me/socks"): return p.normalizeTelegramLink(trimmed) default: return trimmed, nil } } func (p *Socks5Parser) normalizeTelegramLink(link string) (string, error) { parsed, err := url.Parse(link) if err != nil { return "", fmt.Errorf("failed to parse Telegram socks link: %w", err) } values := parsed.Query() host := values.Get("server") if host == "" { host = values.Get("host") } port := values.Get("port") if port == "" { return "", fmt.Errorf("missing port in Telegram socks link") } username := values.Get("user") if username == "" { username = values.Get("username") } password := values.Get("pass") if password == "" { password = values.Get("password") } if host == "" { return "", fmt.Errorf("missing server in Telegram socks link") } credentials := "" if username != "" { var userInfo *url.Userinfo if password != "" { userInfo = url.UserPassword(username, password) } else { userInfo = url.User(username) } credentials = userInfo.String() + "@" } fragment := parsed.Fragment if fragment != "" { fragment = "#" + fragment } return fmt.Sprintf("socks5://%s%s:%s%s", credentials, host, port, fragment), nil } // Validate 验证Socks5配置 func (p *Socks5Parser) Validate(config *ProxyConfig) error { p.logger.Debugf("Validating Socks5 configuration") // 检查必要字段 if config.Server == "" { return fmt.Errorf("server address is required") } if config.Port <= 0 || config.Port > 65535 { return fmt.Errorf("invalid port number: %d", config.Port) } // 验证认证信息 username := p.getUsername(config) password := p.getPassword(config) // 如果提供了用户名,验证密码是否也提供 if username != "" && password == "" { p.logger.Warn("Username provided but password is empty") } // 如果没有提供用户名,确保也没有密码 if username == "" && password != "" { return fmt.Errorf("password provided without username") } p.logger.Debug("Socks5 configuration validation passed") return nil } // getUsername 从配置中获取用户名 func (p *Socks5Parser) getUsername(config *ProxyConfig) string { if username, exists := config.Settings["username"]; exists { if usernameStr, ok := username.(string); ok { return usernameStr } } return "" } // getPassword 从配置中获取密码 func (p *Socks5Parser) getPassword(config *ProxyConfig) string { if password, exists := config.Settings["password"]; exists { if passwordStr, ok := password.(string); ok { return passwordStr } } return "" } // GetSupportedProtocols 获取支持的协议 func (p *Socks5Parser) GetSupportedProtocols() []string { return []string{"socks5"} }