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
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:
314
internal/parser/vmess.go
Normal file
314
internal/parser/vmess.go
Normal file
@@ -0,0 +1,314 @@
|
||||
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"}
|
||||
}
|
||||
Reference in New Issue
Block a user