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
322 lines
8.1 KiB
Go
322 lines
8.1 KiB
Go
package generator
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/subconverter-go/internal/logging"
|
|
"github.com/subconverter-go/internal/parser"
|
|
)
|
|
|
|
// V2RayGenerator V2Ray格式生成器
|
|
// 实现V2Ray代理配置的生成功能
|
|
type V2RayGenerator struct {
|
|
logger *logging.Logger
|
|
}
|
|
|
|
// NewV2RayGenerator 创建新的V2Ray生成器
|
|
// 返回初始化好的V2RayGenerator实例
|
|
func NewV2RayGenerator(logger *logging.Logger) *V2RayGenerator {
|
|
return &V2RayGenerator{
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Generate 生成V2Ray配置
|
|
func (g *V2RayGenerator) Generate(configs []*parser.ProxyConfig, options *GenerationOptions) (string, error) {
|
|
g.logger.Debugf("Generating V2Ray configuration")
|
|
|
|
// 创建V2Ray配置结构
|
|
v2rayConfig := g.createV2RayConfig(configs, options)
|
|
|
|
// 转换为JSON
|
|
jsonData, err := json.MarshalIndent(v2rayConfig, "", " ")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to marshal V2Ray configuration: %v", err)
|
|
}
|
|
|
|
return string(jsonData), nil
|
|
}
|
|
|
|
// ValidateOptions 验证V2Ray生成选项
|
|
func (g *V2RayGenerator) ValidateOptions(options *GenerationOptions) error {
|
|
g.logger.Debugf("Validating V2Ray generation options")
|
|
|
|
// 验证基本信息
|
|
if options.Name == "" {
|
|
return fmt.Errorf("configuration name is required")
|
|
}
|
|
|
|
// 验证端口
|
|
if options.MixedPort < 0 || options.MixedPort > 65535 {
|
|
return fmt.Errorf("invalid mixed port: %d", options.MixedPort)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetSupportedFormats 获取支持的格式
|
|
func (g *V2RayGenerator) GetSupportedFormats() []string {
|
|
return []string{"v2ray"}
|
|
}
|
|
|
|
// V2RayConfig V2Ray配置结构体
|
|
type V2RayConfig struct {
|
|
Log *V2RayLog `json:"log,omitempty"`
|
|
Inbound *V2RayInbound `json:"inbounds"`
|
|
Outbound *V2RayOutbound `json:"outbounds"`
|
|
Routing *V2RayRouting `json:"routing,omitempty"`
|
|
}
|
|
|
|
// V2RayLog 日志配置
|
|
type V2RayLog struct {
|
|
Loglevel string `json:"loglevel,omitempty"`
|
|
}
|
|
|
|
// V2RayInbound 入站配置
|
|
type V2RayInbound struct {
|
|
Protocol string `json:"protocol"`
|
|
Listen string `json:"listen"`
|
|
Port int `json:"port"`
|
|
Settings *V2RayInSettings `json:"settings,omitempty"`
|
|
Sniffing *V2RaySniffing `json:"sniffing,omitempty"`
|
|
Stream *V2RayStream `json:"streamSettings,omitempty"`
|
|
}
|
|
|
|
// V2RayInSettings 入站设置
|
|
type V2RayInSettings struct {
|
|
Auth string `json:"auth,omitempty"`
|
|
UDP bool `json:"udp,omitempty"`
|
|
UserLevel int `json:"userLevel,omitempty"`
|
|
Accounts []V2RayAccount `json:"accounts,omitempty"`
|
|
}
|
|
|
|
// V2RayAccount 账户信息
|
|
type V2RayAccount struct {
|
|
User string `json:"user"`
|
|
Pass string `json:"pass"`
|
|
}
|
|
|
|
// V2RaySniffing 流量嗅探
|
|
type V2RaySniffing struct {
|
|
Enabled bool `json:"enabled"`
|
|
DestOverride []string `json:"destOverride,omitempty"`
|
|
}
|
|
|
|
// V2RayStream 流媒体设置
|
|
type V2RayStream struct {
|
|
Network string `json:"network,omitempty"`
|
|
}
|
|
|
|
// V2RayOutbound 出站配置
|
|
type V2RayOutbound struct {
|
|
Protocol string `json:"protocol"`
|
|
Settings *V2RayOutSettings `json:"settings,omitempty"`
|
|
Stream *V2RayStream `json:"streamSettings,omitempty"`
|
|
Tag string `json:"tag,omitempty"`
|
|
}
|
|
|
|
// V2RayOutSettings 出站设置
|
|
type V2RayOutSettings struct {
|
|
VNext []V2RayVNext `json:"vnext,omitempty"`
|
|
Servers []V2RayServer `json:"servers,omitempty"`
|
|
Users []V2RayUser `json:"users,omitempty"`
|
|
}
|
|
|
|
// V2RayVNext 服务器节点
|
|
type V2RayVNext struct {
|
|
Address string `json:"address"`
|
|
Port int `json:"port"`
|
|
Users []V2RayUser `json:"users"`
|
|
}
|
|
|
|
// V2RayUser 用户信息
|
|
type V2RayUser struct {
|
|
ID string `json:"id"`
|
|
AlterID int `json:"alterId,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
Security string `json:"security,omitempty"`
|
|
Level int `json:"level,omitempty"`
|
|
}
|
|
|
|
// V2RayServer 服务器信息
|
|
type V2RayServer struct {
|
|
Address string `json:"address"`
|
|
Port int `json:"port"`
|
|
Method string `json:"method,omitempty"`
|
|
Password string `json:"password,omitempty"`
|
|
OTA bool `json:"ota,omitempty"`
|
|
Users []V2RayUser `json:"users,omitempty"`
|
|
}
|
|
|
|
// V2RayRouting 路由配置
|
|
type V2RayRouting struct {
|
|
Rules []V2RayRule `json:"rules"`
|
|
}
|
|
|
|
// V2RayRule 路由规则
|
|
type V2RayRule struct {
|
|
Type string `json:"type"`
|
|
InboundTag []string `json:"inboundTag,omitempty"`
|
|
OutboundTag string `json:"outboundTag,omitempty"`
|
|
Domain []string `json:"domain,omitempty"`
|
|
IP []string `json:"ip,omitempty"`
|
|
}
|
|
|
|
// createV2RayConfig 创建V2Ray配置结构
|
|
func (g *V2RayGenerator) createV2RayConfig(configs []*parser.ProxyConfig, options *GenerationOptions) *V2RayConfig {
|
|
config := &V2RayConfig{
|
|
Log: &V2RayLog{
|
|
Loglevel: "info",
|
|
},
|
|
Inbound: g.createInbound(options),
|
|
Outbound: g.createOutbound(configs),
|
|
Routing: g.createRouting(),
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
// createInbound 创建入站配置
|
|
func (g *V2RayGenerator) createInbound(options *GenerationOptions) *V2RayInbound {
|
|
port := 10808
|
|
if options.MixedPort > 0 {
|
|
port = options.MixedPort
|
|
}
|
|
|
|
return &V2RayInbound{
|
|
Protocol: "socks",
|
|
Listen: "127.0.0.1",
|
|
Port: port,
|
|
Settings: &V2RayInSettings{
|
|
Auth: "noauth",
|
|
UDP: true,
|
|
UserLevel: 0,
|
|
},
|
|
Sniffing: &V2RaySniffing{
|
|
Enabled: true,
|
|
DestOverride: []string{"http", "tls"},
|
|
},
|
|
}
|
|
}
|
|
|
|
// createOutbound 创建出站配置
|
|
func (g *V2RayGenerator) createOutbound(configs []*parser.ProxyConfig) *V2RayOutbound {
|
|
// 代理节点列表
|
|
vnext := make([]V2RayVNext, 0)
|
|
servers := make([]V2RayServer, 0)
|
|
|
|
for _, config := range configs {
|
|
switch config.Protocol {
|
|
case "vmess":
|
|
vnext = append(vnext, g.createVMessVNext(config))
|
|
case "ss":
|
|
servers = append(servers, g.createShadowsocksServer(config))
|
|
case "trojan":
|
|
servers = append(servers, g.createTrojanServer(config))
|
|
}
|
|
}
|
|
|
|
outbound := &V2RayOutbound{
|
|
Protocol: "freedom",
|
|
Tag: "direct",
|
|
}
|
|
|
|
// 如果有代理节点,创建代理出站
|
|
if len(vnext) > 0 || len(servers) > 0 {
|
|
if len(vnext) > 0 {
|
|
outbound = &V2RayOutbound{
|
|
Protocol: "vmess",
|
|
Tag: "proxy",
|
|
Settings: &V2RayOutSettings{
|
|
VNext: vnext,
|
|
},
|
|
}
|
|
} else {
|
|
outbound = &V2RayOutbound{
|
|
Protocol: "shadowsocks",
|
|
Tag: "proxy",
|
|
Settings: &V2RayOutSettings{
|
|
Servers: servers,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
return outbound
|
|
}
|
|
|
|
// createVMessVNext 创建VMess节点配置
|
|
func (g *V2RayGenerator) createVMessVNext(config *parser.ProxyConfig) V2RayVNext {
|
|
uuid, _ := config.Settings["uuid"].(string)
|
|
alterId, _ := config.Settings["alterId"].(int)
|
|
if alterId == 0 {
|
|
alterId = 0
|
|
}
|
|
|
|
return V2RayVNext{
|
|
Address: config.Server,
|
|
Port: config.Port,
|
|
Users: []V2RayUser{
|
|
{
|
|
ID: uuid,
|
|
AlterID: alterId,
|
|
Security: "auto",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// createShadowsocksServer 创建Shadowsocks服务器配置
|
|
func (g *V2RayGenerator) createShadowsocksServer(config *parser.ProxyConfig) V2RayServer {
|
|
method, _ := config.Settings["method"].(string)
|
|
password, _ := config.Settings["password"].(string)
|
|
|
|
return V2RayServer{
|
|
Address: config.Server,
|
|
Port: config.Port,
|
|
Method: method,
|
|
Password: password,
|
|
OTA: false,
|
|
}
|
|
}
|
|
|
|
// createTrojanServer 创建Trojan服务器配置
|
|
func (g *V2RayGenerator) createTrojanServer(config *parser.ProxyConfig) V2RayServer {
|
|
password, _ := config.Settings["password"].(string)
|
|
|
|
return V2RayServer{
|
|
Address: config.Server,
|
|
Port: config.Port,
|
|
Method: "chacha20-ietf-poly1305",
|
|
Password: password,
|
|
OTA: false,
|
|
}
|
|
}
|
|
|
|
// createRouting 创建路由配置
|
|
func (g *V2RayGenerator) createRouting() *V2RayRouting {
|
|
return &V2RayRouting{
|
|
Rules: []V2RayRule{
|
|
{
|
|
Type: "field",
|
|
InboundTag: []string{"inbound"},
|
|
OutboundTag: "proxy",
|
|
},
|
|
{
|
|
Type: "field",
|
|
Domain: []string{"geosite:cn"},
|
|
OutboundTag: "direct",
|
|
},
|
|
{
|
|
Type: "field",
|
|
IP: []string{"geoip:cn", "geoip:private"},
|
|
OutboundTag: "direct",
|
|
},
|
|
{
|
|
Type: "field",
|
|
OutboundTag: "proxy",
|
|
},
|
|
},
|
|
}
|
|
} |