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