mirror of
https://github.com/amnezia-vpn/amnezia-libxray.git
synced 2026-05-17 06:55:44 +03:00
revert support of clash subscription
This commit is contained in:
48
go.mod
48
go.mod
@@ -1,56 +1,56 @@
|
||||
module github.com/xtls/libxray
|
||||
|
||||
go 1.21.4
|
||||
go 1.21.5
|
||||
|
||||
require (
|
||||
github.com/xtls/xray-core v1.8.6
|
||||
google.golang.org/grpc v1.59.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
github.com/xtls/xray-core v1.8.7
|
||||
google.golang.org/grpc v1.60.1
|
||||
google.golang.org/protobuf v1.32.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/cloudflare/circl v1.3.6 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/klauspost/compress v1.17.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/quic-go/quic-go v0.40.0 // indirect
|
||||
github.com/refraction-networking/utls v1.5.4 // indirect
|
||||
github.com/quic-go/quic-go v0.40.1 // indirect
|
||||
github.com/refraction-networking/utls v1.6.0 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/sagernet/sing v0.2.17 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5 // indirect
|
||||
github.com/sagernet/sing v0.3.0 // indirect
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19 // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
|
||||
416
nodep/clash.go
Normal file
416
nodep/clash.go
Normal file
@@ -0,0 +1,416 @@
|
||||
package nodep
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type ClashYaml struct {
|
||||
Proxies []ClashProxy `yaml:"proxies,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxy struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
Type string `yaml:"type,omitempty"`
|
||||
Server string `yaml:"server,omitempty"`
|
||||
Port int `yaml:"port,omitempty"`
|
||||
Uuid string `yaml:"uuid,omitempty"`
|
||||
Cipher string `yaml:"cipher,omitempty"`
|
||||
Username string `yaml:"username,omitempty"`
|
||||
Password string `yaml:"password,omitempty"`
|
||||
|
||||
Tls bool `yaml:"tls,omitempty"`
|
||||
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
|
||||
Servername string `yaml:"servername,omitempty"`
|
||||
Sni string `yaml:"sni,omitempty"`
|
||||
Alpn []string `yaml:"alpn,omitempty"`
|
||||
|
||||
Fingerprint string `yaml:"fingerprint,omitempty"`
|
||||
ClientFingerprint string `yaml:"client-fingerprint,omitempty"`
|
||||
Flow string `yaml:"flow,omitempty"`
|
||||
RealityOpts *ClashProxyRealityOpts `yaml:"reality-opts,omitempty"`
|
||||
|
||||
Network string `yaml:"network,omitempty"`
|
||||
Plugin string `yaml:"plugin,omitempty"`
|
||||
PluginOpts *ClashProxyPluginOpts `yaml:"plugin-opts,omitempty"`
|
||||
WsOpts *ClashProxyWsOpts `yaml:"ws-opts,omitempty"`
|
||||
H2Opts *ClashProxyH2Opts `yaml:"h2-opts,omitempty"`
|
||||
GrpcOpts *ClashProxyGrpcOpts `yaml:"grpc-opts,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyPluginOpts struct {
|
||||
Mode string `yaml:"mode,omitempty"`
|
||||
Tls bool `yaml:"tls,omitempty"`
|
||||
Fingerprint string `yaml:"fingerprint,omitempty"`
|
||||
SkipCertVerify bool `yaml:"skip-cert-verify,omitempty"`
|
||||
Host string `yaml:"host,omitempty"`
|
||||
Path string `yaml:"path,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyWsOpts struct {
|
||||
Path string `yaml:"path,omitempty"`
|
||||
Headers *ClashProxyWsOptsHeaders `yaml:"headers,omitempty"`
|
||||
MaxEarlyData int `yaml:"max-early-data,omitempty"`
|
||||
EarlyDataHeaderName string `yaml:"early-data-header-name,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyWsOptsHeaders struct {
|
||||
Host string `yaml:"Host,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyH2Opts struct {
|
||||
Host []string `yaml:"host,omitempty"`
|
||||
Path string `yaml:"path,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyGrpcOpts struct {
|
||||
GrpcServiceName string `yaml:"grpc-service-name,omitempty"`
|
||||
}
|
||||
|
||||
type ClashProxyRealityOpts struct {
|
||||
PublicKey string `yaml:"public-key,omitempty"`
|
||||
ShortId string `yaml:"short-id,omitempty"`
|
||||
}
|
||||
|
||||
func tryConvertClashYaml(text string) (*XrayJson, error) {
|
||||
ClashBytes := []byte(text)
|
||||
Clash := ClashYaml{}
|
||||
|
||||
err := yaml.Unmarshal(ClashBytes, &Clash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xray := Clash.xrayConfig()
|
||||
return &xray, nil
|
||||
}
|
||||
|
||||
func (Clash ClashYaml) xrayConfig() XrayJson {
|
||||
var xray XrayJson
|
||||
|
||||
var outbounds []XrayOutbound
|
||||
for _, proxy := range Clash.Proxies {
|
||||
if outbound, err := proxy.outbound(); err == nil {
|
||||
outbounds = append(outbounds, *outbound)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
xray.Outbounds = outbounds
|
||||
|
||||
return xray
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) outbound() (*XrayOutbound, error) {
|
||||
switch proxy.Type {
|
||||
case "ss":
|
||||
outbound, err := proxy.shadowsocksOutbound()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbound, nil
|
||||
|
||||
case "vmess":
|
||||
outbound, err := proxy.vmessOutbound()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbound, nil
|
||||
|
||||
case "vless":
|
||||
outbound, err := proxy.vlessOutbound()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbound, nil
|
||||
|
||||
case "socks5":
|
||||
outbound, err := proxy.socksOutbound()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbound, nil
|
||||
case "trojan":
|
||||
outbound, err := proxy.trojanOutbound()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbound, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupport proxy type: %s", proxy.Type)
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) shadowsocksOutbound() (*XrayOutbound, error) {
|
||||
var outbound XrayOutbound
|
||||
outbound.Protocol = "shadowsocks"
|
||||
outbound.Name = proxy.Name
|
||||
|
||||
var server XrayShadowsocksServer
|
||||
server.Address = proxy.Server
|
||||
server.Port = proxy.Port
|
||||
server.Method = proxy.Cipher
|
||||
server.Password = proxy.Password
|
||||
|
||||
var settings XrayShadowsocks
|
||||
settings.Servers = []XrayShadowsocksServer{server}
|
||||
|
||||
setttingsBytes, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.Settings = (*json.RawMessage)(&setttingsBytes)
|
||||
|
||||
if len(proxy.Plugin) != 0 {
|
||||
if proxy.Plugin != "v2ray-plugin" {
|
||||
return nil, fmt.Errorf("unsupport ss plugin: obfs")
|
||||
}
|
||||
if proxy.PluginOpts == nil {
|
||||
return nil, fmt.Errorf("unsupport ss plugin-opts: nil")
|
||||
}
|
||||
if proxy.PluginOpts.Mode != "websocket" {
|
||||
return nil, fmt.Errorf("unsupport ss plugin-opts mode: %s", proxy.PluginOpts.Mode)
|
||||
}
|
||||
var streamSetting XrayStreamSettings
|
||||
streamSetting.Network = "websocket"
|
||||
|
||||
var wsSettings XrayWsSettings
|
||||
if len(proxy.PluginOpts.Path) > 0 {
|
||||
wsSettings.Path = proxy.PluginOpts.Path
|
||||
}
|
||||
if len(proxy.PluginOpts.Host) > 0 {
|
||||
var headers XrayWsSettingsHeaders
|
||||
headers.Host = proxy.PluginOpts.Host
|
||||
wsSettings.Headers = &headers
|
||||
}
|
||||
streamSetting.WsSettings = &wsSettings
|
||||
|
||||
if proxy.PluginOpts.Tls {
|
||||
var tlsSettings XrayTlsSettings
|
||||
tlsSettings.Fingerprint = proxy.PluginOpts.Fingerprint
|
||||
tlsSettings.AllowInsecure = proxy.PluginOpts.SkipCertVerify
|
||||
streamSetting.TlsSettings = &tlsSettings
|
||||
}
|
||||
|
||||
outbound.StreamSettings = &streamSetting
|
||||
}
|
||||
return &outbound, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) vmessOutbound() (*XrayOutbound, error) {
|
||||
var outbound XrayOutbound
|
||||
outbound.Protocol = "vmess"
|
||||
outbound.Name = proxy.Name
|
||||
|
||||
var user XrayVMessVnextUser
|
||||
user.Id = proxy.Uuid
|
||||
user.Security = proxy.Cipher
|
||||
|
||||
var vnext XrayVMessVnext
|
||||
vnext.Address = proxy.Server
|
||||
vnext.Port = proxy.Port
|
||||
vnext.Users = []XrayVMessVnextUser{user}
|
||||
|
||||
var settings XrayVMess
|
||||
settings.Vnext = []XrayVMessVnext{vnext}
|
||||
|
||||
setttingsBytes, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.Settings = (*json.RawMessage)(&setttingsBytes)
|
||||
|
||||
streamSettings, err := proxy.streamSettings(outbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.StreamSettings = streamSettings
|
||||
|
||||
return &outbound, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) vlessOutbound() (*XrayOutbound, error) {
|
||||
var outbound XrayOutbound
|
||||
outbound.Protocol = "vless"
|
||||
outbound.Name = proxy.Name
|
||||
|
||||
var user XrayVLESSVnextUser
|
||||
user.Id = proxy.Uuid
|
||||
user.Flow = proxy.Flow
|
||||
|
||||
var vnext XrayVLESSVnext
|
||||
vnext.Address = proxy.Server
|
||||
vnext.Port = proxy.Port
|
||||
vnext.Users = []XrayVLESSVnextUser{user}
|
||||
|
||||
var settings XrayVLESS
|
||||
settings.Vnext = []XrayVLESSVnext{vnext}
|
||||
|
||||
setttingsBytes, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.Settings = (*json.RawMessage)(&setttingsBytes)
|
||||
|
||||
streamSettings, err := proxy.streamSettings(outbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.StreamSettings = streamSettings
|
||||
|
||||
return &outbound, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) socksOutbound() (*XrayOutbound, error) {
|
||||
var outbound XrayOutbound
|
||||
outbound.Protocol = "socks"
|
||||
outbound.Name = proxy.Name
|
||||
|
||||
var user XraySocksServerUser
|
||||
user.User = proxy.Username
|
||||
user.Pass = proxy.Password
|
||||
|
||||
var server XraySocksServer
|
||||
server.Address = proxy.Server
|
||||
server.Port = proxy.Port
|
||||
server.Users = []XraySocksServerUser{user}
|
||||
|
||||
var settings XraySocks
|
||||
settings.Servers = []XraySocksServer{server}
|
||||
|
||||
setttingsBytes, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.Settings = (*json.RawMessage)(&setttingsBytes)
|
||||
|
||||
streamSettings, err := proxy.streamSettings(outbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.StreamSettings = streamSettings
|
||||
|
||||
return &outbound, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) trojanOutbound() (*XrayOutbound, error) {
|
||||
var outbound XrayOutbound
|
||||
outbound.Protocol = "trojan"
|
||||
outbound.Name = proxy.Name
|
||||
|
||||
var server XrayTrojanServer
|
||||
server.Address = proxy.Server
|
||||
server.Port = proxy.Port
|
||||
server.Password = proxy.Password
|
||||
|
||||
var settings XrayTrojan
|
||||
settings.Servers = []XrayTrojanServer{server}
|
||||
|
||||
setttingsBytes, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.Settings = (*json.RawMessage)(&setttingsBytes)
|
||||
|
||||
streamSettings, err := proxy.streamSettings(outbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.StreamSettings = streamSettings
|
||||
|
||||
return &outbound, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) streamSettings(outbound XrayOutbound) (*XrayStreamSettings, error) {
|
||||
var streamSettings XrayStreamSettings
|
||||
if len(proxy.Network) == 0 {
|
||||
streamSettings.Network = "tcp"
|
||||
} else {
|
||||
streamSettings.Network = proxy.Network
|
||||
}
|
||||
|
||||
switch streamSettings.Network {
|
||||
case "ws":
|
||||
if proxy.WsOpts != nil {
|
||||
var wsSettings XrayWsSettings
|
||||
if proxy.WsOpts.Headers != nil {
|
||||
var headers XrayWsSettingsHeaders
|
||||
headers.Host = proxy.WsOpts.Headers.Host
|
||||
wsSettings.Headers = &headers
|
||||
}
|
||||
|
||||
wsSettings.Path = proxy.WsOpts.Path
|
||||
|
||||
if proxy.WsOpts.MaxEarlyData > 0 {
|
||||
return nil, fmt.Errorf("unsupport ws-opts max-early-data: %d", proxy.WsOpts.MaxEarlyData)
|
||||
}
|
||||
streamSettings.WsSettings = &wsSettings
|
||||
}
|
||||
case "h2":
|
||||
if proxy.H2Opts != nil {
|
||||
var httpSettings XrayHttpSettings
|
||||
httpSettings.Host = proxy.H2Opts.Host
|
||||
httpSettings.Path = proxy.H2Opts.Path
|
||||
|
||||
streamSettings.HttpSettings = &httpSettings
|
||||
}
|
||||
case "grpc":
|
||||
if proxy.GrpcOpts != nil {
|
||||
var grpcSettings XrayGrpcSettings
|
||||
grpcSettings.ServiceName = proxy.GrpcOpts.GrpcServiceName
|
||||
|
||||
streamSettings.GrpcSettings = &grpcSettings
|
||||
}
|
||||
}
|
||||
proxy.parseSecurity(&streamSettings, outbound)
|
||||
return &streamSettings, nil
|
||||
}
|
||||
|
||||
func (proxy ClashProxy) parseSecurity(streamSettings *XrayStreamSettings, outbound XrayOutbound) {
|
||||
var tlsSettings XrayTlsSettings
|
||||
var realitySettings XrayRealitySettings
|
||||
|
||||
if proxy.Tls {
|
||||
streamSettings.Security = "tls"
|
||||
}
|
||||
if proxy.SkipCertVerify {
|
||||
tlsSettings.AllowInsecure = true
|
||||
}
|
||||
|
||||
if proxy.RealityOpts != nil {
|
||||
streamSettings.Security = "reality"
|
||||
realitySettings.PublicKey = proxy.RealityOpts.PublicKey
|
||||
realitySettings.ShortId = proxy.RealityOpts.ShortId
|
||||
}
|
||||
if len(proxy.Servername) > 0 {
|
||||
tlsSettings.ServerName = proxy.Servername
|
||||
realitySettings.ServerName = proxy.Servername
|
||||
}
|
||||
if len(proxy.Sni) > 0 {
|
||||
tlsSettings.ServerName = proxy.Sni
|
||||
realitySettings.ServerName = proxy.Sni
|
||||
}
|
||||
if len(proxy.Alpn) > 0 {
|
||||
tlsSettings.Alpn = proxy.Alpn
|
||||
}
|
||||
if len(proxy.Fingerprint) > 0 {
|
||||
tlsSettings.Fingerprint = proxy.Fingerprint
|
||||
realitySettings.Fingerprint = proxy.Fingerprint
|
||||
}
|
||||
if len(proxy.ClientFingerprint) > 0 {
|
||||
tlsSettings.Fingerprint = proxy.ClientFingerprint
|
||||
realitySettings.Fingerprint = proxy.ClientFingerprint
|
||||
}
|
||||
|
||||
if outbound.Protocol == "trojan" && len(streamSettings.Security) == 0 {
|
||||
streamSettings.Security = "tls"
|
||||
}
|
||||
|
||||
switch streamSettings.Security {
|
||||
case "tls":
|
||||
streamSettings.TlsSettings = &tlsSettings
|
||||
case "reality":
|
||||
streamSettings.RealitySettings = &realitySettings
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func tryParse(text string) (*XrayJson, error) {
|
||||
cleanText := FixWindowsReturn(base64Text)
|
||||
return parsePlainShareText(cleanText)
|
||||
}
|
||||
return nil, fmt.Errorf("wrong format")
|
||||
return tryConvertClashYaml(text)
|
||||
}
|
||||
|
||||
func decodeBase64Text(text string) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user