revert support of clash subscription

This commit is contained in:
yiguo
2024-01-08 17:08:31 +08:00
parent e876c9369a
commit b107a762e8
3 changed files with 441 additions and 25 deletions

48
go.mod
View File

@@ -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
View 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
}
}

View File

@@ -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) {