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:
278
internal/parser/shadowsocksr.go
Normal file
278
internal/parser/shadowsocksr.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/subconverter-go/internal/logging"
|
||||
)
|
||||
|
||||
// ShadowsocksRParser ShadowsocksR协议解析器
|
||||
// 实现ShadowsocksR代理配置的解析功能
|
||||
type ShadowsocksRParser struct {
|
||||
logger *logging.Logger
|
||||
}
|
||||
|
||||
// NewShadowsocksRParser 创建新的ShadowsocksR解析器
|
||||
// 返回初始化好的ShadowsocksRParser实例
|
||||
func NewShadowsocksRParser(logger *logging.Logger) *ShadowsocksRParser {
|
||||
return &ShadowsocksRParser{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Parse 解析ShadowsocksR配置
|
||||
// 支持标准格式和Base64编码格式
|
||||
func (p *ShadowsocksRParser) Parse(input string) (*ProxyConfig, error) {
|
||||
p.logger.Debugf("Parsing ShadowsocksR configuration")
|
||||
|
||||
// 去除前缀
|
||||
input = strings.TrimPrefix(input, "ssr://")
|
||||
|
||||
// 解码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 ShadowsocksR configuration: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析配置字符串: server:port:protocol:method:obfs:password_base64/remarks_base64/group_base64/obfsparam_base64/protocolparam_base64
|
||||
parts := strings.Split(string(decoded), "/")
|
||||
if len(parts) < 1 {
|
||||
return nil, fmt.Errorf("invalid ShadowsocksR configuration format")
|
||||
}
|
||||
|
||||
// 解析主要配置
|
||||
mainParts := strings.Split(parts[0], ":")
|
||||
if len(mainParts) < 6 {
|
||||
return nil, fmt.Errorf("invalid ShadowsocksR main configuration format")
|
||||
}
|
||||
|
||||
config := &ProxyConfig{
|
||||
Type: "ssr",
|
||||
Protocol: "ssr",
|
||||
}
|
||||
|
||||
// 解析服务器和端口
|
||||
config.Server = mainParts[0]
|
||||
port, err := strconv.Atoi(mainParts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid port number: %v", err)
|
||||
}
|
||||
config.Port = port
|
||||
|
||||
// 解码密码
|
||||
password, err := base64.StdEncoding.DecodeString(mainParts[5])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode password: %v", err)
|
||||
}
|
||||
|
||||
// 创建设置映射
|
||||
settings := map[string]interface{}{
|
||||
"protocol": mainParts[2],
|
||||
"method": mainParts[3],
|
||||
"obfs": mainParts[4],
|
||||
"password": string(password),
|
||||
"udp": true,
|
||||
"protocolParam": "",
|
||||
"obfsParam": "",
|
||||
}
|
||||
|
||||
// 解析可选参数
|
||||
if len(parts) > 1 {
|
||||
// 解析备注
|
||||
remarks, err := base64.StdEncoding.DecodeString(parts[1])
|
||||
if err == nil {
|
||||
config.Name = string(remarks)
|
||||
}
|
||||
|
||||
// 解析分组
|
||||
if len(parts) > 2 {
|
||||
group, err := base64.StdEncoding.DecodeString(parts[2])
|
||||
if err == nil {
|
||||
config.Group = string(group)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析obfs参数
|
||||
if len(parts) > 3 {
|
||||
obfsParam, err := base64.StdEncoding.DecodeString(parts[3])
|
||||
if err == nil {
|
||||
settings["obfsParam"] = string(obfsParam)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析protocol参数
|
||||
if len(parts) > 4 {
|
||||
protocolParam, err := base64.StdEncoding.DecodeString(parts[4])
|
||||
if err == nil {
|
||||
settings["protocolParam"] = string(protocolParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认名称
|
||||
if config.Name == "" {
|
||||
config.Name = fmt.Sprintf("ssr-%s:%d", config.Server, config.Port)
|
||||
}
|
||||
|
||||
config.UDP = true
|
||||
config.Settings = settings
|
||||
|
||||
p.logger.Infof("Successfully parsed ShadowsocksR configuration for server: %s:%d", config.Server, config.Port)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Validate 验证ShadowsocksR配置
|
||||
func (p *ShadowsocksRParser) Validate(config *ProxyConfig) error {
|
||||
p.logger.Debugf("Validating ShadowsocksR 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)
|
||||
}
|
||||
|
||||
method := p.getMethod(config)
|
||||
if method == "" {
|
||||
return fmt.Errorf("encryption method is required")
|
||||
}
|
||||
|
||||
password := p.getPassword(config)
|
||||
if password == "" {
|
||||
return fmt.Errorf("password is required")
|
||||
}
|
||||
|
||||
protocol := p.getProtocol(config)
|
||||
if protocol == "" {
|
||||
return fmt.Errorf("protocol is required")
|
||||
}
|
||||
|
||||
obfs := p.getObfs(config)
|
||||
if obfs == "" {
|
||||
return fmt.Errorf("obfs is required")
|
||||
}
|
||||
|
||||
// 验证加密方法
|
||||
if err := p.validateMethod(method); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 验证协议
|
||||
if err := p.validateProtocol(protocol); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 验证混淆
|
||||
if err := p.validateObfs(obfs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.logger.Debug("ShadowsocksR configuration validation passed")
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateMethod 验证加密方法
|
||||
func (p *ShadowsocksRParser) validateMethod(method string) error {
|
||||
supportedMethods := []string{
|
||||
"none", "table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
|
||||
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
|
||||
"camellia-192-cfb", "camellia-256-cfb", "cast5-cfb", "des-cfb", "idea-cfb",
|
||||
"rc2-cfb", "seed-cfb", "salsa20", "chacha20", "chacha20-ietf",
|
||||
}
|
||||
|
||||
for _, supported := range supportedMethods {
|
||||
if method == supported {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
p.logger.Warnf("Unsupported encryption method: %s", method)
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateProtocol 验证协议
|
||||
func (p *ShadowsocksRParser) validateProtocol(protocol string) error {
|
||||
supportedProtocols := []string{
|
||||
"origin", "verify_deflate", "auth_sha1_v4", "auth_aes128_md5",
|
||||
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b",
|
||||
}
|
||||
|
||||
for _, supported := range supportedProtocols {
|
||||
if protocol == supported {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
p.logger.Warnf("Unsupported protocol: %s", protocol)
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateObfs 验证混淆
|
||||
func (p *ShadowsocksRParser) validateObfs(obfs string) error {
|
||||
supportedObfs := []string{
|
||||
"plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth",
|
||||
}
|
||||
|
||||
for _, supported := range supportedObfs {
|
||||
if obfs == supported {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
p.logger.Warnf("Unsupported obfs: %s", obfs)
|
||||
return nil
|
||||
}
|
||||
|
||||
// getMethod 从配置中获取加密方法
|
||||
func (p *ShadowsocksRParser) getMethod(config *ProxyConfig) string {
|
||||
if method, exists := config.Settings["method"]; exists {
|
||||
if methodStr, ok := method.(string); ok {
|
||||
return methodStr
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getPassword 从配置中获取密码
|
||||
func (p *ShadowsocksRParser) getPassword(config *ProxyConfig) string {
|
||||
if password, exists := config.Settings["password"]; exists {
|
||||
if passwordStr, ok := password.(string); ok {
|
||||
return passwordStr
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getProtocol 从配置中获取协议
|
||||
func (p *ShadowsocksRParser) getProtocol(config *ProxyConfig) string {
|
||||
if protocol, exists := config.Settings["protocol"]; exists {
|
||||
if protocolStr, ok := protocol.(string); ok {
|
||||
return protocolStr
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getObfs 从配置中获取混淆
|
||||
func (p *ShadowsocksRParser) getObfs(config *ProxyConfig) string {
|
||||
if obfs, exists := config.Settings["obfs"]; exists {
|
||||
if obfsStr, ok := obfs.(string); ok {
|
||||
return obfsStr
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetSupportedProtocols 获取支持的协议
|
||||
func (p *ShadowsocksRParser) GetSupportedProtocols() []string {
|
||||
return []string{"ssr"}
|
||||
}
|
||||
Reference in New Issue
Block a user