From 85609b41dea2236db608f30a2ad97bd233abdb0f Mon Sep 17 00:00:00 2001 From: cubemaze Date: Mon, 7 Aug 2023 12:23:34 +0800 Subject: [PATCH 1/3] chore: trojan and singConfigs --- conf/option.go | 39 ++++++++++++++++++++++++--------- core/sing/node.go | 52 +++++++++++++++++++++++++++++++++++++++++--- core/sing/user.go | 9 ++++++++ core/sing/utils.go | 19 ++++++++++++++++ core/xray/inbound.go | 4 ++-- 5 files changed, 108 insertions(+), 15 deletions(-) create mode 100644 core/sing/utils.go diff --git a/conf/option.go b/conf/option.go index 7073f25..5e0a9fc 100644 --- a/conf/option.go +++ b/conf/option.go @@ -7,21 +7,30 @@ type Options struct { CertConfig *CertConfig `yaml:"CertConfig"` XrayOptions XrayOptions `yaml:"XrayOptions"` HyOptions HyOptions `yaml:"HyOptions"` + SingOptions SingOptions `yaml:"SingOptions"` } type XrayOptions struct { - EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` - EnableDNS bool `yaml:"EnableDNS"` - DNSType string `yaml:"DNSType"` - EnableUot bool `yaml:"EnableUot"` - EnableTFO bool `yaml:"EnableTFO"` - DisableIVCheck bool `yaml:"DisableIVCheck"` - DisableSniffing bool `yaml:"DisableSniffing"` - EnableFallback bool `yaml:"EnableFallback"` - FallBackConfigs []FallBackConfig `yaml:"FallBackConfigs"` + EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` + EnableDNS bool `yaml:"EnableDNS"` + DNSType string `yaml:"DNSType"` + EnableUot bool `yaml:"EnableUot"` + EnableTFO bool `yaml:"EnableTFO"` + DisableIVCheck bool `yaml:"DisableIVCheck"` + DisableSniffing bool `yaml:"DisableSniffing"` + EnableFallback bool `yaml:"EnableFallback"` + FallBackConfigs []FallBackConfigForXray `yaml:"FallBackConfigs"` } -type FallBackConfig struct { +type SingOptions struct { + EnableProxyProtocol bool `yaml:"EnableProxyProtocol"` + TCPFastOpen bool `yaml:"EnableTFO"` + SniffEnabled bool `yaml:"EnableSniff"` + SniffOverrideDestination bool `yaml:"SniffOverrideDestination"` + FallBackConfigs *FallBackConfigForSing `yaml:"FallBackConfigs"` +} + +type FallBackConfigForXray struct { SNI string `yaml:"SNI"` Alpn string `yaml:"Alpn"` Path string `yaml:"Path"` @@ -29,6 +38,16 @@ type FallBackConfig struct { ProxyProtocolVer uint64 `yaml:"ProxyProtocolVer"` } +type FallBackConfigForSing struct { + // sing-box + FallBack FallBack `yaml:"FallBack"` + FallBackForALPN map[string]FallBack `yaml:"FallBackForALPN"` +} +type FallBack struct { + Server string `yaml:"Server"` + ServerPort string `yaml:"ServerPort"` +} + type HyOptions struct { Resolver string `yaml:"Resolver"` ResolvePreference string `yaml:"ResolvePreference"` diff --git a/core/sing/node.go b/core/sing/node.go index e6f202f..51cba83 100644 --- a/core/sing/node.go +++ b/core/sing/node.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "encoding/base64" "fmt" + "github.com/google/uuid" "net/netip" "net/url" "strconv" @@ -30,9 +31,14 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio return option.Inbound{}, fmt.Errorf("the listen ip not vail") } listen := option.ListenOptions{ - //ProxyProtocol: true, - Listen: (*option.ListenAddress)(&addr), - ListenPort: uint16(info.Port), + Listen: (*option.ListenAddress)(&addr), + ListenPort: uint16(info.Port), + ProxyProtocol: c.SingOptions.EnableProxyProtocol, + TCPFastOpen: c.SingOptions.TCPFastOpen, + InboundOptions: option.InboundOptions{ + SniffEnabled: c.SingOptions.SniffEnabled, + SniffOverrideDestination: c.SingOptions.SniffOverrideDestination, + }, } tls := option.InboundTLSOptions{ Enabled: info.Tls, @@ -121,6 +127,46 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio in.ShadowsocksOptions.Users = []option.ShadowsocksUser{{ Password: randomPasswd, }} + case "trojan": + in.Type = "trojan" + t := option.V2RayTransportOptions{ + Type: info.Network, + } + switch info.Network { + case "tcp": + t.Type = "" + case "grpc": + err := json.Unmarshal(info.NetworkSettings, &t.GRPCOptions) + if err != nil { + return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err) + } + } + randomPasswd := uuid.New().String() + in.TrojanOptions = option.TrojanInboundOptions{ + ListenOptions: listen, + Users: []option.TrojanUser{{ + Name: randomPasswd, + Password: randomPasswd, + }}, + TLS: &tls, + Transport: &t, + } + if c.SingOptions.FallBackConfigs != nil { + // fallback handling + fallback := c.SingOptions.FallBackConfigs.FallBack + fallbackPort, err := strconv.Atoi(fallback.ServerPort) + if err == nil { + in.TrojanOptions.Fallback = &option.ServerOptions{ + Server: fallback.Server, + ServerPort: uint16(fallbackPort), + } + } + fallbackForALPNMap := c.SingOptions.FallBackConfigs.FallBackForALPN + fallbackForALPN := make(map[string]*option.ServerOptions, len(fallbackForALPNMap)) + if err := processFallback(c, fallbackForALPN); err == nil { + in.TrojanOptions.FallbackForALPN = fallbackForALPN + } + } } return in, nil } diff --git a/core/sing/user.go b/core/sing/user.go index 775f720..ee7f1cb 100644 --- a/core/sing/user.go +++ b/core/sing/user.go @@ -50,6 +50,15 @@ func (b *Box) AddUsers(p *core.AddUsersParams) (added int, err error) { } } err = b.inbounds[p.Tag].(*inbound.ShadowsocksMulti).AddUsers(us) + case "trojan": + us := make([]option.TrojanUser, len(p.UserInfo)) + for i := range p.UserInfo { + us[i] = option.TrojanUser{ + Name: p.UserInfo[i].Uuid, + Password: p.UserInfo[i].Uuid, + } + } + err = b.inbounds[p.Tag].(*inbound.Trojan).AddUsers(us) } if err != nil { return 0, err diff --git a/core/sing/utils.go b/core/sing/utils.go new file mode 100644 index 0000000..2db7ebf --- /dev/null +++ b/core/sing/utils.go @@ -0,0 +1,19 @@ +package sing + +import ( + "fmt" + "github.com/InazumaV/V2bX/conf" + "github.com/inazumav/sing-box/option" + "strconv" +) + +func processFallback(c *conf.Options, fallbackForALPN map[string]*option.ServerOptions) error { + for k, v := range c.SingOptions.FallBackConfigs.FallBackForALPN { + fallbackPort, err := strconv.Atoi(v.ServerPort) + if err != nil { + return fmt.Errorf("unable to parse fallbackForALPN server port error: %s", err) + } + fallbackForALPN[k] = &option.ServerOptions{Server: v.Server, ServerPort: uint16(fallbackPort)} + } + return nil +} diff --git a/core/xray/inbound.go b/core/xray/inbound.go index fb2ae4d..44320bb 100644 --- a/core/xray/inbound.go +++ b/core/xray/inbound.go @@ -274,7 +274,7 @@ func buildShadowsocks(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *c return nil } -func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.VLessInboundFallback, error) { +func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfigForXray) ([]*coreConf.VLessInboundFallback, error) { if fallbackConfigs == nil { return nil, fmt.Errorf("you must provide FallBackConfigs") } @@ -299,7 +299,7 @@ func buildVlessFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.VLe return vlessFallBacks, nil } -func buildTrojanFallbacks(fallbackConfigs []conf.FallBackConfig) ([]*coreConf.TrojanInboundFallback, error) { +func buildTrojanFallbacks(fallbackConfigs []conf.FallBackConfigForXray) ([]*coreConf.TrojanInboundFallback, error) { if fallbackConfigs == nil { return nil, fmt.Errorf("you must provide FallBackConfigs") } From 78beaeb03f9150f0ef068f71c0ae187816fd75a1 Mon Sep 17 00:00:00 2001 From: cubemaze Date: Mon, 7 Aug 2023 12:36:58 +0800 Subject: [PATCH 2/3] chore: update example config.yml --- example/config.yml.example | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/example/config.yml.example b/example/config.yml.example index b6098de..04959fe 100644 --- a/example/config.yml.example +++ b/example/config.yml.example @@ -38,6 +38,19 @@ Nodes: Path: # HTTP PATH, Empty for any Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/features/fallback.html for details. ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for disable + SingOptions: + EnableTFO: true + SniffEnabled: true + SniffOverrideDestination: true + EnableProxyProtocol: false + FallBackConfigs: + FallBack: + Server: 127.0.0.1 + ServerPort: 8080 + FallBackForALPN: + http/1.1: + Server: 127.0.0.1 + ServerPort: 8081 HyOptions: Resolver: "udp://1.1.1.1:53" # DNS resolver address ResolvePreference: 64 # DNS IPv4/IPv6 preference. Available options: "64" (IPv6 first, fallback to IPv4), "46" (IPv4 first, fallback to IPv6), "6" (IPv6 only), "4" (IPv4 only) From 329d1480020bd41daff74313426005e58db7107a Mon Sep 17 00:00:00 2001 From: cubemaze Date: Mon, 7 Aug 2023 14:52:50 +0800 Subject: [PATCH 3/3] chore: support reality --- api/panel/node.go | 16 +++++------ conf/cert.go | 16 +++++------ core/sing/node.go | 69 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/api/panel/node.go b/api/panel/node.go index c51878e..42a1252 100644 --- a/api/panel/node.go +++ b/api/panel/node.go @@ -86,14 +86,14 @@ type V2rayExtraConfig struct { } type RealityConfig struct { - Dest interface{} `yaml:"Dest" json:"Dest"` - Xver string `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` + Dest string `yaml:"Dest" json:"Dest"` + Xver string `yaml:"Xver" json:"Xver"` + ServerNames []string `yaml:"ServerNames" json:"ServerNames"` + PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` + MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` + MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` + MaxTimeDiff string `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` + ShortIds []string `yaml:"ShortIds" json:"ShortIds"` } type DNSConfig struct { diff --git a/conf/cert.go b/conf/cert.go index a921964..9ef89b1 100644 --- a/conf/cert.go +++ b/conf/cert.go @@ -13,12 +13,12 @@ type CertConfig struct { } type RealityConfig struct { - Dest interface{} `yaml:"Dest" json:"Dest"` - Xver uint64 `yaml:"Xver" json:"Xver"` - ServerNames []string `yaml:"ServerNames" json:"ServerNames"` - PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` - MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` - MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` - MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` - ShortIds []string `yaml:"ShortIds" json:"ShortIds"` + Dest string `yaml:"Dest" json:"Dest"` + Xver uint64 `yaml:"Xver" json:"Xver"` + ServerNames []string `yaml:"ServerNames" json:"ServerNames"` + PrivateKey string `yaml:"PrivateKey" json:"PrivateKey"` + MinClientVer string `yaml:"MinClientVer" json:"MinClientVer"` + MaxClientVer string `yaml:"MaxClientVer" json:"MaxClientVer"` + MaxTimeDiff uint64 `yaml:"MaxTimeDiff" json:"MaxTimeDiff"` + ShortIds []string `yaml:"ShortIds" json:"ShortIds"` } diff --git a/core/sing/node.go b/core/sing/node.go index 51cba83..3ca26a4 100644 --- a/core/sing/node.go +++ b/core/sing/node.go @@ -10,6 +10,7 @@ import ( "net/url" "strconv" "strings" + "time" "github.com/inazumav/sing-box/inbound" F "github.com/sagernet/sing/common/format" @@ -40,11 +41,69 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio SniffOverrideDestination: c.SingOptions.SniffOverrideDestination, }, } - tls := option.InboundTLSOptions{ - Enabled: info.Tls, - CertificatePath: c.CertConfig.CertFile, - KeyPath: c.CertConfig.KeyFile, - ServerName: info.ServerName, + var tls option.InboundTLSOptions + if info.Tls || info.Type == "hysteria" { + if c.CertConfig == nil { + return option.Inbound{}, fmt.Errorf("the CertConfig is not vail") + } + tls.Enabled = true + tls.Insecure = true + tls.ServerName = info.ServerName + switch c.CertConfig.CertMode { + case "none", "": + break // disable + case "reality": + if c.CertConfig.RealityConfig == nil { + return option.Inbound{}, fmt.Errorf("RealityConfig is not valid") + } + rc := c.CertConfig.RealityConfig + tls.ServerName = rc.ServerNames[0] + if len(rc.ShortIds) == 0 { + rc.ShortIds = []string{""} + } + dest, _ := strconv.Atoi(rc.Dest) + mtd, _ := strconv.Atoi(strconv.FormatUint(rc.MaxTimeDiff, 10)) + tls.Reality = &option.InboundRealityOptions{ + Enabled: true, + ShortID: rc.ShortIds, + PrivateKey: rc.PrivateKey, + MaxTimeDifference: option.Duration(time.Duration(mtd) * time.Second), + Handshake: option.InboundRealityHandshakeOptions{ + ServerOptions: option.ServerOptions{ + Server: rc.ServerNames[0], + ServerPort: uint16(dest), + }, + }, + } + + case "remote": + if info.ExtraConfig.EnableReality == "true" { + if c.CertConfig.RealityConfig == nil { + return option.Inbound{}, fmt.Errorf("RealityConfig is not valid") + } + rc := info.ExtraConfig.RealityConfig + if len(rc.ShortIds) == 0 { + rc.ShortIds = []string{""} + } + dest, _ := strconv.Atoi(rc.Dest) + mtd, _ := strconv.Atoi(rc.MaxTimeDiff) + tls.Reality = &option.InboundRealityOptions{ + Enabled: true, + ShortID: rc.ShortIds, + PrivateKey: rc.PrivateKey, + MaxTimeDifference: option.Duration(time.Duration(mtd) * time.Second), + Handshake: option.InboundRealityHandshakeOptions{ + ServerOptions: option.ServerOptions{ + Server: rc.ServerNames[0], + ServerPort: uint16(dest), + }, + }, + } + } + default: + tls.CertificatePath = c.CertConfig.CertFile + tls.KeyPath = c.CertConfig.KeyFile + } } in := option.Inbound{ Tag: tag,