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
266 lines
5.9 KiB
Go
266 lines
5.9 KiB
Go
package parser
|
||
|
||
import (
|
||
"fmt"
|
||
"net/url"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"github.com/subconverter-go/internal/logging"
|
||
)
|
||
|
||
// TrojanParser Trojan协议解析器
|
||
// 实现Trojan代理配置的解析功能
|
||
type TrojanParser struct {
|
||
logger *logging.Logger
|
||
}
|
||
|
||
// NewTrojanParser 创建新的Trojan解析器
|
||
// 返回初始化好的TrojanParser实例
|
||
func NewTrojanParser(logger *logging.Logger) *TrojanParser {
|
||
return &TrojanParser{
|
||
logger: logger,
|
||
}
|
||
}
|
||
|
||
// Parse 解析Trojan配置
|
||
// 支持标准URL格式
|
||
func (p *TrojanParser) Parse(input string) (*ProxyConfig, error) {
|
||
p.logger.Debugf("Parsing Trojan configuration")
|
||
|
||
// 去除前缀
|
||
input = strings.TrimPrefix(input, "trojan://")
|
||
|
||
// 解析URL
|
||
parsedURL, err := url.Parse("trojan://" + input)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to parse Trojan URL: %v", err)
|
||
}
|
||
|
||
// 获取密码
|
||
password := parsedURL.User.String()
|
||
if password == "" {
|
||
return nil, fmt.Errorf("password is required")
|
||
}
|
||
|
||
config := &ProxyConfig{
|
||
Type: "trojan",
|
||
Protocol: "trojan",
|
||
Server: parsedURL.Hostname(),
|
||
}
|
||
|
||
// 解析端口
|
||
port, err := strconv.Atoi(parsedURL.Port())
|
||
if err != nil {
|
||
return nil, fmt.Errorf("invalid port number: %v", err)
|
||
}
|
||
config.Port = port
|
||
|
||
// 解析备注
|
||
if parsedURL.Fragment != "" {
|
||
config.Name = parsedURL.Fragment
|
||
} else {
|
||
config.Name = fmt.Sprintf("trojan-%s:%d", config.Server, config.Port)
|
||
}
|
||
|
||
// 创建设置映射
|
||
settings := map[string]interface{}{
|
||
"password": password,
|
||
"udp": true,
|
||
}
|
||
|
||
// 解析查询参数
|
||
query := parsedURL.Query()
|
||
|
||
// 解析allowInsecure
|
||
if allowInsecure := query.Get("allowInsecure"); allowInsecure != "" {
|
||
settings["allowInsecure"] = p.parseBool(allowInsecure)
|
||
}
|
||
|
||
// 解析sni
|
||
if sni := query.Get("sni"); sni != "" {
|
||
settings["sni"] = sni
|
||
}
|
||
|
||
// 解析peer
|
||
if peer := query.Get("peer"); peer != "" {
|
||
settings["peer"] = peer
|
||
}
|
||
|
||
// 解析network类型
|
||
network := query.Get("type")
|
||
if network == "" {
|
||
network = "tcp"
|
||
}
|
||
|
||
// 添加网络特定配置
|
||
switch network {
|
||
case "ws":
|
||
settings["network"] = "ws"
|
||
wsSettings := map[string]interface{}{
|
||
"path": "/",
|
||
}
|
||
|
||
if host := query.Get("host"); host != "" {
|
||
wsSettings["headers"] = map[string]string{
|
||
"Host": host,
|
||
}
|
||
}
|
||
|
||
if path := query.Get("path"); path != "" {
|
||
wsSettings["path"] = path
|
||
}
|
||
|
||
settings["wsSettings"] = wsSettings
|
||
|
||
case "grpc":
|
||
settings["network"] = "grpc"
|
||
grpcSettings := map[string]interface{}{
|
||
"serviceName": query.Get("serviceName"),
|
||
"multiMode": false,
|
||
}
|
||
|
||
if service := query.Get("serviceName"); service != "" {
|
||
grpcSettings["serviceName"] = service
|
||
}
|
||
|
||
settings["grpcSettings"] = grpcSettings
|
||
|
||
case "kcp":
|
||
settings["network"] = "kcp"
|
||
kcpSettings := map[string]interface{}{
|
||
"header": map[string]string{
|
||
"type": query.Get("headerType"),
|
||
},
|
||
}
|
||
|
||
if headerType := query.Get("headerType"); headerType != "" {
|
||
kcpSettings["header"].(map[string]string)["type"] = headerType
|
||
}
|
||
|
||
settings["kcpSettings"] = kcpSettings
|
||
|
||
default:
|
||
settings["network"] = "tcp"
|
||
}
|
||
|
||
// 解析TLS配置
|
||
if network != "tcp" || query.Get("security") == "tls" {
|
||
settings["security"] = "tls"
|
||
}
|
||
|
||
config.Settings = settings
|
||
config.UDP = true
|
||
|
||
p.logger.Infof("Successfully parsed Trojan configuration for server: %s:%d", config.Server, config.Port)
|
||
return config, nil
|
||
}
|
||
|
||
// parseBool 解析布尔值
|
||
func (p *TrojanParser) parseBool(value string) bool {
|
||
switch strings.ToLower(value) {
|
||
case "1", "true", "yes", "on":
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
}
|
||
|
||
// Validate 验证Trojan配置
|
||
func (p *TrojanParser) Validate(config *ProxyConfig) error {
|
||
p.logger.Debugf("Validating Trojan 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)
|
||
}
|
||
|
||
password := p.getPassword(config)
|
||
if password == "" {
|
||
return fmt.Errorf("password is required")
|
||
}
|
||
|
||
// 验证密码格式(应该是一个44字符的Base64编码字符串)
|
||
if len(password) != 44 {
|
||
p.logger.Warnf("Trojan password length is not 44 characters: %d", len(password))
|
||
}
|
||
|
||
// 验证网络协议
|
||
network := p.getNetwork(config)
|
||
if err := p.validateNetwork(network); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 验证SNI(如果启用TLS)
|
||
if p.getSecurity(config) == "tls" {
|
||
sni := p.getSNI(config)
|
||
if sni == "" {
|
||
p.logger.Debug("SNI not specified, using server address")
|
||
}
|
||
}
|
||
|
||
p.logger.Debug("Trojan configuration validation passed")
|
||
return nil
|
||
}
|
||
|
||
// validateNetwork 验证网络协议
|
||
func (p *TrojanParser) validateNetwork(network string) error {
|
||
supportedNetworks := []string{"tcp", "ws", "grpc", "kcp"}
|
||
|
||
for _, supported := range supportedNetworks {
|
||
if network == supported {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
return fmt.Errorf("unsupported network type: %s", network)
|
||
}
|
||
|
||
// getPassword 从配置中获取密码
|
||
func (p *TrojanParser) getPassword(config *ProxyConfig) string {
|
||
if password, exists := config.Settings["password"]; exists {
|
||
if passwordStr, ok := password.(string); ok {
|
||
return passwordStr
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// getNetwork 从配置中获取网络协议
|
||
func (p *TrojanParser) getNetwork(config *ProxyConfig) string {
|
||
if network, exists := config.Settings["network"]; exists {
|
||
if networkStr, ok := network.(string); ok {
|
||
return networkStr
|
||
}
|
||
}
|
||
return "tcp"
|
||
}
|
||
|
||
// getSecurity 从配置中获取安全设置
|
||
func (p *TrojanParser) getSecurity(config *ProxyConfig) string {
|
||
if security, exists := config.Settings["security"]; exists {
|
||
if securityStr, ok := security.(string); ok {
|
||
return securityStr
|
||
}
|
||
}
|
||
return "none"
|
||
}
|
||
|
||
// getSNI 从配置中获取SNI
|
||
func (p *TrojanParser) getSNI(config *ProxyConfig) string {
|
||
if sni, exists := config.Settings["sni"]; exists {
|
||
if sniStr, ok := sni.(string); ok {
|
||
return sniStr
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
// GetSupportedProtocols 获取支持的协议
|
||
func (p *TrojanParser) GetSupportedProtocols() []string {
|
||
return []string{"trojan"}
|
||
} |