Fix service.go to work with singbox 1.8.2
Drop deprecated feautre (Clash API: cache_file and store_selected) Add feature (Cache File: path) Add new idle_timeout field for URLTest outbound Refactor outbound.go Add feature to omit TLSTricks and Fragment on VLESS Reality configs.
This commit is contained in:
@@ -53,8 +53,10 @@ func BuildConfig(configOpt ConfigOptions, input option.Options) (*option.Options
|
|||||||
options.Experimental = &option.ExperimentalOptions{
|
options.Experimental = &option.ExperimentalOptions{
|
||||||
ClashAPI: &option.ClashAPIOptions{
|
ClashAPI: &option.ClashAPIOptions{
|
||||||
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", configOpt.ClashApiPort),
|
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", configOpt.ClashApiPort),
|
||||||
StoreSelected: true,
|
},
|
||||||
CacheFile: "clash.db",
|
CacheFile: &option.CacheFileOptions{
|
||||||
|
Enabled: true,
|
||||||
|
Path: "clash.db",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,9 +356,10 @@ func BuildConfig(configOpt ConfigOptions, input option.Options) (*option.Options
|
|||||||
Type: C.TypeURLTest,
|
Type: C.TypeURLTest,
|
||||||
Tag: "auto",
|
Tag: "auto",
|
||||||
URLTestOptions: option.URLTestOutboundOptions{
|
URLTestOptions: option.URLTestOutboundOptions{
|
||||||
Outbounds: tags,
|
Outbounds: tags,
|
||||||
URL: configOpt.ConnectionTestUrl,
|
URL: configOpt.ConnectionTestUrl,
|
||||||
Interval: configOpt.URLTestInterval,
|
Interval: configOpt.URLTestInterval,
|
||||||
|
IdleTimeout: configOpt.URLTestIdleTimeout,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +411,6 @@ func applyOverrides(overrides ConfigOptions, options option.Options) *option.Opt
|
|||||||
if overrides.EnableClashApi {
|
if overrides.EnableClashApi {
|
||||||
options.Experimental.ClashAPI = &option.ClashAPIOptions{
|
options.Experimental.ClashAPI = &option.ClashAPIOptions{
|
||||||
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", overrides.ClashApiPort),
|
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", overrides.ClashApiPort),
|
||||||
StoreSelected: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type ConfigOptions struct {
|
|||||||
TUNStack string `json:"tun-stack"`
|
TUNStack string `json:"tun-stack"`
|
||||||
ConnectionTestUrl string `json:"connection-test-url"`
|
ConnectionTestUrl string `json:"connection-test-url"`
|
||||||
URLTestInterval option.Duration `json:"url-test-interval"`
|
URLTestInterval option.Duration `json:"url-test-interval"`
|
||||||
|
URLTestIdleTimeout option.Duration `json:"url-test-idle-timeout"`
|
||||||
EnableClashApi bool `json:"enable-clash-api"`
|
EnableClashApi bool `json:"enable-clash-api"`
|
||||||
ClashApiPort uint16 `json:"clash-api-port"`
|
ClashApiPort uint16 `json:"clash-api-port"`
|
||||||
EnableTun bool `json:"enable-tun"`
|
EnableTun bool `json:"enable-tun"`
|
||||||
@@ -72,6 +73,7 @@ func DefaultConfigOptions() *ConfigOptions {
|
|||||||
TUNStack: "mixed",
|
TUNStack: "mixed",
|
||||||
ConnectionTestUrl: "https://cp.cloudflare.com/",
|
ConnectionTestUrl: "https://cp.cloudflare.com/",
|
||||||
URLTestInterval: option.Duration(10 * time.Minute),
|
URLTestInterval: option.Duration(10 * time.Minute),
|
||||||
|
URLTestIdleTimeout: option.Duration(100 * time.Minute),
|
||||||
EnableClashApi: true,
|
EnableClashApi: true,
|
||||||
ClashApiPort: 6756,
|
ClashApiPort: 6756,
|
||||||
EnableTun: true,
|
EnableTun: true,
|
||||||
|
|||||||
@@ -11,6 +11,70 @@ import (
|
|||||||
|
|
||||||
type outboundMap map[string]interface{}
|
type outboundMap map[string]interface{}
|
||||||
|
|
||||||
|
func patchOutboundMux(base option.Outbound, configOpt ConfigOptions, obj outboundMap) outboundMap {
|
||||||
|
if configOpt.EnableMux {
|
||||||
|
multiplex := option.OutboundMultiplexOptions{
|
||||||
|
Enabled: true,
|
||||||
|
Padding: configOpt.MuxPadding,
|
||||||
|
MaxStreams: configOpt.MaxStreams,
|
||||||
|
Protocol: configOpt.MuxProtocol,
|
||||||
|
}
|
||||||
|
obj["multiplex"] = multiplex
|
||||||
|
} else {
|
||||||
|
delete(obj, "multiplex")
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func patchOutboundTLSTricks(base option.Outbound, configOpt ConfigOptions, obj outboundMap) outboundMap {
|
||||||
|
|
||||||
|
obj = patchOutboundFragment(base, configOpt, obj)
|
||||||
|
if tls, ok := obj["tls"].(map[string]interface{}); ok {
|
||||||
|
tlsTricks := option.TLSTricksOptions{
|
||||||
|
MixedCaseSNI: configOpt.TLSTricks.EnableMixedSNICase,
|
||||||
|
}
|
||||||
|
|
||||||
|
if configOpt.TLSTricks.EnablePadding {
|
||||||
|
tlsTricks.PaddingMode = "random"
|
||||||
|
tlsTricks.PaddingSize = configOpt.TLSTricks.PaddingSize
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsTricks.MixedCaseSNI || tlsTricks.PaddingMode != "" {
|
||||||
|
tls["tls_tricks"] = tlsTricks
|
||||||
|
} else {
|
||||||
|
tls["tls_tricks"] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func patchOutboundFragment(base option.Outbound, configOpt ConfigOptions, obj outboundMap) outboundMap {
|
||||||
|
if configOpt.EnableFragment {
|
||||||
|
tlsFragment := option.TLSFragmentOptions{
|
||||||
|
Enabled: configOpt.TLSTricks.EnableFragment,
|
||||||
|
Size: configOpt.TLSTricks.FragmentSize,
|
||||||
|
Sleep: configOpt.TLSTricks.FragmentSleep,
|
||||||
|
}
|
||||||
|
obj["tls_fragment"] = tlsFragment
|
||||||
|
} else {
|
||||||
|
obj["tls_fragment"] = nil
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func isOutboundReality(base option.Outbound) bool {
|
||||||
|
// this function checks reality status ONLY FOR VLESS.
|
||||||
|
// Some other protocols can also use reality, but it's discouraged as stated in the reality document
|
||||||
|
isReality := false
|
||||||
|
switch base.Type {
|
||||||
|
case C.TypeVLESS:
|
||||||
|
if base.VLESSOptions.TLS.Reality != nil {
|
||||||
|
isReality = base.VLESSOptions.TLS.Reality.Enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isReality
|
||||||
|
}
|
||||||
|
|
||||||
func patchOutbound(base option.Outbound, configOpt ConfigOptions) (*option.Outbound, string, error) {
|
func patchOutbound(base option.Outbound, configOpt ConfigOptions) (*option.Outbound, string, error) {
|
||||||
var serverDomain string
|
var serverDomain string
|
||||||
var outbound option.Outbound
|
var outbound option.Outbound
|
||||||
@@ -35,50 +99,12 @@ func patchOutbound(base option.Outbound, configOpt ConfigOptions) (*option.Outbo
|
|||||||
serverDomain = fmt.Sprintf("full:%s", server)
|
serverDomain = fmt.Sprintf("full:%s", server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !(base.Type == C.TypeSelector || base.Type == C.TypeURLTest || base.Type == C.TypeBlock || base.Type == C.TypeDNS || isOutboundReality(base)) {
|
||||||
if !(base.Type == C.TypeSelector || base.Type == C.TypeURLTest || base.Type == C.TypeBlock || base.Type == C.TypeDNS) {
|
obj = patchOutboundTLSTricks(base, configOpt, obj)
|
||||||
if configOpt.EnableFragment {
|
|
||||||
tlsFragment := option.TLSFragmentOptions{
|
|
||||||
Enabled: configOpt.TLSTricks.EnableFragment,
|
|
||||||
Size: configOpt.TLSTricks.FragmentSize,
|
|
||||||
Sleep: configOpt.TLSTricks.FragmentSleep,
|
|
||||||
}
|
|
||||||
obj["tls_fragment"] = tlsFragment
|
|
||||||
} else {
|
|
||||||
obj["tls_fragment"] = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if tls, ok := obj["tls"].(map[string]interface{}); ok {
|
|
||||||
tlsTricks := option.TLSTricksOptions{
|
|
||||||
MixedCaseSNI: configOpt.TLSTricks.EnableMixedSNICase,
|
|
||||||
}
|
|
||||||
|
|
||||||
if configOpt.TLSTricks.EnablePadding {
|
|
||||||
tlsTricks.PaddingMode = "random"
|
|
||||||
tlsTricks.PaddingSize = configOpt.TLSTricks.PaddingSize
|
|
||||||
}
|
|
||||||
|
|
||||||
if tlsTricks.MixedCaseSNI || tlsTricks.PaddingMode != "" {
|
|
||||||
tls["tls_tricks"] = tlsTricks
|
|
||||||
} else {
|
|
||||||
tls["tls_tricks"] = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch base.Type {
|
switch base.Type {
|
||||||
case C.TypeVMess, C.TypeVLESS, C.TypeTrojan, C.TypeShadowsocks:
|
case C.TypeVMess, C.TypeVLESS, C.TypeTrojan, C.TypeShadowsocks:
|
||||||
if configOpt.EnableMux {
|
obj = patchOutboundMux(base, configOpt, obj)
|
||||||
multiplex := option.OutboundMultiplexOptions{
|
|
||||||
Enabled: true,
|
|
||||||
Padding: configOpt.MuxPadding,
|
|
||||||
MaxStreams: configOpt.MaxStreams,
|
|
||||||
Protocol: configOpt.MuxProtocol,
|
|
||||||
}
|
|
||||||
obj["multiplex"] = multiplex
|
|
||||||
} else {
|
|
||||||
delete(obj, "multiplex")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedJson, err := json.Marshal(obj)
|
modifiedJson, err := json.Marshal(obj)
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ func NewService(options option.Options) (*libbox.BoxService, error) {
|
|||||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||||
pauseManager := pause.WithDefaultManager(ctx)
|
|
||||||
// ctx = pause.ContextWithManager(ctx, pauseManager)
|
|
||||||
instance, err := B.New(B.Options{
|
instance, err := B.New(B.Options{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Options: options,
|
Options: options,
|
||||||
@@ -51,7 +49,7 @@ func NewService(options option.Options) (*libbox.BoxService, error) {
|
|||||||
ctx,
|
ctx,
|
||||||
cancel,
|
cancel,
|
||||||
instance,
|
instance,
|
||||||
pauseManager,
|
service.FromContext[pause.Manager](ctx),
|
||||||
urlTestHistoryStorage,
|
urlTestHistoryStorage,
|
||||||
)
|
)
|
||||||
return &service, nil
|
return &service, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user