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
315 lines
7.3 KiB
Go
315 lines
7.3 KiB
Go
package parser
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/subconverter-go/internal/logging"
|
|
)
|
|
|
|
// VMessParser VMess协议解析器
|
|
// 实现VMess代理配置的解析功能
|
|
type VMessParser struct {
|
|
logger *logging.Logger
|
|
}
|
|
|
|
// NewVMessParser 创建新的VMess解析器
|
|
// 返回初始化好的VMessParser实例
|
|
func NewVMessParser(logger *logging.Logger) *VMessParser {
|
|
return &VMessParser{
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// VMessConfig VMess配置结构
|
|
type VMessConfig struct {
|
|
V string `json:"v"` // 版本
|
|
PS string `json:"ps"` // 备注
|
|
Add string `json:"add"` // 服务器地址
|
|
Port string `json:"port"` // 服务器端口
|
|
ID string `json:"id"` // 用户ID
|
|
Aid string `json:"aid"` // 额外ID (alterId)
|
|
Net string `json:"net"` // 传输协议
|
|
Type string `json:"type"` // 伪装类型
|
|
Host string `json:"host"` // 主机名/域名
|
|
Path string `json:"path"` // 路径
|
|
TLS string `json:"tls"` // TLS加密
|
|
}
|
|
|
|
// Parse 解析VMess配置
|
|
// 支持标准Base64编码格式
|
|
func (p *VMessParser) Parse(input string) (*ProxyConfig, error) {
|
|
p.logger.Debugf("Parsing VMess configuration")
|
|
|
|
lower := strings.ToLower(input)
|
|
if strings.HasPrefix(lower, "vmess1://") {
|
|
input = "vmess://" + input[len("vmess1://"):]
|
|
}
|
|
|
|
// 去除前缀
|
|
input = strings.TrimPrefix(input, "vmess://")
|
|
|
|
// 解码Base64
|
|
decoded, err := base64.StdEncoding.DecodeString(input)
|
|
if err != nil {
|
|
// 尝试URL安全的Base64解码
|
|
decoded, err = base64.URLEncoding.DecodeString(input)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode VMess configuration: %v", err)
|
|
}
|
|
}
|
|
|
|
// 解析JSON配置
|
|
var vmessConfig VMessConfig
|
|
if err := json.Unmarshal(decoded, &vmessConfig); err != nil {
|
|
return nil, fmt.Errorf("failed to parse VMess JSON configuration: %v", err)
|
|
}
|
|
|
|
// 验证必要字段
|
|
if vmessConfig.Add == "" || vmessConfig.Port == "" || vmessConfig.ID == "" {
|
|
return nil, fmt.Errorf("invalid VMess configuration: missing required fields")
|
|
}
|
|
|
|
config := &ProxyConfig{
|
|
Type: "vmess",
|
|
Protocol: "vmess",
|
|
Server: vmessConfig.Add,
|
|
}
|
|
|
|
// 解析端口
|
|
port, err := strconv.Atoi(vmessConfig.Port)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid port number: %v", err)
|
|
}
|
|
config.Port = port
|
|
|
|
// 设置备注
|
|
if vmessConfig.PS != "" {
|
|
config.Name = vmessConfig.PS
|
|
} else {
|
|
config.Name = fmt.Sprintf("vmess-%s:%d", config.Server, config.Port)
|
|
}
|
|
|
|
// 创建设置映射
|
|
settings := map[string]interface{}{
|
|
"uuid": vmessConfig.ID,
|
|
"alterId": p.parseAlterId(vmessConfig.Aid),
|
|
"network": p.parseNetwork(vmessConfig.Net),
|
|
"tls": p.parseTLS(vmessConfig.TLS),
|
|
"udp": true,
|
|
}
|
|
|
|
// 添加网络特定配置
|
|
switch vmessConfig.Net {
|
|
case "ws":
|
|
settings["wsSettings"] = map[string]interface{}{
|
|
"path": p.parsePath(vmessConfig.Path),
|
|
"headers": map[string]string{
|
|
"Host": p.parseHost(vmessConfig.Host),
|
|
},
|
|
}
|
|
case "http":
|
|
settings["httpSettings"] = map[string]interface{}{
|
|
"path": p.parsePath(vmessConfig.Path),
|
|
"host": []string{p.parseHost(vmessConfig.Host)},
|
|
}
|
|
case "quic":
|
|
settings["quicSettings"] = map[string]interface{}{
|
|
"security": p.parseType(vmessConfig.Type),
|
|
"key": p.parseHost(vmessConfig.Host),
|
|
"header": map[string]string{
|
|
"type": p.parseType(vmessConfig.Type),
|
|
},
|
|
}
|
|
case "grpc":
|
|
settings["grpcSettings"] = map[string]interface{}{
|
|
"serviceName": p.parsePath(vmessConfig.Path),
|
|
"multiMode": false,
|
|
}
|
|
}
|
|
|
|
config.Settings = settings
|
|
config.UDP = true
|
|
|
|
p.logger.Infof("Successfully parsed VMess configuration for server: %s:%d", config.Server, config.Port)
|
|
return config, nil
|
|
}
|
|
|
|
// parseAlterId 解析额外ID
|
|
func (p *VMessParser) parseAlterId(aid string) int {
|
|
if aid == "" {
|
|
return 0
|
|
}
|
|
alterId, err := strconv.Atoi(aid)
|
|
if err != nil {
|
|
p.logger.Warnf("Invalid alterId: %s, using default 0", aid)
|
|
return 0
|
|
}
|
|
return alterId
|
|
}
|
|
|
|
// parseNetwork 解析网络协议
|
|
func (p *VMessParser) parseNetwork(net string) string {
|
|
switch net {
|
|
case "tcp", "kcp", "ws", "http", "quic", "grpc":
|
|
return net
|
|
default:
|
|
p.logger.Warnf("Unknown network type: %s, using tcp", net)
|
|
return "tcp"
|
|
}
|
|
}
|
|
|
|
// parseTLS 解析TLS配置
|
|
func (p *VMessParser) parseTLS(tls string) string {
|
|
switch tls {
|
|
case "tls", "1", "true":
|
|
return "tls"
|
|
default:
|
|
return "none"
|
|
}
|
|
}
|
|
|
|
// parseType 解析伪装类型
|
|
func (p *VMessParser) parseType(typ string) string {
|
|
if typ == "" {
|
|
return "none"
|
|
}
|
|
return typ
|
|
}
|
|
|
|
// parseHost 解析主机名
|
|
func (p *VMessParser) parseHost(host string) string {
|
|
if host == "" {
|
|
return ""
|
|
}
|
|
return host
|
|
}
|
|
|
|
// parsePath 解析路径
|
|
func (p *VMessParser) parsePath(path string) string {
|
|
if path == "" {
|
|
return "/"
|
|
}
|
|
return path
|
|
}
|
|
|
|
// Validate 验证VMess配置
|
|
func (p *VMessParser) Validate(config *ProxyConfig) error {
|
|
p.logger.Debugf("Validating VMess 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)
|
|
}
|
|
|
|
uuid := p.getUUID(config)
|
|
if uuid == "" {
|
|
return fmt.Errorf("UUID is required")
|
|
}
|
|
|
|
// 验证UUID格式
|
|
if err := p.validateUUID(uuid); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 验证网络协议
|
|
network := p.getNetwork(config)
|
|
if err := p.validateNetwork(network); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 验证额外ID
|
|
alterId := p.getAlterId(config)
|
|
if err := p.validateAlterId(alterId); err != nil {
|
|
return err
|
|
}
|
|
|
|
p.logger.Debug("VMess configuration validation passed")
|
|
return nil
|
|
}
|
|
|
|
// validateUUID 验证UUID格式
|
|
func (p *VMessParser) validateUUID(uuid string) error {
|
|
// 简单的UUID格式验证
|
|
if len(uuid) != 36 {
|
|
return fmt.Errorf("invalid UUID length: %d", len(uuid))
|
|
}
|
|
|
|
if strings.Count(uuid, "-") != 4 {
|
|
return fmt.Errorf("invalid UUID format: incorrect hyphen count")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// validateNetwork 验证网络协议
|
|
func (p *VMessParser) validateNetwork(network string) error {
|
|
supportedNetworks := []string{"tcp", "kcp", "ws", "http", "quic", "grpc"}
|
|
|
|
for _, supported := range supportedNetworks {
|
|
if network == supported {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("unsupported network type: %s", network)
|
|
}
|
|
|
|
// validateAlterId 验证额外ID
|
|
func (p *VMessParser) validateAlterId(alterId int) error {
|
|
if alterId < 0 {
|
|
return fmt.Errorf("alterId cannot be negative: %d", alterId)
|
|
}
|
|
|
|
if alterId > 65535 {
|
|
return fmt.Errorf("alterId too large: %d", alterId)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getUUID 从配置中获取UUID
|
|
func (p *VMessParser) getUUID(config *ProxyConfig) string {
|
|
if uuid, exists := config.Settings["uuid"]; exists {
|
|
if uuidStr, ok := uuid.(string); ok {
|
|
return uuidStr
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// getNetwork 从配置中获取网络协议
|
|
func (p *VMessParser) getNetwork(config *ProxyConfig) string {
|
|
if network, exists := config.Settings["network"]; exists {
|
|
if networkStr, ok := network.(string); ok {
|
|
return networkStr
|
|
}
|
|
}
|
|
return "tcp"
|
|
}
|
|
|
|
// getAlterId 从配置中获取额外ID
|
|
func (p *VMessParser) getAlterId(config *ProxyConfig) int {
|
|
if alterId, exists := config.Settings["alterId"]; exists {
|
|
if alterIdInt, ok := alterId.(int); ok {
|
|
return alterIdInt
|
|
}
|
|
if alterIdFloat, ok := alterId.(float64); ok {
|
|
return int(alterIdFloat)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetSupportedProtocols 获取支持的协议
|
|
func (p *VMessParser) GetSupportedProtocols() []string {
|
|
return []string{"vmess"}
|
|
}
|