Update dependencies

This commit is contained in:
世界 2024-11-07 21:46:53 +08:00
parent 4f768e630d
commit d2f1118c2e
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
30 changed files with 435 additions and 278 deletions

View File

@ -30,7 +30,7 @@ func check() error {
if err != nil { if err != nil {
return err return err
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(globalCtx)
instance, err := server.New(ctx, options) instance, err := server.New(ctx, options)
if err == nil { if err == nil {
instance.Close() instance.Close()

View File

@ -71,7 +71,7 @@ func export(profileName string) error {
} }
options.Log.DisableColor = true options.Log.DisableColor = true
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(globalCtx)
instance, err := server.New(ctx, options) instance, err := server.New(ctx, options)
if err != nil { if err != nil {
cancel() cancel()

View File

@ -38,7 +38,7 @@ func format() error {
return err return err
} }
for _, optionsEntry := range optionsList { for _, optionsEntry := range optionsList {
optionsEntry.options, err = badjson.Omitempty(optionsEntry.options) optionsEntry.options, err = badjson.Omitempty(globalCtx, optionsEntry.options)
if err != nil { if err != nil {
return err return err
} }

View File

@ -58,7 +58,7 @@ func readConfigAt(path string) (*OptionsEntry, error) {
if err != nil { if err != nil {
return nil, E.Cause(err, "read config at ", path) return nil, E.Cause(err, "read config at ", path)
} }
options, err := json.UnmarshalExtended[option.Options](configContent) options, err := json.UnmarshalExtendedContext[option.Options](globalCtx, configContent)
if err != nil { if err != nil {
return nil, E.Cause(err, "decode config at ", path) return nil, E.Cause(err, "decode config at ", path)
} }
@ -110,13 +110,13 @@ func readConfigAndMerge() (option.Options, error) {
} }
var mergedMessage json.RawMessage var mergedMessage json.RawMessage
for _, options := range optionsList { for _, options := range optionsList {
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage, false) mergedMessage, err = badjson.MergeJSON(globalCtx, options.options.RawMessage, mergedMessage, false)
if err != nil { if err != nil {
return option.Options{}, E.Cause(err, "merge config at ", options.path) return option.Options{}, E.Cause(err, "merge config at ", options.path)
} }
} }
var mergedOptions option.Options var mergedOptions option.Options
err = mergedOptions.UnmarshalJSON(mergedMessage) err = mergedOptions.UnmarshalJSONContext(globalCtx, mergedMessage)
if err != nil { if err != nil {
return option.Options{}, E.Cause(err, "unmarshal merged config") return option.Options{}, E.Cause(err, "unmarshal merged config")
} }
@ -134,7 +134,7 @@ func create() (*server.Server, context.CancelFunc, error) {
} }
options.Log.DisableColor = true options.Log.DisableColor = true
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(globalCtx)
instance, err := server.New(ctx, options) instance, err := server.New(ctx, options)
if err != nil { if err != nil {
cancel() cancel()

View File

@ -5,6 +5,8 @@ import (
"os" "os"
"time" "time"
box "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/include"
_ "github.com/sagernet/sing-box/include" _ "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
@ -16,6 +18,7 @@ var (
configDirectories []string configDirectories []string
workingDir string workingDir string
disableColor bool disableColor bool
globalCtx context.Context
) )
var mainCommand = &cobra.Command{ var mainCommand = &cobra.Command{
@ -53,4 +56,5 @@ func preRun(cmd *cobra.Command, args []string) {
if len(configPaths) == 0 && len(configDirectories) == 0 { if len(configPaths) == 0 && len(configDirectories) == 0 {
configPaths = append(configPaths, "config.json") configPaths = append(configPaths, "config.json")
} }
globalCtx = box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry())
} }

31
go.mod
View File

@ -11,9 +11,9 @@ require (
github.com/go-chi/render v1.0.3 github.com/go-chi/render v1.0.3
github.com/miekg/dns v1.1.62 github.com/miekg/dns v1.1.62
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/sing v0.5.0-beta.2 github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f
github.com/sagernet/sing-box v1.10.0-beta.12 github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f
github.com/sagernet/sing-dns v0.3.0-beta.14 github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.21.0 golang.org/x/mod v0.21.0
@ -21,7 +21,6 @@ require (
) )
require ( require (
berty.tech/go-libtor v1.0.385 // indirect
github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect github.com/andybalholm/brotli v1.0.6 // indirect
@ -35,12 +34,12 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/pool v0.2.1 // indirect
github.com/gofrs/uuid/v5 v5.2.0 // indirect github.com/gofrs/uuid/v5 v5.3.0 // indirect
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect github.com/hashicorp/yamux v0.1.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
github.com/josharian/native v1.1.0 // indirect github.com/josharian/native v1.1.0 // indirect
@ -52,10 +51,9 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d // indirect github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa // indirect
github.com/mholt/acmez v1.2.0 // indirect github.com/mholt/acmez v1.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect
github.com/ooni/go-libtor v1.1.8 // indirect
github.com/oschwald/geoip2-golang v1.9.0 // indirect github.com/oschwald/geoip2-golang v1.9.0 // indirect
github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect
@ -65,16 +63,17 @@ require (
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
github.com/sagernet/cors v1.2.1 // indirect github.com/sagernet/cors v1.2.1 // indirect
github.com/sagernet/fswatch v0.1.1 // indirect github.com/sagernet/fswatch v0.1.1 // indirect
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/quic-go v0.47.0-beta.2 // indirect github.com/sagernet/quic-go v0.48.1-beta.1 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-mux v0.2.0 // indirect github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec // indirect
github.com/sagernet/sing-quic v0.3.0-beta.3 // indirect github.com/sagernet/sing-quic v0.3.0-rc.2 // indirect
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.4.0-beta.16 // indirect github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f // indirect
github.com/sagernet/sing-vmess v0.1.12 // indirect github.com/sagernet/sing-vmess v0.1.12 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/utls v1.6.7 // indirect github.com/sagernet/utls v1.6.7 // indirect
@ -97,8 +96,8 @@ require (
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.23.0 // indirect golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/grpc v1.63.2 // indirect google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect

66
go.sum
View File

@ -1,5 +1,3 @@
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
github.com/Dreamacro/clash v1.18.0 h1:tic7ykTOCaT0mxwAkXo6QP3LN3Nps8oZz9atgr6TU8A= github.com/Dreamacro/clash v1.18.0 h1:tic7ykTOCaT0mxwAkXo6QP3LN3Nps8oZz9atgr6TU8A=
github.com/Dreamacro/clash v1.18.0/go.mod h1:r//xe/2pA3Zl+3fjIiI/o6RjIVd+z87drCD58dpRnFg= github.com/Dreamacro/clash v1.18.0/go.mod h1:r//xe/2pA3Zl+3fjIiI/o6RjIVd+z87drCD58dpRnFg=
github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k= github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k=
@ -13,7 +11,6 @@ github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NY
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -39,20 +36,20 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA=
@ -80,8 +77,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d h1:j9LtzkYstLFoNvXW824QQeN7Y26uPL5249kzWKbzO9U= github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa h1:9mcjV+RGZVC3reJBNDjjNPyS8PmFG97zq56X7WNaFO4=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa/go.mod h1:4tLB5c8U0CxpkFM+AJJB77jEaVDbLH5XQvy42vAGsWw=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
@ -92,8 +89,6 @@ github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w=
github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI=
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
@ -115,33 +110,35 @@ github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I= github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3 h1:RxEz7LhPNiF/gX/Hg+OXr5lqsM9iVAgmaK1L1vzlDRM=
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0= github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3/go.mod h1:ehZwnT2UpmOWAHFL48XdBhnd4Qu4hN2O3Ji0us3ZHMw=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU= github.com/sagernet/quic-go v0.48.1-beta.1 h1:ElPaV5yzlXIKZpqFMAcUGax6vddi3zt4AEpT94Z0vwo=
github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q= github.com/sagernet/quic-go v0.48.1-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.5.0-beta.2 h1:V12EpwtsgYo5OLGjAiGoJobDJZeUsKv0b5y+yGAM6W0= github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f h1:A6+OeV5P1mok0eEEbLh4PidymZ6VZnTZ2uHwfapXgdU=
github.com/sagernet/sing v0.5.0-beta.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.0-beta.12 h1:L8VmlfhImH3niP69BziOLmkATeiLlSELV63XumVGY74= github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f h1:CkGSNvQvZlzm5VuKmc23DiY2WxxHbp1jYux0fh3xRW4=
github.com/sagernet/sing-box v1.10.0-beta.12/go.mod h1:VkzoxRgxB87Z0F2vR00qjmezphU/GG9TtgaUYrAzdY8= github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f/go.mod h1:3Ujxk8+gNR1Kve68iZFjzxDHLGrFODdsvnth8oakrwk=
github.com/sagernet/sing-dns v0.3.0-beta.14 h1:/s+fJzYKsvLaNDt/2rjpsrDcN8wmCO2JbX6OFrl8Nww= github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab h1:djP4EY/KM5T62xscormLflVi7eDlHv6p7md1FHMSArE=
github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00= github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48=
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec/go.mod h1:RSwqqHwbtTOX3vs6ms8vMtBGH/0ZNyLm/uwt6TlmR84=
github.com/sagernet/sing-quic v0.3.0-beta.3 h1:8S98VXZxtSiOqVCFbCNbMEvKDPhOF/VNBYMjVC3xMhw= github.com/sagernet/sing-quic v0.3.0-rc.2 h1:7vcC4bdS1GBJzHZhfmJiH0CfzQ4mYLUW51Z2RNHcGwc=
github.com/sagernet/sing-quic v0.3.0-beta.3/go.mod h1:rFPUlYnSj1Bx9gFSghjCqrCzfGvpjhkisOiTKpjq5vQ= github.com/sagernet/sing-quic v0.3.0-rc.2/go.mod h1:3UOq51WVqzra7eCgod7t4hqnTaOiZzFUci9avMrtOqs=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.4.0-beta.16 h1:05VdL5BZiKLQsDNrpdXMseSO1NwPfl9Y4o76PqAd9sY= github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f h1:gQwTgN/E4oHe3VlseD3/RhPs866cWcTsPG4dP6a8f8o=
github.com/sagernet/sing-tun v0.4.0-beta.16/go.mod h1:81JwnnYw8X9W9XvmZetSTTiPgIE3SbAbnc+EHKwPJ5U= github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f/go.mod h1:Ehs5mZ3T8tTgV3H1Tx4Va5ixvyKjTAUPJ3G11dq7B/g=
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg= github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I= github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
@ -161,7 +158,6 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
@ -191,7 +187,6 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
@ -205,7 +200,6 @@ golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -225,11 +219,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=

View File

@ -1,11 +1,13 @@
package option package option
import ( import (
"context"
"time" "time"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/common/json/badoption"
) )
type _Options struct { type _Options struct {
@ -15,7 +17,7 @@ type _Options struct {
TLS *option.InboundTLSOptions `json:"tls,omitempty"` TLS *option.InboundTLSOptions `json:"tls,omitempty"`
CacheFile string `json:"cache_file,omitempty"` CacheFile string `json:"cache_file,omitempty"`
Outbounds []option.Listable[option.Outbound] `json:"outbounds,omitempty"` Outbounds []badoption.Listable[option.Outbound] `json:"outbounds,omitempty"`
Subscriptions []Subscription `json:"subscriptions,omitempty"` Subscriptions []Subscription `json:"subscriptions,omitempty"`
Templates []Template `json:"templates,omitempty"` Templates []Template `json:"templates,omitempty"`
Profiles []Profile `json:"profiles,omitempty"` Profiles []Profile `json:"profiles,omitempty"`
@ -24,8 +26,8 @@ type _Options struct {
type Options _Options type Options _Options
func (o *Options) UnmarshalJSON(content []byte) error { func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) error {
err := json.UnmarshalDisallowUnknownFields(content, (*_Options)(o)) err := json.UnmarshalContextDisallowUnknownFields(ctx, content, (*_Options)(o))
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,11 +1,14 @@
package option package option
import ( import (
"context"
C "github.com/sagernet/serenity/constant" C "github.com/sagernet/serenity/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson"
) )
type _Template struct { type _Template struct {
@ -81,8 +84,8 @@ func (t *Template) MarshalJSON() ([]byte, error) {
return json.Marshal((*_Template)(t)) return json.Marshal((*_Template)(t))
} }
func (t *Template) UnmarshalJSON(content []byte) error { func (t *Template) UnmarshalJSONContext(ctx context.Context, content []byte) error {
err := json.UnmarshalDisallowUnknownFields(content, (*_Template)(t)) err := json.UnmarshalContextDisallowUnknownFields(ctx, content, (*_Template)(t))
if err != nil { if err != nil {
return err return err
} }
@ -100,7 +103,7 @@ type RuleSet _RuleSet
func (r *RuleSet) MarshalJSON() ([]byte, error) { func (r *RuleSet) MarshalJSON() ([]byte, error) {
if r.Type == C.RuleSetTypeGitHub { if r.Type == C.RuleSetTypeGitHub {
return option.MarshallObjects((*_RuleSet)(r), r.GitHubOptions) return badjson.MarshallObjects((*_RuleSet)(r), r.GitHubOptions)
} else { } else {
return json.Marshal(r.DefaultOptions) return json.Marshal(r.DefaultOptions)
} }
@ -112,9 +115,9 @@ func (r *RuleSet) UnmarshalJSON(content []byte) error {
return err return err
} }
if r.Type == C.RuleSetTypeGitHub { if r.Type == C.RuleSetTypeGitHub {
return option.UnmarshallExcluded(content, (*_RuleSet)(r), &r.GitHubOptions) return badjson.UnmarshallExcluded(content, (*_RuleSet)(r), &r.GitHubOptions)
} else { } else {
return option.UnmarshallExcluded(content, (*_RuleSet)(r), &r.DefaultOptions) return badjson.UnmarshallExcluded(content, (*_RuleSet)(r), &r.DefaultOptions)
} }
} }

View File

@ -141,11 +141,11 @@ func (p *Profile) Render(metadata metadata.Metadata) (*boxOption.Options, error)
subscriptions := common.Filter(p.manager.subscription.Subscriptions(), func(it *subscription.Subscription) bool { subscriptions := common.Filter(p.manager.subscription.Subscriptions(), func(it *subscription.Subscription) bool {
return common.Contains(p.Subscription, it.Name) return common.Contains(p.Subscription, it.Name)
}) })
options, err := selectedTemplate.Render(metadata, p.Name, outbounds, subscriptions) options, err := selectedTemplate.Render(p.manager.ctx, metadata, p.Name, outbounds, subscriptions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
options, err = badjson.Omitempty(options) options, err = badjson.Omitempty(p.manager.ctx, options)
if err != nil { if err != nil {
return nil, E.Cause(err, "omitempty") return nil, E.Cause(err, "omitempty")
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
"github.com/sagernet/sing/service" "github.com/sagernet/sing/service"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@ -99,7 +100,7 @@ func New(ctx context.Context, options option.Options) (*Server, error) {
logFactory.NewLogger("profile"), logFactory.NewLogger("profile"),
subscriptionManager, subscriptionManager,
templateManager, templateManager,
common.Map(options.Outbounds, func(it boxOption.Listable[boxOption.Outbound]) []boxOption.Outbound { common.Map(options.Outbounds, func(it badoption.Listable[boxOption.Outbound]) []boxOption.Outbound {
return it return it
}), }),
options.Profiles, options.Profiles,

View File

@ -7,7 +7,7 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" dns "github.com/sagernet/sing-dns"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/task" "github.com/sagernet/sing/common/task"
@ -70,11 +70,7 @@ type resolveContext struct {
} }
func resolveDestination(ctx *resolveContext, server option.Outbound) netip.AddrPort { func resolveDestination(ctx *resolveContext, server option.Outbound) netip.AddrPort {
rawOptions, err := server.RawOptions() serverOptionsWrapper, loaded := server.Options.(option.ServerOptionsWrapper)
if err != nil {
return netip.AddrPort{}
}
serverOptionsWrapper, loaded := rawOptions.(option.ServerOptionsWrapper)
if !loaded { if !loaded {
return netip.AddrPort{} return netip.AddrPort{}
} }
@ -83,7 +79,9 @@ func resolveDestination(ctx *resolveContext, server option.Outbound) netip.AddrP
return serverOptions.AddrPort() return serverOptions.AddrPort()
} }
if serverOptions.IsFqdn() { if serverOptions.IsFqdn() {
addresses, lookupErr := ctx.dnsClient.Lookup(ctx.ctx, ctx.dnsTransport, serverOptions.Fqdn, dns.DomainStrategyPreferIPv4) addresses, lookupErr := ctx.dnsClient.Lookup(ctx.ctx, ctx.dnsTransport, serverOptions.Fqdn, dns.QueryOptions{
Strategy: dns.DomainStrategyPreferIPv4,
})
if lookupErr == nil && len(addresses) > 0 { if lookupErr == nil && len(addresses) > 0 {
return netip.AddrPortFrom(addresses[0], serverOptions.Port) return netip.AddrPortFrom(addresses[0], serverOptions.Port)
} }

View File

@ -1,6 +1,7 @@
package parser package parser
import ( import (
"context"
"strings" "strings"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@ -16,7 +17,7 @@ import (
"github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant"
) )
func ParseClashSubscription(content string) ([]option.Outbound, error) { func ParseClashSubscription(_ context.Context, content string) ([]option.Outbound, error) {
config, err := config.UnmarshalRawConfig([]byte(content)) config, err := config.UnmarshalRawConfig([]byte(content))
if err != nil { if err != nil {
return nil, E.Cause(err, "parse clash config") return nil, E.Cause(err, "parse clash config")
@ -38,7 +39,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
return nil, err return nil, err
} }
outbound.Type = C.TypeShadowsocks outbound.Type = C.TypeShadowsocks
outbound.ShadowsocksOptions = option.ShadowsocksOutboundOptions{ outbound.Options = &option.ShadowsocksOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: ssOption.Server, Server: ssOption.Server,
ServerPort: uint16(ssOption.Port), ServerPort: uint16(ssOption.Port),
@ -56,7 +57,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
return nil, err return nil, err
} }
outbound.Type = C.TypeShadowsocksR outbound.Type = C.TypeShadowsocksR
outbound.ShadowsocksROptions = option.ShadowsocksROutboundOptions{ outbound.Options = &option.ShadowsocksROutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: ssrOption.Server, Server: ssrOption.Server,
ServerPort: uint16(ssrOption.Port), ServerPort: uint16(ssrOption.Port),
@ -76,7 +77,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
return nil, err return nil, err
} }
outbound.Type = C.TypeTrojan outbound.Type = C.TypeTrojan
outbound.TrojanOptions = option.TrojanOutboundOptions{ outbound.Options = &option.TrojanOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: trojanOption.Server, Server: trojanOption.Server,
ServerPort: uint16(trojanOption.Port), ServerPort: uint16(trojanOption.Port),
@ -100,7 +101,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
return nil, err return nil, err
} }
outbound.Type = C.TypeVMess outbound.Type = C.TypeVMess
outbound.VMessOptions = option.VMessOutboundOptions{ outbound.Options = &option.VMessOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: vmessOption.Server, Server: vmessOption.Server,
ServerPort: uint16(vmessOption.Port), ServerPort: uint16(vmessOption.Port),
@ -131,7 +132,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
} }
outbound.Type = C.TypeSOCKS outbound.Type = C.TypeSOCKS
outbound.SocksOptions = option.SocksOutboundOptions{ outbound.Options = &option.SOCKSOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: socks5Option.Server, Server: socks5Option.Server,
ServerPort: uint16(socks5Option.Port), ServerPort: uint16(socks5Option.Port),
@ -152,7 +153,7 @@ func ParseClashSubscription(content string) ([]option.Outbound, error) {
} }
outbound.Type = C.TypeHTTP outbound.Type = C.TypeHTTP
outbound.HTTPOptions = option.HTTPOutboundOptions{ outbound.Options = &option.HTTPOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: httpOption.Server, Server: httpOption.Server,
ServerPort: uint16(httpOption.Port), ServerPort: uint16(httpOption.Port),

View File

@ -43,7 +43,7 @@ func ParseShadowsocksLink(link string) (option.Outbound, error) {
var outbound option.Outbound var outbound option.Outbound
outbound.Type = C.TypeShadowsocks outbound.Type = C.TypeShadowsocks
outbound.Tag = linkURL.Fragment outbound.Tag = linkURL.Fragment
outbound.ShadowsocksOptions = options outbound.Options = &options
return outbound, nil return outbound, nil
} }

View File

@ -1,21 +1,23 @@
package parser package parser
import ( import (
"context"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
) )
var subscriptionParsers = []func(string) ([]option.Outbound, error){ var subscriptionParsers = []func(ctx context.Context, content string) ([]option.Outbound, error){
ParseBoxSubscription, ParseBoxSubscription,
ParseClashSubscription, ParseClashSubscription,
ParseSIP008Subscription, ParseSIP008Subscription,
ParseRawSubscription, ParseRawSubscription,
} }
func ParseSubscription(content string) ([]option.Outbound, error) { func ParseSubscription(ctx context.Context, content string) ([]option.Outbound, error) {
var pErr error var pErr error
for _, parser := range subscriptionParsers { for _, parser := range subscriptionParsers {
servers, err := parser(content) servers, err := parser(ctx, content)
if len(servers) > 0 { if len(servers) > 0 {
return servers, nil return servers, nil
} }

View File

@ -1,6 +1,7 @@
package parser package parser
import ( import (
"context"
"encoding/base64" "encoding/base64"
"strings" "strings"
@ -8,7 +9,7 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
) )
func ParseRawSubscription(content string) ([]option.Outbound, error) { func ParseRawSubscription(_ context.Context, content string) ([]option.Outbound, error) {
if base64Content, err := decodeBase64URLSafe(content); err == nil { if base64Content, err := decodeBase64URLSafe(content); err == nil {
servers, _ := parseRawSubscription(base64Content) servers, _ := parseRawSubscription(base64Content)
if len(servers) > 0 { if len(servers) > 0 {

View File

@ -1,6 +1,8 @@
package parser package parser
import ( import (
"context"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@ -8,8 +10,8 @@ import (
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
) )
func ParseBoxSubscription(content string) ([]option.Outbound, error) { func ParseBoxSubscription(ctx context.Context, content string) ([]option.Outbound, error) {
options, err := json.UnmarshalExtended[option.Options]([]byte(content)) options, err := json.UnmarshalExtendedContext[option.Options](ctx, []byte(content))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,6 +1,8 @@
package parser package parser
import ( import (
"context"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@ -23,7 +25,7 @@ type ShadowsocksServerDocument struct {
PluginOpts string `json:"plugin_opts"` PluginOpts string `json:"plugin_opts"`
} }
func ParseSIP008Subscription(content string) ([]option.Outbound, error) { func ParseSIP008Subscription(_ context.Context, content string) ([]option.Outbound, error) {
var document ShadowsocksDocument var document ShadowsocksDocument
err := json.Unmarshal([]byte(content), &document) err := json.Unmarshal([]byte(content), &document)
if err != nil { if err != nil {
@ -35,7 +37,7 @@ func ParseSIP008Subscription(content string) ([]option.Outbound, error) {
servers = append(servers, option.Outbound{ servers = append(servers, option.Outbound{
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
Tag: server.Remarks, Tag: server.Remarks,
ShadowsocksOptions: option.ShadowsocksOutboundOptions{ Options: &option.ShadowsocksOutboundOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
Server: server.Server, Server: server.Server,
ServerPort: uint16(server.ServerPort), ServerPort: uint16(server.ServerPort),

View File

@ -5,7 +5,6 @@ import (
"strings" "strings"
"github.com/sagernet/serenity/option" "github.com/sagernet/serenity/option"
C "github.com/sagernet/sing-box/constant"
boxOption "github.com/sagernet/sing-box/option" boxOption "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@ -120,26 +119,22 @@ func (o *ProcessOptions) Process(outbounds []boxOption.Outbound) []boxOption.Out
renameResult[originTag] = outbound.Tag renameResult[originTag] = outbound.Tag
} }
if o.RewriteMultiplex != nil { if o.RewriteMultiplex != nil {
switch outbound.Type { switch outboundOptions := outbound.Options.(type) {
case C.TypeShadowsocks: case *boxOption.ShadowsocksOutboundOptions:
outbound.ShadowsocksOptions.Multiplex = o.RewriteMultiplex outboundOptions.Multiplex = o.RewriteMultiplex
case C.TypeTrojan: case *boxOption.TrojanOutboundOptions:
outbound.TrojanOptions.Multiplex = o.RewriteMultiplex outboundOptions.Multiplex = o.RewriteMultiplex
case C.TypeVMess: case *boxOption.VMessOutboundOptions:
outbound.VMessOptions.Multiplex = o.RewriteMultiplex outboundOptions.Multiplex = o.RewriteMultiplex
case C.TypeVLESS: case *boxOption.VLESSOutboundOptions:
outbound.VLESSOptions.Multiplex = o.RewriteMultiplex outboundOptions.Multiplex = o.RewriteMultiplex
} }
} }
newOutbounds = append(newOutbounds, outbound) newOutbounds = append(newOutbounds, outbound)
} }
if len(renameResult) > 0 { if len(renameResult) > 0 {
for i, outbound := range newOutbounds { for i, outbound := range newOutbounds {
rawOptions, err := outbound.RawOptions() if dialerOptionsWrapper, containsDialerOptions := outbound.Options.(boxOption.DialerOptionsWrapper); containsDialerOptions {
if err != nil {
continue
}
if dialerOptionsWrapper, containsDialerOptions := rawOptions.(boxOption.DialerOptionsWrapper); containsDialerOptions {
dialerOptions := dialerOptionsWrapper.TakeDialerOptions() dialerOptions := dialerOptionsWrapper.TakeDialerOptions()
if dialerOptions.Detour == "" { if dialerOptions.Detour == "" {
continue continue

View File

@ -187,7 +187,7 @@ func (m *Manager) update(subscription *Subscription) error {
response.Body.Close() response.Body.Close()
return err return err
} }
rawServers, err := parser.ParseSubscription(string(content)) rawServers, err := parser.ParseSubscription(m.ctx, string(content))
if err != nil { if err != nil {
response.Body.Close() response.Body.Close()
return err return err

View File

@ -1,6 +1,7 @@
package filter package filter
import ( import (
"context"
"net/netip" "net/netip"
"github.com/sagernet/serenity/common/metadata" "github.com/sagernet/serenity/common/metadata"
@ -77,41 +78,42 @@ func filter1100(metadata metadata.Metadata, options *option.Options) error {
newInbounds := make([]option.Inbound, 0, len(options.Inbounds)) newInbounds := make([]option.Inbound, 0, len(options.Inbounds))
for _, inbound := range options.Inbounds { for _, inbound := range options.Inbounds {
if inbound.Type == C.TypeTun { if inbound.Type == C.TypeTun {
inbound.TunOptions.AutoRedirect = false tunOptions := inbound.Options.(*option.TunInboundOptions)
inbound.TunOptions.RouteAddressSet = nil tunOptions.AutoRedirect = false
inbound.TunOptions.RouteExcludeAddressSet = nil tunOptions.RouteAddressSet = nil
tunOptions.RouteExcludeAddressSet = nil
//nolint:staticcheck //nolint:staticcheck
//goland:noinspection GoDeprecation //goland:noinspection GoDeprecation
if len(inbound.TunOptions.Address) > 0 { if len(tunOptions.Address) > 0 {
inbound.TunOptions.Inet4Address = append(inbound.TunOptions.Inet4Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool { tunOptions.Inet4Address = append(tunOptions.Inet4Address, common.Filter(tunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is4() return it.Addr().Is4()
})...) })...)
inbound.TunOptions.Inet6Address = append(inbound.TunOptions.Inet6Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool { tunOptions.Inet6Address = append(tunOptions.Inet6Address, common.Filter(tunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is6() return it.Addr().Is6()
})...) })...)
inbound.TunOptions.Address = nil tunOptions.Address = nil
} }
//nolint:staticcheck //nolint:staticcheck
//goland:noinspection GoDeprecation //goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteAddress) > 0 { if len(tunOptions.RouteAddress) > 0 {
inbound.TunOptions.Inet4RouteAddress = append(inbound.TunOptions.Inet4RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool { tunOptions.Inet4RouteAddress = append(tunOptions.Inet4RouteAddress, common.Filter(tunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is4() return it.Addr().Is4()
})...) })...)
inbound.TunOptions.Inet6RouteAddress = append(inbound.TunOptions.Inet6RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool { tunOptions.Inet6RouteAddress = append(tunOptions.Inet6RouteAddress, common.Filter(tunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is6() return it.Addr().Is6()
})...) })...)
inbound.TunOptions.RouteAddress = nil tunOptions.RouteAddress = nil
} }
//nolint:staticcheck //nolint:staticcheck
//goland:noinspection GoDeprecation //goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteExcludeAddress) > 0 { if len(tunOptions.RouteExcludeAddress) > 0 {
inbound.TunOptions.Inet4RouteExcludeAddress = append(inbound.TunOptions.Inet4RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool { tunOptions.Inet4RouteExcludeAddress = append(tunOptions.Inet4RouteExcludeAddress, common.Filter(tunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is4() return it.Addr().Is4()
})...) })...)
inbound.TunOptions.Inet6RouteExcludeAddress = append(inbound.TunOptions.Inet6RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool { tunOptions.Inet6RouteExcludeAddress = append(tunOptions.Inet6RouteExcludeAddress, common.Filter(tunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is6() return it.Addr().Is6()
})...) })...)
inbound.TunOptions.RouteExcludeAddress = nil tunOptions.RouteExcludeAddress = nil
} }
} }
newInbounds = append(newInbounds, inbound) newInbounds = append(newInbounds, inbound)
@ -152,7 +154,7 @@ func expandInlineRule(ruleSet option.RuleSet, rule option.Rule) ([]option.Rule,
if err != nil { if err != nil {
return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]") return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]")
} }
newRule, err = badjson.MergeFromSource(rawRule, rule, false) newRule, err = badjson.MergeFromSource(context.Background(), rawRule, rule, false)
if err != nil { if err != nil {
return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]") return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]")
} }
@ -192,7 +194,7 @@ func expandInlineDNSRule(ruleSet option.RuleSet, rule option.DNSRule) ([]option.
if err != nil { if err != nil {
return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]") return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]")
} }
newRule, err = badjson.MergeFromSource(rawRule, rule, false) newRule, err = badjson.MergeFromSource(context.Background(), rawRule, rule, false)
if err != nil { if err != nil {
return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]") return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]")
} }

View File

@ -3,7 +3,6 @@ package filter
import ( import (
"github.com/sagernet/serenity/common/metadata" "github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver" "github.com/sagernet/serenity/common/semver"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
) )
@ -24,12 +23,12 @@ func filter190(metadata metadata.Metadata, options *option.Options) error {
return nil return nil
} }
for _, inbound := range options.Inbounds { for _, inbound := range options.Inbounds {
switch inbound.Type { switch inboundOptions := inbound.Options.(type) {
case C.TypeTun: case *option.TunInboundOptions:
if inbound.TunOptions.Platform == nil || inbound.TunOptions.Platform.HTTPProxy == nil { if inboundOptions.Platform == nil || inboundOptions.Platform.HTTPProxy == nil {
continue continue
} }
httpProxy := inbound.TunOptions.Platform.HTTPProxy httpProxy := inboundOptions.Platform.HTTPProxy
if len(httpProxy.BypassDomain) > 0 || len(httpProxy.MatchDomain) > 0 { if len(httpProxy.BypassDomain) > 0 || len(httpProxy.MatchDomain) > 0 {
httpProxy.BypassDomain = nil httpProxy.BypassDomain = nil
httpProxy.MatchDomain = nil httpProxy.MatchDomain = nil

View File

@ -15,27 +15,32 @@ func filterNullGroupReference(metadata M.Metadata, options *option.Options) erro
outboundTags := common.Map(options.Outbounds, func(it option.Outbound) string { outboundTags := common.Map(options.Outbounds, func(it option.Outbound) string {
return it.Tag return it.Tag
}) })
for i, outbound := range options.Outbounds { for _, outbound := range options.Outbounds {
switch outbound.Type { switch outboundOptions := outbound.Options.(type) {
case C.TypeSelector: case *option.SelectorOutboundOptions:
outbound.SelectorOptions.Outbounds = common.Filter(outbound.SelectorOptions.Outbounds, func(outbound string) bool { outboundOptions.Outbounds = common.Filter(outboundOptions.Outbounds, func(outbound string) bool {
return common.Contains(outboundTags, outbound) return common.Contains(outboundTags, outbound)
}) })
case C.TypeURLTest: case *option.URLTestOutboundOptions:
outbound.URLTestOptions.Outbounds = common.Filter(outbound.URLTestOptions.Outbounds, func(outbound string) bool { outboundOptions.Outbounds = common.Filter(outboundOptions.Outbounds, func(outbound string) bool {
return common.Contains(outboundTags, outbound) return common.Contains(outboundTags, outbound)
}) })
default: default:
continue continue
} }
options.Outbounds[i] = outbound
} }
options.Route.Rules = common.Filter(options.Route.Rules, func(it option.Rule) bool { options.Route.Rules = common.Filter(options.Route.Rules, func(it option.Rule) bool {
switch it.Type { switch it.Type {
case C.RuleTypeDefault: case C.RuleTypeDefault:
return common.Contains(outboundTags, it.DefaultOptions.Outbound) if it.DefaultOptions.Action != C.RuleActionTypeRoute {
return true
}
return common.Contains(outboundTags, it.DefaultOptions.RouteOptions.Outbound)
case C.RuleTypeLogical: case C.RuleTypeLogical:
return common.Contains(outboundTags, it.LogicalOptions.Outbound) if it.LogicalOptions.Action != C.RuleActionTypeRoute {
return true
}
return common.Contains(outboundTags, it.LogicalOptions.RouteOptions.Outbound)
default: default:
panic("no") panic("no")
} }

View File

@ -18,7 +18,7 @@ type Manager struct {
templates []*Template templates []*Template
} }
func extendTemplate(rawTemplates []option.Template, root, current option.Template) (option.Template, error) { func extendTemplate(ctx context.Context, rawTemplates []option.Template, root, current option.Template) (option.Template, error) {
if current.Extend == "" { if current.Extend == "" {
return current, nil return current, nil
} else if root.Name == current.Extend { } else if root.Name == current.Extend {
@ -35,13 +35,13 @@ func extendTemplate(rawTemplates []option.Template, root, current option.Templat
return option.Template{}, E.New("initialize template[", current.Name, "]: extended template not found: ", current.Extend) return option.Template{}, E.New("initialize template[", current.Name, "]: extended template not found: ", current.Extend)
} }
if next.Extend != "" { if next.Extend != "" {
newNext, err := extendTemplate(rawTemplates, root, next) newNext, err := extendTemplate(ctx, rawTemplates, root, next)
if err != nil { if err != nil {
return option.Template{}, E.Cause(err, next.Extend) return option.Template{}, E.Cause(err, next.Extend)
} }
next = newNext next = newNext
} }
newRawTemplate, err := badjson.MergeJSON(next.RawMessage, current.RawMessage, false) newRawTemplate, err := badjson.MergeJSON(ctx, next.RawMessage, current.RawMessage, false)
if err != nil { if err != nil {
return option.Template{}, E.Cause(err, "initialize template[", current.Name, "]: merge extended template: ", current.Extend) return option.Template{}, E.Cause(err, "initialize template[", current.Name, "]: merge extended template: ", current.Extend)
} }
@ -60,7 +60,7 @@ func NewManager(ctx context.Context, logger logger.Logger, rawTemplates []option
return nil, E.New("initialize template[", templateIndex, "]: missing name") return nil, E.New("initialize template[", templateIndex, "]: missing name")
} }
if template.Extend != "" { if template.Extend != "" {
newTemplate, err := extendTemplate(rawTemplates, template, template) newTemplate, err := extendTemplate(ctx, rawTemplates, template, template)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -110,10 +110,17 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Outbound: []string{"any"}, Outbound: []string{"any"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
}, },
}, },
},
},
} }
clashModeRule := t.ClashModeRule clashModeRule := t.ClashModeRule
if clashModeRule == "" { if clashModeRule == "" {
@ -132,15 +139,29 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
ClashMode: clashModeGlobal, ClashMode: clashModeGlobal,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSDefaultTag, Server: DNSDefaultTag,
}, },
},
},
}, option.DNSRule{ }, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
ClashMode: clashModeDirect, ClashMode: clashModeDirect,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
}, },
},
},
}) })
} }
options.DNS.Rules = append(options.DNS.Rules, t.PreDNSRules...) options.DNS.Rules = append(options.DNS.Rules, t.PreDNSRules...)
@ -150,47 +171,90 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Geosite: []string{"geolocation-cn"}, Geosite: []string{"geolocation-cn"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
}, },
},
},
}) })
} else { } else {
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geosite-geolocation-cn"}, RuleSet: []string{"geosite-geolocation-cn"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
}, },
},
},
}) })
} }
if !t.DisableDNSLeak && (metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) { if !t.DisableDNSLeak && (metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) {
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
ClashMode: clashModeRule, ClashMode: clashModeRule,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSDefaultTag, Server: DNSDefaultTag,
}, },
},
},
}, option.DNSRule{ }, option.DNSRule{
Type: C.RuleTypeLogical, Type: C.RuleTypeLogical,
LogicalOptions: option.LogicalDNSRule{ LogicalOptions: option.LogicalDNSRule{
RawLogicalDNSRule: option.RawLogicalDNSRule{
Mode: C.LogicalTypeAnd, Mode: C.LogicalTypeAnd,
Rules: []option.DNSRule{ Rules: []option.DNSRule{
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geosite-geolocation-!cn"}, RuleSet: []string{"geosite-geolocation-!cn"},
Invert: true, },
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSDefaultTag,
},
},
}, },
}, },
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geoip-cn"}, RuleSet: []string{"geoip-cn"},
}, },
}, DNSRuleAction: option.DNSRuleAction{
}, Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
}, },
},
},
},
},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag,
},
},
},
}) })
} }
} }
@ -201,12 +265,19 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
QueryType: []option.DNSQueryType{ QueryType: []option.DNSQueryType{
option.DNSQueryType(mDNS.TypeA), option.DNSQueryType(mDNS.TypeA),
option.DNSQueryType(mDNS.TypeAAAA), option.DNSQueryType(mDNS.TypeAAAA),
}, },
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSFakeIPTag, Server: DNSFakeIPTag,
}, },
},
},
}) })
} }
return nil return nil

View File

@ -1,6 +1,8 @@
package template package template
import ( import (
"context"
M "github.com/sagernet/serenity/common/metadata" M "github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver" "github.com/sagernet/serenity/common/semver"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
@ -8,7 +10,7 @@ import (
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
) )
func (t *Template) renderExperimental(metadata M.Metadata, options *option.Options, profileName string) error { func (t *Template) renderExperimental(ctx context.Context, metadata M.Metadata, options *option.Options, profileName string) error {
if t.DisableCacheFile && t.DisableClashMode && t.CustomClashAPI == nil { if t.DisableCacheFile && t.DisableClashMode && t.CustomClashAPI == nil {
return nil return nil
} }
@ -37,7 +39,7 @@ func (t *Template) renderExperimental(metadata M.Metadata, options *option.Optio
} }
if t.CustomClashAPI != nil { if t.CustomClashAPI != nil {
newClashOptions, err := badjson.MergeFromDestination(options.Experimental.ClashAPI, t.CustomClashAPI.Message, true) newClashOptions, err := badjson.MergeFromDestination(ctx, options.Experimental.ClashAPI, t.CustomClashAPI.Message, true)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package template package template
import ( import (
"context"
"net/netip" "net/netip"
M "github.com/sagernet/serenity/common/metadata" M "github.com/sagernet/serenity/common/metadata"
@ -36,27 +37,28 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
if !t.DisableIPv6() { if !t.DisableIPv6() {
address = append(address, netip.MustParsePrefix("fdfe:dcba:9876::1/126")) address = append(address, netip.MustParsePrefix("fdfe:dcba:9876::1/126"))
} }
tunInbound := option.Inbound{ tunOptions := &option.TunInboundOptions{
Type: C.TypeTun,
TunOptions: option.TunInboundOptions{
AutoRoute: true, AutoRoute: true,
Address: address, Address: address,
InboundOptions: option.InboundOptions{ InboundOptions: option.InboundOptions{
SniffEnabled: needSniff, SniffEnabled: needSniff,
}, },
}, }
tunInbound := option.Inbound{
Type: C.TypeTun,
Options: tunOptions,
} }
if autoRedirect { if autoRedirect {
tunInbound.TunOptions.AutoRedirect = true tunOptions.AutoRedirect = true
if !t.DisableTrafficBypass && metadata.Platform == "" { if !t.DisableTrafficBypass && metadata.Platform == "" {
tunInbound.TunOptions.RouteExcludeAddressSet = []string{"geoip-cn"} tunOptions.RouteExcludeAddressSet = []string{"geoip-cn"}
} }
} }
if t.EnableFakeIP { if t.EnableFakeIP {
tunInbound.TunOptions.InboundOptions.DomainStrategy = domainStrategy tunOptions.DomainStrategy = domainStrategy
} }
if metadata.Platform == M.PlatformUnknown { if metadata.Platform == M.PlatformUnknown {
tunInbound.TunOptions.StrictRoute = true tunOptions.StrictRoute = true
} }
if !t.DisableSystemProxy && metadata.Platform != M.PlatformUnknown { if !t.DisableSystemProxy && metadata.Platform != M.PlatformUnknown {
var httpPort uint16 var httpPort uint16
@ -66,7 +68,7 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
if httpPort == 0 { if httpPort == 0 {
httpPort = DefaultMixedPort httpPort = DefaultMixedPort
} }
tunInbound.TunOptions.Platform = &option.TunPlatformOptions{ tunOptions.Platform = &option.TunPlatformOptions{
HTTPProxy: &option.HTTPProxyOptions{ HTTPProxy: &option.HTTPProxyOptions{
Enabled: true, Enabled: true,
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
@ -77,18 +79,16 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
} }
} }
if t.CustomTUN != nil { if t.CustomTUN != nil {
newTUNOptions, err := badjson.MergeFromDestination(tunInbound.TunOptions, t.CustomTUN.Message, true) newTUNOptions, err := badjson.MergeFromDestination(context.Background(), tunOptions, t.CustomTUN.Message, true)
if err != nil { if err != nil {
return E.Cause(err, "merge custom tun options") return E.Cause(err, "merge custom tun options")
} }
tunInbound.TunOptions = newTUNOptions tunInbound.Options = newTUNOptions
} }
options.Inbounds = append(options.Inbounds, tunInbound) options.Inbounds = append(options.Inbounds, tunInbound)
} }
if disableTun || !t.DisableSystemProxy { if disableTun || !t.DisableSystemProxy {
mixedInbound := option.Inbound{ mixedOptions := &option.HTTPMixedInboundOptions{
Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.AddrFrom4([4]byte{127, 0, 0, 1})), Listen: option.NewListenAddress(netip.AddrFrom4([4]byte{127, 0, 0, 1})),
ListenPort: DefaultMixedPort, ListenPort: DefaultMixedPort,
@ -98,14 +98,17 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
}, },
}, },
SetSystemProxy: metadata.Platform == M.PlatformUnknown && disableTun && !t.DisableSystemProxy, SetSystemProxy: metadata.Platform == M.PlatformUnknown && disableTun && !t.DisableSystemProxy,
}, }
mixedInbound := option.Inbound{
Type: C.TypeMixed,
Options: mixedOptions,
} }
if t.CustomMixed != nil { if t.CustomMixed != nil {
newMixedOptions, err := badjson.MergeFromDestination(mixedInbound.MixedOptions, t.CustomMixed.Message, true) newMixedOptions, err := badjson.MergeFromDestination(context.Background(), mixedOptions, t.CustomMixed.Message, true)
if err != nil { if err != nil {
return E.Cause(err, "merge custom mixed options") return E.Cause(err, "merge custom mixed options")
} }
mixedInbound.MixedOptions = newMixedOptions mixedInbound.Options = newMixedOptions
} }
options.Inbounds = append(options.Inbounds, mixedInbound) options.Inbounds = append(options.Inbounds, mixedInbound)
} }

View File

@ -33,20 +33,22 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
{ {
Tag: directTag, Tag: directTag,
Type: C.TypeDirect, Type: C.TypeDirect,
DirectOptions: common.PtrValueOrDefault(t.CustomDirect), Options: common.Ptr(common.PtrValueOrDefault(t.CustomDirect)),
}, },
{ {
Tag: blockTag, Tag: blockTag,
Type: C.TypeBlock, Type: C.TypeBlock,
Options: &boxOption.StubOptions{},
}, },
{ {
Tag: DNSTag, Tag: DNSTag,
Type: C.TypeDNS, Type: C.TypeDNS,
Options: &boxOption.StubOptions{},
}, },
{ {
Tag: defaultTag, Tag: defaultTag,
Type: C.TypeSelector, Type: C.TypeSelector,
SelectorOptions: common.PtrValueOrDefault(t.CustomSelector), Options: common.Ptr(common.PtrValueOrDefault(t.CustomSelector)),
}, },
} }
urlTestTag := t.URLTestTag urlTestTag := t.URLTestTag
@ -80,12 +82,13 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
return it.Tag return it.Tag
}) })
if it.GenerateSelector { if it.GenerateSelector {
selectorOptions := common.PtrValueOrDefault(it.CustomSelector)
selectorOutbound := boxOption.Outbound{ selectorOutbound := boxOption.Outbound{
Type: C.TypeSelector, Type: C.TypeSelector,
Tag: it.Name, Tag: it.Name,
SelectorOptions: common.PtrValueOrDefault(it.CustomSelector), Options: &selectorOptions,
} }
selectorOutbound.SelectorOptions.Outbounds = append(selectorOutbound.SelectorOptions.Outbounds, joinOutbounds...) selectorOptions.Outbounds = append(selectorOptions.Outbounds, joinOutbounds...)
allGroups = append(allGroups, selectorOutbound) allGroups = append(allGroups, selectorOutbound)
groupTags = append(groupTags, selectorOutbound.Tag) groupTags = append(groupTags, selectorOutbound.Tag)
} }
@ -98,12 +101,13 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
} else { } else {
urltestTag = it.Name + " - URLTest" urltestTag = it.Name + " - URLTest"
} }
urltestOptions := common.PtrValueOrDefault(t.CustomURLTest)
urltestOutbound := boxOption.Outbound{ urltestOutbound := boxOption.Outbound{
Type: C.TypeURLTest, Type: C.TypeURLTest,
Tag: urltestTag, Tag: urltestTag,
URLTestOptions: common.PtrValueOrDefault(t.CustomURLTest), Options: &urltestOptions,
} }
urltestOutbound.URLTestOptions.Outbounds = append(urltestOutbound.URLTestOptions.Outbounds, joinOutbounds...) urltestOptions.Outbounds = append(urltestOptions.Outbounds, joinOutbounds...)
allGroups = append(allGroups, urltestOutbound) allGroups = append(allGroups, urltestOutbound)
groupTags = append(groupTags, urltestOutbound.Tag) groupTags = append(groupTags, urltestOutbound.Tag)
} }
@ -146,14 +150,16 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
groupOutbound := boxOption.Outbound{ groupOutbound := boxOption.Outbound{
Tag: extraGroup.Tag, Tag: extraGroup.Tag,
Type: extraGroup.Type, Type: extraGroup.Type,
SelectorOptions: common.PtrValueOrDefault(extraGroup.CustomSelector),
URLTestOptions: common.PtrValueOrDefault(extraGroup.CustomURLTest),
} }
switch extraGroup.Type { switch extraGroup.Type {
case C.TypeSelector: case C.TypeSelector:
groupOutbound.SelectorOptions.Outbounds = append(groupOutbound.SelectorOptions.Outbounds, extraTags...) selectorOptions := common.PtrValueOrDefault(extraGroup.CustomSelector)
groupOutbound.Options = &selectorOptions
selectorOptions.Outbounds = append(selectorOptions.Outbounds, extraTags...)
case C.TypeURLTest: case C.TypeURLTest:
groupOutbound.URLTestOptions.Outbounds = append(groupOutbound.URLTestOptions.Outbounds, extraTags...) urltestOptions := common.PtrValueOrDefault(extraGroup.CustomURLTest)
groupOutbound.Options = &urltestOptions
urltestOptions.Outbounds = append(urltestOptions.Outbounds, extraTags...)
} }
if extraGroup.Target == option.ExtraGroupTargetDefault { if extraGroup.Target == option.ExtraGroupTargetDefault {
defaultGroups = append(defaultGroups, groupOutbound) defaultGroups = append(defaultGroups, groupOutbound)
@ -193,14 +199,16 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
groupOutboundPerSubscription := boxOption.Outbound{ groupOutboundPerSubscription := boxOption.Outbound{
Tag: tagPerSubscription, Tag: tagPerSubscription,
Type: extraGroup.Type, Type: extraGroup.Type,
SelectorOptions: common.PtrValueOrDefault(extraGroup.CustomSelector),
URLTestOptions: common.PtrValueOrDefault(extraGroup.CustomURLTest),
} }
switch extraGroup.Type { switch extraGroup.Type {
case C.TypeSelector: case C.TypeSelector:
groupOutboundPerSubscription.SelectorOptions.Outbounds = append(groupOutboundPerSubscription.SelectorOptions.Outbounds, subscriptionTags...) selectorOptions := common.PtrValueOrDefault(extraGroup.CustomSelector)
groupOutboundPerSubscription.Options = &selectorOptions
selectorOptions.Outbounds = append(selectorOptions.Outbounds, subscriptionTags...)
case C.TypeURLTest: case C.TypeURLTest:
groupOutboundPerSubscription.URLTestOptions.Outbounds = append(groupOutboundPerSubscription.URLTestOptions.Outbounds, subscriptionTags...) urltestOptions := common.PtrValueOrDefault(extraGroup.CustomURLTest)
groupOutboundPerSubscription.Options = &urltestOptions
urltestOptions.Outbounds = append(urltestOptions.Outbounds, subscriptionTags...)
} }
subscriptionGroups[it.Name] = append(subscriptionGroups[it.Name], groupOutboundPerSubscription) subscriptionGroups[it.Name] = append(subscriptionGroups[it.Name], groupOutboundPerSubscription)
} }
@ -238,11 +246,11 @@ func groupJoin(outbounds []boxOption.Outbound, groupTag string, appendFront bool
} }
groupOutbound := outbounds[groupIndex] groupOutbound := outbounds[groupIndex]
var outboundPtr *[]string var outboundPtr *[]string
switch groupOutbound.Type { switch outboundOptions := groupOutbound.Options.(type) {
case C.TypeSelector: case *boxOption.SelectorOutboundOptions:
outboundPtr = &groupOutbound.SelectorOptions.Outbounds outboundPtr = &outboundOptions.Outbounds
case C.TypeURLTest: case *boxOption.URLTestOutboundOptions:
outboundPtr = &groupOutbound.URLTestOptions.Outbounds outboundPtr = &outboundOptions.Outbounds
default: default:
panic(F.ToString("unexpected group type: ", groupOutbound.Type)) panic(F.ToString("unexpected group type: ", groupOutbound.Type))
} }

View File

@ -24,25 +24,36 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
{ {
Type: C.RuleTypeLogical, Type: C.RuleTypeLogical,
LogicalOptions: option.LogicalRule{ LogicalOptions: option.LogicalRule{
RawLogicalRule: option.RawLogicalRule{
Mode: C.LogicalTypeOr, Mode: C.LogicalTypeOr,
Rules: []option.Rule{ Rules: []option.Rule{
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
Network: []string{N.NetworkUDP}, Network: []string{N.NetworkUDP},
Port: []uint16{53}, Port: []uint16{53},
}, },
}, },
},
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
Protocol: []string{C.ProtocolDNS}, Protocol: []string{C.ProtocolDNS},
}, },
}, },
}, },
},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: DNSTag, Outbound: DNSTag,
}, },
}, },
},
},
} }
directTag := t.DirectTag directTag := t.DirectTag
defaultTag := t.DefaultTag defaultTag := t.DefaultTag
@ -56,17 +67,31 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
GeoIP: []string{"private"}, GeoIP: []string{"private"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag, Outbound: directTag,
}, },
},
},
}) })
} else { } else {
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
IPIsPrivate: true, IPIsPrivate: true,
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag, Outbound: directTag,
}, },
},
},
}) })
} }
if !t.DisableClashMode { if !t.DisableClashMode {
@ -81,15 +106,29 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
ClashMode: modeGlobal, ClashMode: modeGlobal,
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: defaultTag, Outbound: defaultTag,
}, },
},
},
}, option.Rule{ }, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
ClashMode: modeDirect, ClashMode: modeDirect,
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag, Outbound: directTag,
}, },
},
},
}) })
} }
options.Route.Rules = append(options.Route.Rules, t.PreRules...) options.Route.Rules = append(options.Route.Rules, t.PreRules...)
@ -99,18 +138,32 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
GeoIP: []string{"cn"}, GeoIP: []string{"cn"},
Geosite: []string{"geolocation-cn"}, Geosite: []string{"geolocation-cn"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag, Outbound: directTag,
}, },
},
},
}) })
} else { } else {
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
RuleSet: []string{"geoip-cn", "geosite-geolocation-cn"}, RuleSet: []string{"geoip-cn", "geosite-geolocation-cn"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag, Outbound: directTag,
}, },
},
},
}) })
} }
} }
@ -125,18 +178,27 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
options.Route.Rules = append(options.Route.Rules, option.Rule{ options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeLogical, Type: C.RuleTypeLogical,
LogicalOptions: option.LogicalRule{ LogicalOptions: option.LogicalRule{
RawLogicalRule: option.RawLogicalRule{
Mode: C.LogicalTypeOr, Mode: C.LogicalTypeOr,
Rules: []option.Rule{ Rules: []option.Rule{
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
Network: []string{N.NetworkUDP}, Network: []string{N.NetworkUDP},
Port: []uint16{443}, Port: []uint16{443},
}, },
}, },
}, },
},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: blockTag, Outbound: blockTag,
}, },
},
},
}) })
} }
return nil return nil

View File

@ -1,6 +1,7 @@
package template package template
import ( import (
"context"
"regexp" "regexp"
M "github.com/sagernet/serenity/common/metadata" M "github.com/sagernet/serenity/common/metadata"
@ -39,7 +40,7 @@ type ExtraGroup struct {
exclude []*regexp.Regexp exclude []*regexp.Regexp
} }
func (t *Template) Render(metadata M.Metadata, profileName string, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) (*boxOption.Options, error) { func (t *Template) Render(ctx context.Context, metadata M.Metadata, profileName string, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) (*boxOption.Options, error) {
var options boxOption.Options var options boxOption.Options
options.Log = t.Log options.Log = t.Log
err := t.renderDNS(metadata, &options) err := t.renderDNS(metadata, &options)
@ -58,7 +59,7 @@ func (t *Template) Render(metadata M.Metadata, profileName string, outbounds [][
if err != nil { if err != nil {
return nil, E.Cause(err, "render outbounds") return nil, E.Cause(err, "render outbounds")
} }
err = t.renderExperimental(metadata, &options, profileName) err = t.renderExperimental(ctx, metadata, &options, profileName)
if err != nil { if err != nil {
return nil, E.Cause(err, "render experimental") return nil, E.Cause(err, "render experimental")
} }