diff --git a/cmd/sing-box/cmd_rule_set_convert.go b/cmd/sing-box/cmd_rule_set_convert.go new file mode 100644 index 0000000000..8d2092ea28 --- /dev/null +++ b/cmd/sing-box/cmd_rule_set_convert.go @@ -0,0 +1,88 @@ +package main + +import ( + "io" + "os" + "strings" + + "github.com/sagernet/sing-box/cmd/sing-box/internal/convertor/adguard" + "github.com/sagernet/sing-box/common/srs" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + + "github.com/spf13/cobra" +) + +var ( + flagRuleSetConvertType string + flagRuleSetConvertOutput string +) + +var commandRuleSetConvert = &cobra.Command{ + Use: "convert [source-path]", + Short: "Convert adguard DNS filter to rule-set", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + err := convertRuleSet(args[0]) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandRuleSet.AddCommand(commandRuleSetConvert) + commandRuleSetConvert.Flags().StringVarP(&flagRuleSetConvertType, "type", "t", "", "Source type, available: adguard") + commandRuleSetConvert.Flags().StringVarP(&flagRuleSetConvertOutput, "output", "o", flagRuleSetCompileDefaultOutput, "Output file") +} + +func convertRuleSet(sourcePath string) error { + var ( + reader io.Reader + err error + ) + if sourcePath == "stdin" { + reader = os.Stdin + } else { + reader, err = os.Open(sourcePath) + if err != nil { + return err + } + } + var rules []option.HeadlessRule + switch flagRuleSetConvertType { + case "adguard": + rules, err = adguard.Convert(reader) + case "": + return E.New("source type is required") + default: + return E.New("unsupported source type: ", flagRuleSetConvertType) + } + if err != nil { + return err + } + var outputPath string + if flagRuleSetConvertOutput == flagRuleSetCompileDefaultOutput { + if strings.HasSuffix(sourcePath, ".txt") { + outputPath = sourcePath[:len(sourcePath)-4] + ".srs" + } else { + outputPath = sourcePath + ".srs" + } + } else { + outputPath = flagRuleSetConvertOutput + } + outputFile, err := os.Create(outputPath) + if err != nil { + return err + } + defer outputFile.Close() + err = srs.Write(outputFile, option.PlainRuleSet{Rules: rules}, true) + if err != nil { + outputFile.Close() + os.Remove(outputPath) + return err + } + outputFile.Close() + return nil +} diff --git a/cmd/sing-box/cmd_run.go b/cmd/sing-box/cmd_run.go index e717c5945d..6850cd19e3 100644 --- a/cmd/sing-box/cmd_run.go +++ b/cmd/sing-box/cmd_run.go @@ -188,9 +188,12 @@ func run() error { cancel() closeCtx, closed := context.WithCancel(context.Background()) go closeMonitor(closeCtx) - instance.Close() + err = instance.Close() closed() if osSignal != syscall.SIGHUP { + if err != nil { + log.Error(E.Cause(err, "sing-box did not closed properly")) + } return nil } break diff --git a/cmd/sing-box/internal/convertor/adguard/convertor.go b/cmd/sing-box/internal/convertor/adguard/convertor.go new file mode 100644 index 0000000000..ff60929b8d --- /dev/null +++ b/cmd/sing-box/internal/convertor/adguard/convertor.go @@ -0,0 +1,346 @@ +package adguard + +import ( + "bufio" + "io" + "net/netip" + "os" + "strconv" + "strings" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" +) + +type agdguardRuleLine struct { + ruleLine string + isRawDomain bool + isExclude bool + isSuffix bool + hasStart bool + hasEnd bool + isRegexp bool + isImportant bool +} + +func Convert(reader io.Reader) ([]option.HeadlessRule, error) { + scanner := bufio.NewScanner(reader) + var ( + ruleLines []agdguardRuleLine + ignoredLines int + ) +parseLine: + for scanner.Scan() { + ruleLine := scanner.Text() + if ruleLine == "" || ruleLine[0] == '!' || ruleLine[0] == '#' { + continue + } + originRuleLine := ruleLine + if M.IsDomainName(ruleLine) { + ruleLines = append(ruleLines, agdguardRuleLine{ + ruleLine: ruleLine, + isRawDomain: true, + }) + continue + } + hostLine, err := parseAdGuardHostLine(ruleLine) + if err == nil { + if hostLine != "" { + ruleLines = append(ruleLines, agdguardRuleLine{ + ruleLine: hostLine, + isRawDomain: true, + hasStart: true, + hasEnd: true, + }) + } + continue + } + if strings.HasSuffix(ruleLine, "|") { + ruleLine = ruleLine[:len(ruleLine)-1] + } + var ( + isExclude bool + isSuffix bool + hasStart bool + hasEnd bool + isRegexp bool + isImportant bool + ) + if !strings.HasPrefix(ruleLine, "/") && strings.Contains(ruleLine, "$") { + params := common.SubstringAfter(ruleLine, "$") + for _, param := range strings.Split(params, ",") { + paramParts := strings.Split(param, "=") + var ignored bool + if len(paramParts) > 0 && len(paramParts) <= 2 { + switch paramParts[0] { + case "app", "network": + // maybe support by package_name/process_name + case "dnstype": + // maybe support by query_type + case "important": + ignored = true + isImportant = true + case "dnsrewrite": + if len(paramParts) == 2 && M.ParseAddr(paramParts[1]).IsUnspecified() { + ignored = true + } + } + } + if !ignored { + ignoredLines++ + log.Debug("ignored unsupported rule with modifier: ", paramParts[0], ": ", ruleLine) + continue parseLine + } + } + ruleLine = common.SubstringBefore(ruleLine, "$") + } + if strings.HasPrefix(ruleLine, "@@") { + ruleLine = ruleLine[2:] + isExclude = true + } + if strings.HasSuffix(ruleLine, "|") { + ruleLine = ruleLine[:len(ruleLine)-1] + } + if strings.HasPrefix(ruleLine, "||") { + ruleLine = ruleLine[2:] + isSuffix = true + } else if strings.HasPrefix(ruleLine, "|") { + ruleLine = ruleLine[1:] + hasStart = true + } + if strings.HasSuffix(ruleLine, "^") { + ruleLine = ruleLine[:len(ruleLine)-1] + hasEnd = true + } + if strings.HasPrefix(ruleLine, "/") && strings.HasSuffix(ruleLine, "/") { + ruleLine = ruleLine[1 : len(ruleLine)-1] + if ignoreIPCIDRRegexp(ruleLine) { + ignoredLines++ + log.Debug("ignored unsupported rule with IPCIDR regexp: ", ruleLine) + continue + } + isRegexp = true + } else { + if strings.Contains(ruleLine, "://") { + ruleLine = common.SubstringAfter(ruleLine, "://") + } + if strings.Contains(ruleLine, "/") { + ignoredLines++ + log.Debug("ignored unsupported rule with path: ", ruleLine) + continue + } + if strings.Contains(ruleLine, "##") { + ignoredLines++ + log.Debug("ignored unsupported rule with element hiding: ", ruleLine) + continue + } + if strings.Contains(ruleLine, "#$#") { + ignoredLines++ + log.Debug("ignored unsupported rule with element hiding: ", ruleLine) + continue + } + var domainCheck string + if strings.HasPrefix(ruleLine, ".") || strings.HasPrefix(ruleLine, "-") { + domainCheck = "r" + ruleLine + } else { + domainCheck = ruleLine + } + if ruleLine == "" { + ignoredLines++ + log.Debug("ignored unsupported rule with empty domain", originRuleLine) + continue + } else { + domainCheck = strings.ReplaceAll(domainCheck, "*", "x") + if !M.IsDomainName(domainCheck) { + _, ipErr := parseADGuardIPCIDRLine(ruleLine) + if ipErr == nil { + ignoredLines++ + log.Debug("ignored unsupported rule with IPCIDR: ", ruleLine) + continue + } + if M.ParseSocksaddr(domainCheck).Port != 0 { + log.Debug("ignored unsupported rule with port: ", ruleLine) + } else { + log.Debug("ignored unsupported rule with invalid domain: ", ruleLine) + } + ignoredLines++ + continue + } + } + } + ruleLines = append(ruleLines, agdguardRuleLine{ + ruleLine: ruleLine, + isExclude: isExclude, + isSuffix: isSuffix, + hasStart: hasStart, + hasEnd: hasEnd, + isRegexp: isRegexp, + isImportant: isImportant, + }) + } + if len(ruleLines) == 0 { + return nil, E.New("AdGuard rule-set is empty or all rules are unsupported") + } + if common.All(ruleLines, func(it agdguardRuleLine) bool { + return it.isRawDomain + }) { + return []option.HeadlessRule{ + { + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultHeadlessRule{ + Domain: common.Map(ruleLines, func(it agdguardRuleLine) string { + return it.ruleLine + }), + }, + }, + }, nil + } + mapDomain := func(it agdguardRuleLine) string { + ruleLine := it.ruleLine + if it.isSuffix { + ruleLine = "||" + ruleLine + } else if it.hasStart { + ruleLine = "|" + ruleLine + } + if it.hasEnd { + ruleLine += "^" + } + return ruleLine + } + + importantDomain := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return it.isImportant && !it.isRegexp && !it.isExclude }), mapDomain) + importantDomainRegex := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return it.isImportant && it.isRegexp && !it.isExclude }), mapDomain) + importantExcludeDomain := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return it.isImportant && !it.isRegexp && it.isExclude }), mapDomain) + importantExcludeDomainRegex := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return it.isImportant && it.isRegexp && it.isExclude }), mapDomain) + domain := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return !it.isImportant && !it.isRegexp && !it.isExclude }), mapDomain) + domainRegex := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return !it.isImportant && it.isRegexp && !it.isExclude }), mapDomain) + excludeDomain := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return !it.isImportant && !it.isRegexp && it.isExclude }), mapDomain) + excludeDomainRegex := common.Map(common.Filter(ruleLines, func(it agdguardRuleLine) bool { return !it.isImportant && it.isRegexp && it.isExclude }), mapDomain) + currentRule := option.HeadlessRule{ + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultHeadlessRule{ + AdGuardDomain: domain, + DomainRegex: domainRegex, + }, + } + if len(excludeDomain) > 0 || len(excludeDomainRegex) > 0 { + currentRule = option.HeadlessRule{ + Type: C.RuleTypeLogical, + LogicalOptions: option.LogicalHeadlessRule{ + Mode: C.LogicalTypeAnd, + Rules: []option.HeadlessRule{ + { + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultHeadlessRule{ + AdGuardDomain: excludeDomain, + DomainRegex: excludeDomainRegex, + Invert: true, + }, + }, + currentRule, + }, + }, + } + } + if len(importantDomain) > 0 || len(importantDomainRegex) > 0 { + currentRule = option.HeadlessRule{ + Type: C.RuleTypeLogical, + LogicalOptions: option.LogicalHeadlessRule{ + Mode: C.LogicalTypeOr, + Rules: []option.HeadlessRule{ + { + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultHeadlessRule{ + AdGuardDomain: importantDomain, + DomainRegex: importantDomainRegex, + }, + }, + currentRule, + }, + }, + } + } + if len(importantExcludeDomain) > 0 || len(importantExcludeDomainRegex) > 0 { + currentRule = option.HeadlessRule{ + Type: C.RuleTypeLogical, + LogicalOptions: option.LogicalHeadlessRule{ + Mode: C.LogicalTypeAnd, + Rules: []option.HeadlessRule{ + { + Type: C.RuleTypeDefault, + DefaultOptions: option.DefaultHeadlessRule{ + AdGuardDomain: importantExcludeDomain, + DomainRegex: importantExcludeDomainRegex, + Invert: true, + }, + }, + currentRule, + }, + }, + } + } + log.Info("parsed rules: ", len(ruleLines), "/", len(ruleLines)+ignoredLines) + return []option.HeadlessRule{currentRule}, nil +} + +func ignoreIPCIDRRegexp(ruleLine string) bool { + if strings.HasPrefix(ruleLine, "(http?:\\/\\/)") { + ruleLine = ruleLine[12:] + } else if strings.HasPrefix(ruleLine, "(https?:\\/\\/)") { + ruleLine = ruleLine[13:] + } else if strings.HasPrefix(ruleLine, "^") { + ruleLine = ruleLine[1:] + } else { + return false + } + _, parseErr := strconv.ParseUint(common.SubstringBefore(ruleLine, "\\."), 10, 8) + return parseErr == nil +} + +func parseAdGuardHostLine(ruleLine string) (string, error) { + idx := strings.Index(ruleLine, " ") + if idx == -1 { + return "", os.ErrInvalid + } + address, err := netip.ParseAddr(ruleLine[:idx]) + if err != nil { + return "", err + } + if !address.IsUnspecified() { + return "", nil + } + domain := ruleLine[idx+1:] + if !M.IsDomainName(domain) { + return "", E.New("invalid domain name: ", domain) + } + return domain, nil +} + +func parseADGuardIPCIDRLine(ruleLine string) (netip.Prefix, error) { + var isPrefix bool + if strings.HasSuffix(ruleLine, ".") { + isPrefix = true + ruleLine = ruleLine[:len(ruleLine)-1] + } + ruleStringParts := strings.Split(ruleLine, ".") + if len(ruleStringParts) > 4 || len(ruleStringParts) < 4 && !isPrefix { + return netip.Prefix{}, os.ErrInvalid + } + ruleParts := make([]uint8, 0, len(ruleStringParts)) + for _, part := range ruleStringParts { + rulePart, err := strconv.ParseUint(part, 10, 8) + if err != nil { + return netip.Prefix{}, err + } + ruleParts = append(ruleParts, uint8(rulePart)) + } + bitLen := len(ruleParts) * 8 + for len(ruleParts) < 4 { + ruleParts = append(ruleParts, 0) + } + return netip.PrefixFrom(netip.AddrFrom4(*(*[4]byte)(ruleParts)), bitLen), nil +} diff --git a/cmd/sing-box/internal/convertor/adguard/convertor_test.go b/cmd/sing-box/internal/convertor/adguard/convertor_test.go new file mode 100644 index 0000000000..7da8a22841 --- /dev/null +++ b/cmd/sing-box/internal/convertor/adguard/convertor_test.go @@ -0,0 +1,140 @@ +package adguard + +import ( + "strings" + "testing" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/route" + + "github.com/stretchr/testify/require" +) + +func TestConverter(t *testing.T) { + t.Parallel() + rules, err := Convert(strings.NewReader(` +||example.org^ +|example.com^ +example.net^ +||example.edu +||example.edu.tw^ +|example.gov +example.arpa +@@|sagernet.example.org| +||sagernet.org^$important +@@|sing-box.sagernet.org^$important +`)) + require.NoError(t, err) + require.Len(t, rules, 1) + rule, err := route.NewHeadlessRule(nil, rules[0]) + require.NoError(t, err) + matchDomain := []string{ + "example.org", + "www.example.org", + "example.com", + "example.net", + "isexample.net", + "www.example.net", + "example.edu", + "example.edu.cn", + "example.edu.tw", + "www.example.edu", + "www.example.edu.cn", + "example.gov", + "example.gov.cn", + "example.arpa", + "www.example.arpa", + "isexample.arpa", + "example.arpa.cn", + "www.example.arpa.cn", + "isexample.arpa.cn", + "sagernet.org", + "www.sagernet.org", + } + notMatchDomain := []string{ + "example.org.cn", + "notexample.org", + "example.com.cn", + "www.example.com.cn", + "example.net.cn", + "notexample.edu", + "notexample.edu.cn", + "www.example.gov", + "notexample.gov", + "sagernet.example.org", + "sing-box.sagernet.org", + } + for _, domain := range matchDomain { + require.True(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } + for _, domain := range notMatchDomain { + require.False(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } +} + +func TestHosts(t *testing.T) { + t.Parallel() + rules, err := Convert(strings.NewReader(` +127.0.0.1 localhost +::1 localhost #[IPv6] +0.0.0.0 google.com +`)) + require.NoError(t, err) + require.Len(t, rules, 1) + rule, err := route.NewHeadlessRule(nil, rules[0]) + require.NoError(t, err) + matchDomain := []string{ + "google.com", + } + notMatchDomain := []string{ + "www.google.com", + "notgoogle.com", + "localhost", + } + for _, domain := range matchDomain { + require.True(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } + for _, domain := range notMatchDomain { + require.False(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } +} + +func TestSimpleHosts(t *testing.T) { + t.Parallel() + rules, err := Convert(strings.NewReader(` +example.com +www.example.org +`)) + require.NoError(t, err) + require.Len(t, rules, 1) + rule, err := route.NewHeadlessRule(nil, rules[0]) + require.NoError(t, err) + matchDomain := []string{ + "example.com", + "www.example.org", + } + notMatchDomain := []string{ + "example.com.cn", + "www.example.com", + "notexample.com", + "example.org", + } + for _, domain := range matchDomain { + require.True(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } + for _, domain := range notMatchDomain { + require.False(t, rule.Match(&adapter.InboundContext{ + Domain: domain, + }), domain) + } +} diff --git a/common/srs/binary.go b/common/srs/binary.go index 69075f7881..7e4f402b39 100644 --- a/common/srs/binary.go +++ b/common/srs/binary.go @@ -36,6 +36,7 @@ const ( ruleItemPackageName ruleItemWIFISSID ruleItemWIFIBSSID + ruleItemAdGuardDomain ruleItemFinal uint8 = 0xFF ) @@ -212,6 +213,17 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea rule.WIFISSID, err = readRuleItemString(reader) case ruleItemWIFIBSSID: rule.WIFIBSSID, err = readRuleItemString(reader) + case ruleItemAdGuardDomain: + if recover { + err = E.New("unable to decompile binary AdGuard rules to rule-set") + return + } + var matcher *domain.AdGuardMatcher + matcher, err = domain.ReadAdGuardMatcher(reader) + if err != nil { + return + } + rule.AdGuardDomainMatcher = matcher case ruleItemFinal: err = binary.Read(reader, binary.BigEndian, &rule.Invert) return @@ -332,6 +344,16 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen return err } } + if len(rule.AdGuardDomain) > 0 { + err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain) + if err != nil { + return err + } + err = domain.NewAdGuardMatcher(rule.AdGuardDomain).Write(writer) + if err != nil { + return err + } + } err = binary.Write(writer, binary.BigEndian, ruleItemFinal) if err != nil { return err diff --git a/debug_go119.go b/debug.go similarity index 97% rename from debug_go119.go rename to debug.go index cf522afb72..2fa962d642 100644 --- a/debug_go119.go +++ b/debug.go @@ -1,5 +1,3 @@ -//go:build go1.19 - package box import ( diff --git a/debug_go118.go b/debug_go118.go deleted file mode 100644 index bb132efb98..0000000000 --- a/debug_go118.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build !go1.19 - -package box - -import ( - "runtime/debug" - - "github.com/sagernet/sing-box/common/conntrack" - "github.com/sagernet/sing-box/option" -) - -func applyDebugOptions(options option.DebugOptions) { - applyDebugListenOption(options) - if options.GCPercent != nil { - debug.SetGCPercent(*options.GCPercent) - } - if options.MaxStack != nil { - debug.SetMaxStack(*options.MaxStack) - } - if options.MaxThreads != nil { - debug.SetMaxThreads(*options.MaxThreads) - } - if options.PanicOnFault != nil { - debug.SetPanicOnFault(*options.PanicOnFault) - } - if options.TraceBack != "" { - debug.SetTraceback(options.TraceBack) - } - if options.MemoryLimit != 0 { - // debug.SetMemoryLimit(int64(options.MemoryLimit)) - conntrack.MemoryLimit = uint64(options.MemoryLimit) - } - if options.OOMKiller != nil { - conntrack.KillerEnabled = *options.OOMKiller - } -} diff --git a/docs/changelog.md b/docs/changelog.md index 4640ae0cf2..39940253f3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,10 +2,21 @@ icon: material/alert-decagram --- -#### 1.10.0-alpha.24 +#### 1.10.0-alpha.29 +* Update quic-go to v0.46.0 * Fixes and improvements +#### 1.10.0-alpha.25 + +* Add AdGuard DNS Filter support **1** + +**1**: + +The new feature allows you to use AdGuard DNS Filter lists in a sing-box without AdGuard Home. + +See [AdGuard DNS Filter](/configuration/rule-set/adguard/). + #### 1.10.0-alpha.23 * Add Chromium support for QUIC sniffer diff --git a/docs/configuration/route/rule.zh.md b/docs/configuration/route/rule.zh.md index f9a84d5175..68e66cf5c9 100644 --- a/docs/configuration/route/rule.zh.md +++ b/docs/configuration/route/rule.zh.md @@ -4,9 +4,9 @@ icon: material/alert-decagram !!! quote "sing-box 1.10.0 中的更改" - :material-plus: [client](#client) + :material-plus: [client](#client) :material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source) - :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) + :material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source) !!! quote "sing-box 1.8.0 中的更改" diff --git a/docs/configuration/route/sniff.md b/docs/configuration/route/sniff.md index df030d73e8..ab96e75a6f 100644 --- a/docs/configuration/route/sniff.md +++ b/docs/configuration/route/sniff.md @@ -4,9 +4,9 @@ icon: material/new-box !!! quote "Changes in sing-box 1.10.0" - :material-plus: QUIC client type detect support for QUIC - :material-plus: Chromium support for QUIC - :material-plus: BitTorrent support + :material-plus: QUIC client type detect support for QUIC + :material-plus: Chromium support for QUIC + :material-plus: BitTorrent support :material-plus: DTLS support If enabled in the inbound, the protocol and domain name (if present) of by the connection can be sniffed. diff --git a/docs/configuration/route/sniff.zh.md b/docs/configuration/route/sniff.zh.md index 99a6535972..1ebc6d38d1 100644 --- a/docs/configuration/route/sniff.zh.md +++ b/docs/configuration/route/sniff.zh.md @@ -4,9 +4,9 @@ icon: material/new-box !!! quote "sing-box 1.10.0 中的更改" - :material-plus: QUIC 的 客户端类型探测支持 - :material-plus: QUIC 的 Chromium 支持 - :material-plus: BitTorrent 支持 + :material-plus: QUIC 的 客户端类型探测支持 + :material-plus: QUIC 的 Chromium 支持 + :material-plus: BitTorrent 支持 :material-plus: DTLS 支持 如果在入站中启用,则可以嗅探连接的协议和域名(如果存在)。 diff --git a/docs/configuration/rule-set/adguard.md b/docs/configuration/rule-set/adguard.md new file mode 100644 index 0000000000..870972bf2f --- /dev/null +++ b/docs/configuration/rule-set/adguard.md @@ -0,0 +1,71 @@ +--- +icon: material/new-box +--- + +# AdGuard DNS Filter + +!!! question "Since sing-box 1.10.0" + +sing-box supports some rule-set formats from other projects which cannot be fully translated to sing-box, +currently only AdGuard DNS Filter. + +These formats are not directly supported as source formats, +instead you need to convert them to binary rule-set. + +## Convert + +Use `sing-box rule-set convert --type adguard [--output .srs] .txt` to convert to binary rule-set. + +## Performance + +AdGuard keeps all rules in memory and matches them sequentially, +while sing-box chooses high performance and smaller memory usage. +As a trade-off, you cannot know which rule item is matched. + +## Compatibility + +Almost all rules in [AdGuardSDNSFilter](https://github.com/AdguardTeam/AdGuardSDNSFilter) +and rules in rule-sets listed in [adguard-filter-list](https://github.com/ppfeufer/adguard-filter-list) +are supported. + +## Supported formats + +### AdGuard Filter + +#### Basic rule syntax + +| Syntax | Supported | +|--------|------------------| +| `@@` | :material-check: | +| `\|\|` | :material-check: | +| `\|` | :material-check: | +| `^` | :material-check: | +| `*` | :material-check: | + +#### Host syntax + +| Syntax | Example | Supported | +|-------------|--------------------------|--------------------------| +| Scheme | `https://` | :material-alert: Ignored | +| Domain Host | `example.org` | :material-check: | +| IP Host | `1.1.1.1`, `10.0.0.` | :material-close: | +| Regexp | `/regexp/` | :material-check: | +| Port | `example.org:80` | :material-close: | +| Path | `example.org/path/ad.js` | :material-close: | + +#### Modifier syntax + +| Modifier | Supported | +|-----------------------|--------------------------| +| `$important` | :material-check: | +| `$dnsrewrite=0.0.0.0` | :material-alert: Ignored | +| Any other modifiers | :material-close: | + +### Hosts + +Only items with `0.0.0.0` IP addresses will be accepted. + +### Simple + +When all rule lines are valid domains, they are treated as simple line-by-line domain rules which, +like hosts, only match the exact same domain. \ No newline at end of file diff --git a/go.mod b/go.mod index fed8c7e73c..a149d35b5d 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/sagernet/sing-box go 1.21 -toolchain go1.22.5 +toolchain go1.22.6 require ( berty.tech/go-libtor v1.0.385 @@ -28,10 +28,10 @@ require ( github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.3 github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f - github.com/sagernet/quic-go v0.45.1-beta.2 + github.com/sagernet/quic-go v0.46.0-beta.2 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.5.0-alpha.13 - github.com/sagernet/sing-dns v0.3.0-beta.12 + github.com/sagernet/sing v0.5.0-alpha.15 + github.com/sagernet/sing-dns v0.3.0-beta.14 github.com/sagernet/sing-mux v0.2.0 github.com/sagernet/sing-quic v0.2.0-beta.12 github.com/sagernet/sing-shadowsocks v0.2.7 diff --git a/go.sum b/go.sum index d732326a59..ed8cc9f430 100644 --- a/go.sum +++ b/go.sum @@ -120,15 +120,15 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN 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/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.45.1-beta.2 h1:zkEeCbhdFFkrxKcuIRBtXNKci/1t2J/39QSG/sPvlmc= -github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX7DeW7BslzLO6N/xI= +github.com/sagernet/quic-go v0.46.0-beta.2 h1:D/k9P3btgg0CvtUFVlQsUyN9GkLj0fMG59FOlEz1In8= +github.com/sagernet/quic-go v0.46.0-beta.2/go.mod h1:Zt3LVudHvhFRa7uO7hjtLAYJ9wFzYv4F17+LedJSw44= 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/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.5.0-alpha.13 h1:fpR4TFZfu/9V3LbHSAnnnwcaXGMF8ijmAAPoY2WHSKw= -github.com/sagernet/sing v0.5.0-alpha.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-dns v0.3.0-beta.12 h1:mdTsaVU+0jopEKUDLwLmo8AbiSGZOly97oSPBDX3O8I= -github.com/sagernet/sing-dns v0.3.0-beta.12/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00= +github.com/sagernet/sing v0.5.0-alpha.15 h1:Jqc+8MukOIdwyzAK48bK0uHmYUnfMdfGcXTxrB7OTVE= +github.com/sagernet/sing v0.5.0-alpha.15/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing-dns v0.3.0-beta.14 h1:/s+fJzYKsvLaNDt/2rjpsrDcN8wmCO2JbX6OFrl8Nww= +github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00= github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY= diff --git a/mkdocs.yml b/mkdocs.yml index d5218f4d53..63b339fa8b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,6 +90,7 @@ nav: - configuration/rule-set/index.md - Source Format: configuration/rule-set/source-format.md - Headless Rule: configuration/rule-set/headless-rule.md + - AdGuard DNS Filer: configuration/rule-set/adguard.md - Experimental: - configuration/experimental/index.md - Cache File: configuration/experimental/cache-file.md diff --git a/option/rule_dns.go b/option/rule_dns.go index 38cd5c8330..2afe245ea4 100644 --- a/option/rule_dns.go +++ b/option/rule_dns.go @@ -111,7 +111,7 @@ type _DefaultDNSRule struct { type DefaultDNSRule _DefaultDNSRule func (r *DefaultDNSRule) UnmarshalJSON(bytes []byte) error { - err := json.Unmarshal(bytes, (*_DefaultDNSRule)(r)) + err := json.UnmarshalDisallowUnknownFields(bytes, (*_DefaultDNSRule)(r)) if err != nil { return err } diff --git a/option/rule_set.go b/option/rule_set.go index 002cadd46e..8470324b02 100644 --- a/option/rule_set.go +++ b/option/rule_set.go @@ -166,6 +166,9 @@ type DefaultHeadlessRule struct { DomainMatcher *domain.Matcher `json:"-"` SourceIPSet *netipx.IPSet `json:"-"` IPSet *netipx.IPSet `json:"-"` + + AdGuardDomain Listable[string] `json:"-"` + AdGuardDomainMatcher *domain.AdGuardMatcher `json:"-"` } func (r DefaultHeadlessRule) IsValid() bool { diff --git a/route/router.go b/route/router.go index dac2f09e61..e313c6f71d 100644 --- a/route/router.go +++ b/route/router.go @@ -132,7 +132,7 @@ func NewRouter( pauseManager: service.FromContext[pause.Manager](ctx), platformInterface: platformInterface, needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule), - needPackageManager: C.IsAndroid && platformInterface == nil && common.Any(inbounds, func(inbound option.Inbound) bool { + needPackageManager: common.Any(inbounds, func(inbound option.Inbound) bool { return len(inbound.TunOptions.IncludePackage) > 0 || len(inbound.TunOptions.ExcludePackage) > 0 }), } @@ -532,7 +532,7 @@ func (r *Router) Start() error { r.dnsClient.Start() monitor.Finish() - if r.needPackageManager && r.platformInterface == nil { + if C.IsAndroid && r.platformInterface == nil { monitor.Start("initialize package manager") packageManager, err := tun.NewPackageManager(tun.PackageManagerOptions{ Callback: r, @@ -542,11 +542,13 @@ func (r *Router) Start() error { if err != nil { return E.Cause(err, "create package manager") } - monitor.Start("start package manager") - err = packageManager.Start() - monitor.Finish() - if err != nil { - return E.Cause(err, "start package manager") + if r.needPackageManager { + monitor.Start("start package manager") + err = packageManager.Start() + monitor.Finish() + if err != nil { + return E.Cause(err, "start package manager") + } } r.packageManager = packageManager } @@ -679,20 +681,30 @@ func (r *Router) PostStart() error { } ruleSetStartContext.Close() } - var ( - needProcessFromRuleSet bool - needWIFIStateFromRuleSet bool - ) + needFindProcess := r.needFindProcess + needWIFIState := r.needWIFIState for _, ruleSet := range r.ruleSets { metadata := ruleSet.Metadata() if metadata.ContainsProcessRule { - needProcessFromRuleSet = true + needFindProcess = true } if metadata.ContainsWIFIRule { - needWIFIStateFromRuleSet = true + needWIFIState = true + } + } + if C.IsAndroid && r.platformInterface == nil && !r.needPackageManager { + if needFindProcess { + monitor.Start("start package manager") + err := r.packageManager.Start() + monitor.Finish() + if err != nil { + return E.Cause(err, "start package manager") + } + } else { + r.packageManager = nil } } - if needProcessFromRuleSet || r.needFindProcess { + if needFindProcess { if r.platformInterface != nil { r.processSearcher = r.platformInterface } else { @@ -711,7 +723,7 @@ func (r *Router) PostStart() error { } } } - if (needWIFIStateFromRuleSet || r.needWIFIState) && r.platformInterface != nil { + if needWIFIState && r.platformInterface != nil { monitor.Start("initialize WIFI state") r.needWIFIState = true r.interfaceMonitor.RegisterCallback(func(_ int) { diff --git a/route/rule_headless.go b/route/rule_headless.go index 67ac3a1e44..d537df572c 100644 --- a/route/rule_headless.go +++ b/route/rule_headless.go @@ -142,6 +142,15 @@ func NewDefaultHeadlessRule(router adapter.Router, options option.DefaultHeadles rule.allItems = append(rule.allItems, item) } } + if len(options.AdGuardDomain) > 0 { + item := NewAdGuardDomainItem(options.AdGuardDomain) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) + } else if options.AdGuardDomainMatcher != nil { + item := NewRawAdGuardDomainItem(options.AdGuardDomainMatcher) + rule.destinationAddressItems = append(rule.destinationAddressItems, item) + rule.allItems = append(rule.allItems, item) + } return rule, nil } diff --git a/route/rule_item_adguard.go b/route/rule_item_adguard.go new file mode 100644 index 0000000000..bdbb3b75fd --- /dev/null +++ b/route/rule_item_adguard.go @@ -0,0 +1,43 @@ +package route + +import ( + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing/common/domain" +) + +var _ RuleItem = (*AdGuardDomainItem)(nil) + +type AdGuardDomainItem struct { + matcher *domain.AdGuardMatcher +} + +func NewAdGuardDomainItem(ruleLines []string) *AdGuardDomainItem { + return &AdGuardDomainItem{ + domain.NewAdGuardMatcher(ruleLines), + } +} + +func NewRawAdGuardDomainItem(matcher *domain.AdGuardMatcher) *AdGuardDomainItem { + return &AdGuardDomainItem{ + matcher, + } +} + +func (r *AdGuardDomainItem) Match(metadata *adapter.InboundContext) bool { + var domainHost string + if metadata.Domain != "" { + domainHost = metadata.Domain + } else { + domainHost = metadata.Destination.Fqdn + } + if domainHost == "" { + return false + } + return r.matcher.Match(strings.ToLower(domainHost)) +} + +func (r *AdGuardDomainItem) String() string { + return "!adguard_domain_rules=" +} diff --git a/test/go.mod b/test/go.mod index 9f28e7fcc4..a50840bdc9 100644 --- a/test/go.mod +++ b/test/go.mod @@ -1,8 +1,6 @@ module test -go 1.21 - -toolchain go1.21.7 +go 1.20 require github.com/sagernet/sing-box v0.0.0 @@ -12,22 +10,21 @@ require ( github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.2.0 - github.com/sagernet/quic-go v0.43.1-beta.1 - github.com/sagernet/sing v0.5.0-alpha.8 - github.com/sagernet/sing-dns v0.3.0-beta.1 - github.com/sagernet/sing-quic v0.2.0-beta.5 - github.com/sagernet/sing-shadowsocks v0.2.6 + github.com/sagernet/quic-go v0.46.0-beta.2 + github.com/sagernet/sing v0.5.0-alpha.15 + github.com/sagernet/sing-dns v0.3.0-beta.14 + github.com/sagernet/sing-quic v0.2.0-beta.12 + github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/spyzhov/ajson v0.9.0 github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.3.0 - golang.org/x/net v0.25.0 + golang.org/x/net v0.27.0 ) require ( berty.tech/go-libtor v1.0.385 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.6 // indirect github.com/caddyserver/certmagic v0.20.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect @@ -39,19 +36,14 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-chi/chi/v5 v5.0.12 // indirect - github.com/go-chi/cors v1.2.1 // indirect - github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20240204152450-ca2dc33955c1 // indirect - github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/libdns/alidns v1.0.3 // indirect @@ -59,7 +51,7 @@ require ( github.com/libdns/libdns v0.2.2 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mholt/acmez v1.2.0 // indirect - github.com/miekg/dns v1.1.59 // indirect + github.com/miekg/dns v1.1.61 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect @@ -67,7 +59,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect - github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect @@ -75,35 +66,34 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect - github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/sing-mux v0.2.0 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.4.0-beta.6 // indirect - github.com/sagernet/sing-vmess v0.1.8 // indirect + github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d // indirect + github.com/sagernet/sing-vmess v0.1.12 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 // indirect github.com/sagernet/utls v1.5.4 // indirect github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect - github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect - github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/tools v0.23.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/test/go.sum b/test/go.sum index 758d26bad2..a4793ebb53 100644 --- a/test/go.sum +++ b/test/go.sum @@ -3,14 +3,11 @@ berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+f github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= -github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= -github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= @@ -32,14 +29,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= -github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -49,30 +40,18 @@ 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/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= -github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= -github.com/gofrs/uuid/v5 v5.1.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 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/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= -github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= -github.com/insomniacslk/dhcp v0.0.0-20240204152450-ca2dc33955c1/go.mod h1:izxuNQZeFrbx2nK2fAyN5iNUB34Fe9j0nK4PwLzAkKw= -github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= -github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= @@ -83,21 +62,18 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ= github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE= -github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic= -github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8= +github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054= github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU= github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= -github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= -github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= -github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -114,8 +90,6 @@ github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrB github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= -github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= -github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -128,102 +102,56 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY= github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k= -github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e h1:DOkjByVeAR56dkszjnMZke4wr7yM/1xHaJF3G9olkEE= -github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e/go.mod h1:fLxq/gtp0qzkaEwywlRRiGmjOK5ES/xUzyIKIFP2Asw= -github.com/sagernet/gvisor v0.0.0-20240214044702-a3d61928a32f/go.mod h1:bLmnT/4M4+yKB6F7JtRsbUr+YJ64yXwFIygjyYDFQzQ= -github.com/sagernet/gvisor v0.0.0-20240315080113-799fb6b6d311/go.mod h1:mDrXZSv401qiaFiiIUC59Zp4VG5f4nqXFqDmp5o3hYI= +github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I= github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= -github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.40.0 h1:DvQNPb72lzvNQDe9tcUyHTw8eRv6PLtM2mNYmdlzUMo= -github.com/sagernet/quic-go v0.40.0/go.mod h1:VqtdhlbkeeG5Okhb3eDMb/9o0EoglReHunNT9ukrJAI= -github.com/sagernet/quic-go v0.41.0-beta.2/go.mod h1:X10Mf9DVHuSEReOLov/XuflD13MVLH3WtppVVFnSItU= -github.com/sagernet/quic-go v0.42.0-beta.2/go.mod h1:lf8OYop+fMxIlrfM/ZHpENt/7ZD4JaVNqMhOlq2QMwg= -github.com/sagernet/quic-go v0.42.0-beta.3/go.mod h1:lf8OYop+fMxIlrfM/ZHpENt/7ZD4JaVNqMhOlq2QMwg= -github.com/sagernet/quic-go v0.43.0-beta.3/go.mod h1:3EtxR1Yaa1FZu6jFPiBHpOAdhOxL4A3EPxmiVgjJvVM= -github.com/sagernet/quic-go v0.43.1-beta.1/go.mod h1:BkrQYeop7Jx3hN3TW8/76CXcdhYiNPyYEBL/BVJ1ifc= +github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/quic-go v0.45.1-beta.2 h1:zkEeCbhdFFkrxKcuIRBtXNKci/1t2J/39QSG/sPvlmc= +github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX7DeW7BslzLO6N/xI= +github.com/sagernet/quic-go v0.46.0-beta.2/go.mod h1:Zt3LVudHvhFRa7uO7hjtLAYJ9wFzYv4F17+LedJSw44= 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/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.2.20-0.20231212123824-8836b6754226 h1:rcII71ho6F/7Nyx7n2kESLcnvNMdcU4i8ZUGF2Fi7yA= -github.com/sagernet/sing v0.2.20-0.20231212123824-8836b6754226/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= -github.com/sagernet/sing v0.3.1-beta.1/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= -github.com/sagernet/sing v0.3.3-beta.1/go.mod h1:qHySJ7u8po9DABtMYEkNBcOumx7ZZJf/fbv2sfTkNHE= -github.com/sagernet/sing v0.3.4-beta.1/go.mod h1:qHySJ7u8po9DABtMYEkNBcOumx7ZZJf/fbv2sfTkNHE= -github.com/sagernet/sing v0.4.0-beta.2/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/sagernet/sing v0.4.0-beta.3/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/sagernet/sing v0.4.0-beta.4/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/sagernet/sing v0.4.0-beta.6/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/sagernet/sing v0.4.0-beta.15/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/sagernet/sing v0.4.0-beta.18/go.mod h1:PFQKbElc2Pke7faBLv8oEba5ehtKO21Ho+TkYemTI3Y= -github.com/sagernet/sing v0.5.0-alpha.8/go.mod h1:Xh4KO9nGdvm4K/LVg9Xn9jSxJdqe9KcXbAzNC1S2qfw= -github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= -github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= -github.com/sagernet/sing-dns v0.2.0-beta.2/go.mod h1:IxOqfSb6Zt6UVCy8fJpDxb2XxqzHUytNqeOuJfaiLu8= -github.com/sagernet/sing-dns v0.2.0-beta.3/go.mod h1:IxOqfSb6Zt6UVCy8fJpDxb2XxqzHUytNqeOuJfaiLu8= -github.com/sagernet/sing-dns v0.2.0-beta.5/go.mod h1:IxOqfSb6Zt6UVCy8fJpDxb2XxqzHUytNqeOuJfaiLu8= -github.com/sagernet/sing-dns v0.2.0-beta.7/go.mod h1:IxOqfSb6Zt6UVCy8fJpDxb2XxqzHUytNqeOuJfaiLu8= -github.com/sagernet/sing-dns v0.2.0-beta.14/go.mod h1:gfs585rEu+ZgsXJJiecEIK5avrF5SYlCAbFfZ1B66hs= -github.com/sagernet/sing-dns v0.2.0-beta.15/go.mod h1:gfs585rEu+ZgsXJJiecEIK5avrF5SYlCAbFfZ1B66hs= -github.com/sagernet/sing-dns v0.2.0-beta.16/go.mod h1:XU6Vqr6aHcMz/34Fcv8jmXpRCEuShzW+B7Qg1Xe1nxY= -github.com/sagernet/sing-dns v0.3.0-beta.1/go.mod h1:k/dmFcQpg6+m08gC1yQBy+13+QkuLqpKr4bIreq4U24= -github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 h1:rRlYQPbMKmzKX+43XC04gEQvxc45/AxfteRWfcl2/rw= -github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2/go.mod h1:IdSrwwqBeJTrjLZJRFXE+F8mYXNI/rPAjzlgTFuEVmo= +github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM= +github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= +github.com/sagernet/sing v0.5.0-alpha.15/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k= +github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg= +github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00= +github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= -github.com/sagernet/sing-quic v0.1.6-0.20231207143711-eb3cbf9ed054 h1:Ed7FskwQcep5oQ+QahgVK0F6jPPSV8Nqwjr9MwGatMU= -github.com/sagernet/sing-quic v0.1.6-0.20231207143711-eb3cbf9ed054/go.mod h1:u758WWv3G1OITG365CYblL0NfAruFL1PpLD9DUVTv1o= -github.com/sagernet/sing-quic v0.1.9-beta.1/go.mod h1:F4AXCZiwtRtYdLUTjVMO6elTpA/lLJe17sFlHhHmDVw= -github.com/sagernet/sing-quic v0.1.9-beta.3/go.mod h1:oXe0g8T7edh2Xxl0QcpTO4Tret8M478LpMcr3CPuqWE= -github.com/sagernet/sing-quic v0.1.10-beta.2/go.mod h1:TTnOMr3o3rI+zNxTo+SGBJwouzjIEC3FchJJY1F1ca4= -github.com/sagernet/sing-quic v0.1.12-beta.1/go.mod h1:TTnOMr3o3rI+zNxTo+SGBJwouzjIEC3FchJJY1F1ca4= -github.com/sagernet/sing-quic v0.1.13-beta.1/go.mod h1:Bny0k0Puf7yxhtXfovVyz3gfkHvS1T+/ieKLPhfnhY4= -github.com/sagernet/sing-quic v0.2.0-beta.1/go.mod h1:tVUFk5lcW22Bl0ChWlt4Lo93jw0qir3X1fk2ZSypaA4= -github.com/sagernet/sing-quic v0.2.0-beta.5/go.mod h1:lfad61lScAZhAxZ0DHZWvEIcAaT38O6zPTR4vLsHeP0= -github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s= -github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM= -github.com/sagernet/sing-shadowsocks2 v0.1.6-0.20231207143709-50439739601a h1:uYIKfpE1/EJpa+1Bja7b006VixeRuVduOpeuesMk2lU= -github.com/sagernet/sing-shadowsocks2 v0.1.6-0.20231207143709-50439739601a/go.mod h1:pjeylQ4ApvpEH7B4PUBrdyJf4xmQkg8BaIzT5fI2fR0= +github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY= +github.com/sagernet/sing-quic v0.2.0-beta.12/go.mod h1:YVpLfVi8BvYM7NMrjmnvcRm3E8iMETf1gFQmTQDN9jI= +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/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= 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-tun v0.1.24-0.20231212060935-6a1419aeae11 h1:crTOVPJGOGWOW+Q2a0FQiiS/G2+W6uCLKtOofFMisQc= -github.com/sagernet/sing-tun v0.1.24-0.20231212060935-6a1419aeae11/go.mod h1:DgXPnBqtqWrZj37Mun/W61dW0Q56eLqTZYhcuNLaCtY= -github.com/sagernet/sing-tun v0.2.2-beta.1/go.mod h1:w1HTPPEL575m+Ob3GOIWaTs3ZrTdgLIwoldce/p3WPU= -github.com/sagernet/sing-tun v0.2.2-beta.3/go.mod h1:TaUYOzyBWK43Si6TadJ4gc7fj2iYZ7kxcp6CzzKey3E= -github.com/sagernet/sing-tun v0.2.4-beta.1/go.mod h1:lkefC8gty7FTuzz9ZoNASueutIhClEz7LHjFK3BLGco= -github.com/sagernet/sing-tun v0.2.5-beta.1/go.mod h1:lkefC8gty7FTuzz9ZoNASueutIhClEz7LHjFK3BLGco= -github.com/sagernet/sing-tun v0.2.5-beta.2/go.mod h1:E+KwQKzYkdGEhfIxjmoaB1ZkADaxeXUNzx6GRDRKOfE= -github.com/sagernet/sing-tun v0.2.6-beta.1/go.mod h1:E+KwQKzYkdGEhfIxjmoaB1ZkADaxeXUNzx6GRDRKOfE= -github.com/sagernet/sing-tun v0.2.7-beta.1/go.mod h1:9pauo20NImopbZ3ixnJs6m5CbzhJitfvii6w4Rk3QMg= -github.com/sagernet/sing-tun v0.2.8-beta.1/go.mod h1:xPaOkQhngPMILx+/9DMLCFl4vSxUU2tMnCPSlf05HLo= -github.com/sagernet/sing-tun v0.4.0-beta.6/go.mod h1:X9taVYeJXEtK9v6BpS1V/gUXTwY4nQKH4iYDLX1JUXY= -github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= -github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= +github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY= +github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ= +github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d/go.mod h1:81JwnnYw8X9W9XvmZetSTTiPgIE3SbAbnc+EHKwPJ5U= +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/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI= github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY= github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= -github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2FzELOFNFQtvsxH7NPmlo7X5JizEK51UCojo= -github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= +github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs= github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8/go.mod h1:K4J7/npM+VAMUeUmTa2JaA02JmyheP0GpRBOUvn3ecc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= -github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= -github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/spyzhov/ajson v0.9.0 h1:tF46gJGOenYVj+k9K1U1XpCxVWhmiyY5PsVCAs1+OJ0= github.com/spyzhov/ajson v0.9.0/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8= 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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= @@ -239,8 +167,7 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 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/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= @@ -249,44 +176,31 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= -golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -294,58 +208,38 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +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/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= @@ -354,5 +248,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= diff --git a/test/reality_test.go b/test/reality_test.go deleted file mode 100644 index 2355aee31d..0000000000 --- a/test/reality_test.go +++ /dev/null @@ -1,354 +0,0 @@ -package main - -import ( - "net/netip" - "testing" - - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/vless" -) - -func TestVLESSVisionReality(t *testing.T) { - _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - - userUUID := newUUID() - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userUUID.String(), - Flow: vless.FlowVision, - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.InboundRealityOptions{ - Enabled: true, - Handshake: option.InboundRealityHandshakeOptions{ - ServerOptions: option.ServerOptions{ - Server: "google.com", - ServerPort: 443, - }, - }, - ShortID: []string{"0123456789abcdef"}, - PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc", - }, - }, - }, - }, - }, - { - Type: C.TypeTrojan, - Tag: "trojan", - TrojanOptions: option.TrojanInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: otherPort, - }, - Users: []option.TrojanUser{ - { - Name: "sekai", - Password: userUUID.String(), - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeDirect, - }, - { - Type: C.TypeTrojan, - Tag: "trojan-out", - TrojanOptions: option.TrojanOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: otherPort, - }, - Password: userUUID.String(), - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - DialerOptions: option.DialerOptions{ - Detour: "vless-out", - }, - }, - }, - { - Type: C.TypeVLESS, - Tag: "vless-out", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userUUID.String(), - Flow: vless.FlowVision, - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.OutboundRealityOptions{ - Enabled: true, - ShortID: "0123456789abcdef", - PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0", - }, - UTLS: &option.OutboundUTLSOptions{ - Enabled: true, - }, - }, - }, - }, - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"mixed-in"}, - Outbound: "trojan-out", - }, - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} - -func TestVLESSVisionRealityPlain(t *testing.T) { - userUUID := newUUID() - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userUUID.String(), - Flow: vless.FlowVision, - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.InboundRealityOptions{ - Enabled: true, - Handshake: option.InboundRealityHandshakeOptions{ - ServerOptions: option.ServerOptions{ - Server: "google.com", - ServerPort: 443, - }, - }, - ShortID: []string{"0123456789abcdef"}, - PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc", - }, - }, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeDirect, - }, - { - Type: C.TypeVLESS, - Tag: "vless-out", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userUUID.String(), - Flow: vless.FlowVision, - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.OutboundRealityOptions{ - Enabled: true, - ShortID: "0123456789abcdef", - PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0", - }, - UTLS: &option.OutboundUTLSOptions{ - Enabled: true, - }, - }, - }, - }, - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"mixed-in"}, - Outbound: "vless-out", - }, - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} - -func TestVLESSRealityTransport(t *testing.T) { - t.Run("grpc", func(t *testing.T) { - testVLESSRealityTransport(t, &option.V2RayTransportOptions{ - Type: C.V2RayTransportTypeGRPC, - }) - }) - t.Run("websocket", func(t *testing.T) { - testVLESSRealityTransport(t, &option.V2RayTransportOptions{ - Type: C.V2RayTransportTypeWebsocket, - }) - }) - t.Run("h2", func(t *testing.T) { - testVLESSRealityTransport(t, &option.V2RayTransportOptions{ - Type: C.V2RayTransportTypeHTTP, - }) - }) -} - -func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) { - userUUID := newUUID() - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userUUID.String(), - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.InboundRealityOptions{ - Enabled: true, - Handshake: option.InboundRealityHandshakeOptions{ - ServerOptions: option.ServerOptions{ - Server: "google.com", - ServerPort: 443, - }, - }, - ShortID: []string{"0123456789abcdef"}, - PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc", - }, - }, - }, - Transport: transport, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeDirect, - }, - { - Type: C.TypeVLESS, - Tag: "vless-out", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userUUID.String(), - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "google.com", - Reality: &option.OutboundRealityOptions{ - Enabled: true, - ShortID: "0123456789abcdef", - PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0", - }, - UTLS: &option.OutboundUTLSOptions{ - Enabled: true, - }, - }, - }, - Transport: transport, - }, - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"mixed-in"}, - Outbound: "vless-out", - }, - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} diff --git a/test/vless_test.go b/test/vless_test.go deleted file mode 100644 index 50031dd4d3..0000000000 --- a/test/vless_test.go +++ /dev/null @@ -1,559 +0,0 @@ -package main - -import ( - "net/netip" - "os" - "testing" - - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/vless" - - "github.com/gofrs/uuid/v5" - "github.com/spyzhov/ajson" - "github.com/stretchr/testify/require" -) - -func TestVLESS(t *testing.T) { - content, err := os.ReadFile("config/vless-server.json") - require.NoError(t, err) - config, err := ajson.Unmarshal(content) - require.NoError(t, err) - - user := newUUID() - inbound := config.MustKey("inbounds").MustIndex(0) - inbound.MustKey("port").SetNumeric(float64(serverPort)) - inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(user.String()) - - content, err = ajson.Marshal(config) - require.NoError(t, err) - - startDockerContainer(t, DockerOptions{ - Image: ImageV2RayCore, - Ports: []uint16{serverPort}, - EntryPoint: "v2ray", - Cmd: []string{"run"}, - Stdin: content, - }) - - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: user.String(), - }, - }, - }, - }) - testTCP(t, clientPort, testPort) -} - -func TestVLESSXRay(t *testing.T) { - t.Run("origin", func(t *testing.T) { - testVLESSXrayOutbound(t, "", "") - }) - t.Run("xudp", func(t *testing.T) { - testVLESSXrayOutbound(t, "xudp", "") - }) - t.Run("vision", func(t *testing.T) { - testVLESSXrayOutbound(t, "xudp", vless.FlowVision) - }) -} - -func testVLESSXrayOutbound(t *testing.T, packetEncoding string, flow string) { - _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - - content, err := os.ReadFile("config/vless-tls-server.json") - require.NoError(t, err) - config, err := ajson.Unmarshal(content) - require.NoError(t, err) - - userID := newUUID() - inbound := config.MustKey("inbounds").MustIndex(0) - inbound.MustKey("port").SetNumeric(float64(serverPort)) - user := inbound.MustKey("settings").MustKey("clients").MustIndex(0) - user.MustKey("id").SetString(userID.String()) - user.MustKey("flow").SetString(flow) - - content, err = ajson.Marshal(config) - require.NoError(t, err) - - startDockerContainer(t, DockerOptions{ - Image: ImageXRayCore, - Ports: []uint16{serverPort}, - EntryPoint: "xray", - Stdin: content, - Bind: map[string]string{ - certPem: "/path/to/certificate.crt", - keyPem: "/path/to/private.key", - }, - }) - - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeTrojan, - Tag: "trojan", - TrojanOptions: option.TrojanInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: otherPort, - }, - Users: []option.TrojanUser{ - { - Name: "sekai", - Password: userID.String(), - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeTrojan, - TrojanOptions: option.TrojanOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "host.docker.internal", - ServerPort: otherPort, - }, - Password: userID.String(), - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - DialerOptions: option.DialerOptions{ - Detour: "vless", - }, - }, - }, - { - Type: C.TypeVLESS, - Tag: "vless", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userID.String(), - Flow: flow, - PacketEncoding: &packetEncoding, - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - }, - }, - { - Type: C.TypeDirect, - Tag: "direct", - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"trojan"}, - Outbound: "direct", - }, - }, - }, - }, - }) - - testSuit(t, clientPort, testPort) -} - -func TestVLESSSelf(t *testing.T) { - t.Run("origin", func(t *testing.T) { - testVLESSSelf(t, "") - }) - t.Run("vision", func(t *testing.T) { - testVLESSSelf(t, vless.FlowVision) - }) - t.Run("vision-tls", func(t *testing.T) { - testVLESSSelfTLS(t, vless.FlowVision) - }) -} - -func testVLESSSelf(t *testing.T, flow string) { - _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - - userUUID := newUUID() - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userUUID.String(), - Flow: flow, - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeDirect, - }, - { - Type: C.TypeVLESS, - Tag: "vless-out", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userUUID.String(), - Flow: flow, - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - }, - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"mixed-in"}, - Outbound: "vless-out", - }, - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} - -func testVLESSSelfTLS(t *testing.T, flow string) { - _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - - userUUID := newUUID() - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userUUID.String(), - Flow: flow, - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - { - Type: C.TypeTrojan, - Tag: "trojan", - TrojanOptions: option.TrojanInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: otherPort, - }, - Users: []option.TrojanUser{ - { - Name: "sekai", - Password: userUUID.String(), - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeDirect, - }, - { - Type: C.TypeTrojan, - Tag: "trojan-out", - TrojanOptions: option.TrojanOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: otherPort, - }, - Password: userUUID.String(), - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - DialerOptions: option.DialerOptions{ - Detour: "vless-out", - }, - }, - }, - { - Type: C.TypeVLESS, - Tag: "vless-out", - VLESSOptions: option.VLESSOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - UUID: userUUID.String(), - Flow: flow, - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - }, - }, - }, - Route: &option.RouteOptions{ - Rules: []option.Rule{ - { - DefaultOptions: option.DefaultRule{ - Inbound: []string{"mixed-in"}, - Outbound: "trojan-out", - }, - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} - -func TestVLESSXrayInbound(t *testing.T) { - testVLESSXrayInbound(t, vless.FlowVision) -} - -func testVLESSXrayInbound(t *testing.T, flow string) { - userId, err := uuid.DefaultGenerator.NewV4() - require.NoError(t, err) - _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") - - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeVLESS, - VLESSOptions: option.VLESSInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: serverPort, - }, - Users: []option.VLESSUser{ - { - Name: "sekai", - UUID: userId.String(), - Flow: flow, - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - { - Type: C.TypeTrojan, - Tag: "trojan", - TrojanOptions: option.TrojanInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: otherPort, - }, - Users: []option.TrojanUser{ - { - Name: "sekai", - Password: userId.String(), - }, - }, - InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{ - TLS: &option.InboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - KeyPath: keyPem, - }, - }, - }, - }, - }, - }) - - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - Tag: "mixed-in", - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: otherClientPort, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeTrojan, - Tag: "trojan-out", - TrojanOptions: option.TrojanOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: otherPort, - }, - Password: userId.String(), - OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ - TLS: &option.OutboundTLSOptions{ - Enabled: true, - ServerName: "example.org", - CertificatePath: certPem, - }, - }, - DialerOptions: option.DialerOptions{ - Detour: "vless-out", - }, - }, - }, - { - Type: C.TypeSOCKS, - Tag: "vless-out", - SocksOptions: option.SocksOutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: clientPort, - }, - }, - }, - }, - }) - - content, err := os.ReadFile("config/vless-tls-client.json") - require.NoError(t, err) - config, err := ajson.Unmarshal(content) - require.NoError(t, err) - - config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort)) - outbound := config.MustKey("outbounds").MustIndex(0) - settings := outbound.MustKey("settings").MustKey("vnext").MustIndex(0) - settings.MustKey("port").SetNumeric(float64(serverPort)) - user := settings.MustKey("users").MustIndex(0) - user.MustKey("id").SetString(userId.String()) - user.MustKey("flow").SetString(flow) - content, err = ajson.Marshal(config) - require.NoError(t, err) - - content, err = ajson.Marshal(config) - require.NoError(t, err) - - startDockerContainer(t, DockerOptions{ - Image: ImageXRayCore, - Ports: []uint16{clientPort}, - EntryPoint: "xray", - Stdin: content, - Bind: map[string]string{ - certPem: "/path/to/certificate.crt", - keyPem: "/path/to/private.key", - }, - }) - testTCP(t, otherClientPort, testPort) -}