mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-10-21 03:23:08 +00:00
Use Prefixable for ip_cidr rule options
This commit is contained in:
parent
2f10bfc8ea
commit
c8d9ae4acf
10 changed files with 61 additions and 343 deletions
|
|
@ -1,284 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/shell"
|
||||
)
|
||||
|
||||
var iperf3Path string
|
||||
|
||||
func main() {
|
||||
err := main0()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main0() error {
|
||||
err := shell.Exec("sudo", "ls").Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := runTests()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder := json.NewEncoder(os.Stdout)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(results)
|
||||
}
|
||||
|
||||
func runTests() ([]TestResult, error) {
|
||||
boxPaths := []string{
|
||||
os.ExpandEnv("$HOME/Downloads/sing-box-1.11.15-darwin-arm64/sing-box"),
|
||||
//"/Users/sekai/Downloads/sing-box-1.11.15-linux-arm64/sing-box",
|
||||
"./sing-box",
|
||||
}
|
||||
stacks := []string{
|
||||
"gvisor",
|
||||
"system",
|
||||
}
|
||||
mtus := []int{
|
||||
1500,
|
||||
4064,
|
||||
// 16384,
|
||||
// 32768,
|
||||
// 49152,
|
||||
65535,
|
||||
}
|
||||
flagList := [][]string{
|
||||
{},
|
||||
}
|
||||
var results []TestResult
|
||||
for _, boxPath := range boxPaths {
|
||||
for _, stack := range stacks {
|
||||
for _, mtu := range mtus {
|
||||
if strings.HasPrefix(boxPath, ".") {
|
||||
for _, flags := range flagList {
|
||||
result, err := testOnce(boxPath, stack, mtu, false, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
} else {
|
||||
result, err := testOnce(boxPath, stack, mtu, false, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
type TestResult struct {
|
||||
BoxPath string `json:"box_path"`
|
||||
Stack string `json:"stack"`
|
||||
MTU int `json:"mtu"`
|
||||
Flags []string `json:"flags"`
|
||||
MultiThread bool `json:"multi_thread"`
|
||||
UploadSpeed string `json:"upload_speed"`
|
||||
DownloadSpeed string `json:"download_speed"`
|
||||
}
|
||||
|
||||
func testOnce(boxPath string, stackName string, mtu int, multiThread bool, flags []string) (result *TestResult, err error) {
|
||||
testAddress := netip.MustParseAddr("1.1.1.1")
|
||||
testConfig := option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeTun,
|
||||
Options: &option.TunInboundOptions{
|
||||
Address: []netip.Prefix{netip.MustParsePrefix("172.18.0.1/30")},
|
||||
AutoRoute: true,
|
||||
MTU: uint32(mtu),
|
||||
Stack: stackName,
|
||||
RouteAddress: []netip.Prefix{netip.PrefixFrom(testAddress, testAddress.BitLen())},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
IPCIDR: []string{testAddress.String()},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRouteOptions,
|
||||
RouteOptionsOptions: option.RouteOptionsActionOptions{
|
||||
OverrideAddress: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AutoDetectInterface: true,
|
||||
},
|
||||
}
|
||||
ctx := include.Context(context.Background())
|
||||
tempConfig, err := os.CreateTemp("", "tun-bench-*.json")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer os.Remove(tempConfig.Name())
|
||||
encoder := json.NewEncoderContext(ctx, tempConfig)
|
||||
encoder.SetIndent("", " ")
|
||||
err = encoder.Encode(testConfig)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "encode test config")
|
||||
}
|
||||
tempConfig.Close()
|
||||
var sudoArgs []string
|
||||
if len(flags) > 0 {
|
||||
sudoArgs = append(sudoArgs, "env")
|
||||
sudoArgs = append(sudoArgs, flags...)
|
||||
}
|
||||
sudoArgs = append(sudoArgs, boxPath, "run", "-c", tempConfig.Name())
|
||||
boxProcess := shell.Exec("sudo", sudoArgs...)
|
||||
boxProcess.Stdout = &stderrWriter{}
|
||||
boxProcess.Stderr = io.Discard
|
||||
err = boxProcess.Start()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if C.IsDarwin {
|
||||
iperf3Path, err = exec.LookPath("iperf3-darwin")
|
||||
} else {
|
||||
iperf3Path, err = exec.LookPath("iperf3")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverProcess := shell.Exec(iperf3Path, "-s")
|
||||
serverProcess.Stdout = io.Discard
|
||||
serverProcess.Stderr = io.Discard
|
||||
err = serverProcess.Start()
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "start iperf3 server")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
args := []string{"-c", testAddress.String()}
|
||||
if multiThread {
|
||||
args = append(args, "-P", "10")
|
||||
}
|
||||
|
||||
uploadProcess := shell.Exec(iperf3Path, args...)
|
||||
output, err := uploadProcess.Read()
|
||||
if err != nil {
|
||||
boxProcess.Process.Signal(syscall.SIGKILL)
|
||||
serverProcess.Process.Signal(syscall.SIGKILL)
|
||||
println(output)
|
||||
return
|
||||
}
|
||||
|
||||
uploadResult := common.SubstringBeforeLast(output, "iperf Done.")
|
||||
uploadResult = common.SubstringBeforeLast(uploadResult, "sender")
|
||||
uploadResult = common.SubstringBeforeLast(uploadResult, "bits/sec")
|
||||
uploadResult = common.SubstringAfterLast(uploadResult, "Bytes")
|
||||
uploadResult = strings.ReplaceAll(uploadResult, " ", "")
|
||||
|
||||
result = &TestResult{
|
||||
BoxPath: boxPath,
|
||||
Stack: stackName,
|
||||
MTU: mtu,
|
||||
Flags: flags,
|
||||
MultiThread: multiThread,
|
||||
UploadSpeed: uploadResult,
|
||||
}
|
||||
|
||||
downloadProcess := shell.Exec(iperf3Path, append(args, "-R")...)
|
||||
output, err = downloadProcess.Read()
|
||||
if err != nil {
|
||||
boxProcess.Process.Signal(syscall.SIGKILL)
|
||||
serverProcess.Process.Signal(syscall.SIGKILL)
|
||||
println(output)
|
||||
return
|
||||
}
|
||||
|
||||
downloadResult := common.SubstringBeforeLast(output, "iperf Done.")
|
||||
downloadResult = common.SubstringBeforeLast(downloadResult, "receiver")
|
||||
downloadResult = common.SubstringBeforeLast(downloadResult, "bits/sec")
|
||||
downloadResult = common.SubstringAfterLast(downloadResult, "Bytes")
|
||||
downloadResult = strings.ReplaceAll(downloadResult, " ", "")
|
||||
|
||||
result.DownloadSpeed = downloadResult
|
||||
|
||||
printArgs := []any{boxPath, stackName, mtu, "upload", uploadResult, "download", downloadResult}
|
||||
if len(flags) > 0 {
|
||||
printArgs = append(printArgs, "flags", strings.Join(flags, " "))
|
||||
}
|
||||
if multiThread {
|
||||
printArgs = append(printArgs, "(-P 10)")
|
||||
}
|
||||
fmt.Println(printArgs...)
|
||||
err = boxProcess.Process.Signal(syscall.SIGTERM)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = serverProcess.Process.Signal(syscall.SIGTERM)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
boxDone := make(chan struct{})
|
||||
go func() {
|
||||
boxProcess.Cmd.Wait()
|
||||
close(boxDone)
|
||||
}()
|
||||
|
||||
serverDone := make(chan struct{})
|
||||
go func() {
|
||||
serverProcess.Process.Wait()
|
||||
close(serverDone)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-boxDone:
|
||||
case <-time.After(2 * time.Second):
|
||||
boxProcess.Process.Kill()
|
||||
case <-time.After(4 * time.Second):
|
||||
println("box process did not close!")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-serverDone:
|
||||
case <-time.After(2 * time.Second):
|
||||
serverProcess.Process.Kill()
|
||||
case <-time.After(4 * time.Second):
|
||||
println("server process did not close!")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type stderrWriter struct{}
|
||||
|
||||
func (w *stderrWriter) Write(p []byte) (n int, err error) {
|
||||
return os.Stderr.Write(p)
|
||||
}
|
||||
|
|
@ -9,11 +9,14 @@ import (
|
|||
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"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
"github.com/spf13/cobra"
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
var flagGeoipExportOutput string
|
||||
|
|
@ -83,9 +86,13 @@ func geoipExport(countryCode string) error {
|
|||
encoder := json.NewEncoder(outputWriter)
|
||||
encoder.SetIndent("", " ")
|
||||
var headlessRule option.DefaultHeadlessRule
|
||||
headlessRule.IPCIDR = make([]string, 0, len(ipNets))
|
||||
headlessRule.IPCIDR = make([]*badoption.Prefixable, 0, len(ipNets))
|
||||
for _, cidr := range ipNets {
|
||||
headlessRule.IPCIDR = append(headlessRule.IPCIDR, cidr.String())
|
||||
prefix, loaded := netipx.FromStdIPNet(cidr)
|
||||
if !loaded {
|
||||
return E.New("invalid network: ", cidr)
|
||||
}
|
||||
headlessRule.IPCIDR = append(headlessRule.IPCIDR, common.Ptr(badoption.Prefixable(prefix)))
|
||||
}
|
||||
var plainRuleSet option.PlainRuleSetCompat
|
||||
plainRuleSet.Version = C.RuleSetVersion2
|
||||
|
|
|
|||
|
|
@ -206,7 +206,9 @@ func readDefaultRule(reader varbin.Reader, recover bool, mmap *mmapReader) (rule
|
|||
return
|
||||
}
|
||||
if recover {
|
||||
rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), netip.Prefix.String)
|
||||
rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), func(it netip.Prefix) *badoption.Prefixable {
|
||||
return common.Ptr(badoption.Prefixable(it))
|
||||
})
|
||||
}
|
||||
case ruleItemIPCIDR:
|
||||
if mmap != nil {
|
||||
|
|
@ -218,7 +220,9 @@ func readDefaultRule(reader varbin.Reader, recover bool, mmap *mmapReader) (rule
|
|||
return
|
||||
}
|
||||
if recover {
|
||||
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
|
||||
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), func(it netip.Prefix) *badoption.Prefixable {
|
||||
return common.Ptr(badoption.Prefixable(it))
|
||||
})
|
||||
}
|
||||
case ruleItemSourcePort:
|
||||
rule.SourcePort, err = varbin.ReadSlice[uint16](reader, binary.BigEndian)
|
||||
|
|
@ -621,22 +625,12 @@ func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) e
|
|||
return binary.Write(writer, binary.BigEndian, value)
|
||||
}
|
||||
|
||||
func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string, rawSet *ipset.Set, mmap *mmapWriter) error {
|
||||
func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []*badoption.Prefixable, rawSet *ipset.Set, mmap *mmapWriter) error {
|
||||
set := rawSet
|
||||
if len(value) > 0 {
|
||||
var builder netipx.IPSetBuilder
|
||||
for i, prefixString := range value {
|
||||
prefix, err := netip.ParsePrefix(prefixString)
|
||||
if err == nil {
|
||||
builder.AddPrefix(prefix)
|
||||
continue
|
||||
}
|
||||
addr, addrErr := netip.ParseAddr(prefixString)
|
||||
if addrErr == nil {
|
||||
builder.Add(addr)
|
||||
continue
|
||||
}
|
||||
return E.Cause(err, "parse [", i, "]")
|
||||
for _, prefixable := range value {
|
||||
builder.AddPrefix(prefixable.Build(netip.Prefix{}))
|
||||
}
|
||||
ipSet, err := builder.IPSet()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
@ -25,7 +26,11 @@ func TestMmapMatchesSource(t *testing.T) {
|
|||
DefaultOptions: option.DefaultHeadlessRule{
|
||||
Domain: badoption.Listable[string]{"example.com"},
|
||||
DomainSuffix: badoption.Listable[string]{".example.org"},
|
||||
IPCIDR: badoption.Listable[string]{"10.0.0.0/8", "2001:db8::/32", "192.0.2.1"},
|
||||
IPCIDR: badoption.Listable[*badoption.Prefixable]{
|
||||
common.Ptr(badoption.Prefixable(netip.MustParsePrefix("10.0.0.0/8"))),
|
||||
common.Ptr(badoption.Prefixable(netip.MustParsePrefix("2001:db8::/32"))),
|
||||
common.Ptr(badoption.Prefixable(netip.MustParsePrefix("192.0.2.1/32"))),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -36,7 +41,7 @@ func TestMmapMatchesSource(t *testing.T) {
|
|||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultHeadlessRule{
|
||||
AdGuardDomain: badoption.Listable[string]{"||ads.example.net^"},
|
||||
SourceIPCIDR: badoption.Listable[string]{"172.16.0.0/12"},
|
||||
SourceIPCIDR: badoption.Listable[*badoption.Prefixable]{common.Ptr(badoption.Prefixable(netip.MustParsePrefix("172.16.0.0/12")))},
|
||||
},
|
||||
}},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ type RawDefaultRule struct {
|
|||
Geosite badoption.Listable[string] `json:"geosite,omitempty" schema:"omit"`
|
||||
SourceGeoIP badoption.Listable[string] `json:"source_geoip,omitempty" schema:"omit"`
|
||||
GeoIP badoption.Listable[string] `json:"geoip,omitempty" schema:"omit"`
|
||||
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty" schema:"prefixable"`
|
||||
SourceIPCIDR badoption.Listable[*badoption.Prefixable] `json:"source_ip_cidr,omitempty"`
|
||||
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
||||
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty" schema:"prefixable"`
|
||||
IPCIDR badoption.Listable[*badoption.Prefixable] `json:"ip_cidr,omitempty"`
|
||||
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
||||
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ type RawDefaultDNSRule struct {
|
|||
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty" schema:"prefixable"`
|
||||
SourceIPCIDR badoption.Listable[*badoption.Prefixable] `json:"source_ip_cidr,omitempty"`
|
||||
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
||||
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||
|
|
@ -176,7 +176,7 @@ type RawDefaultDNSRule struct {
|
|||
RuleSet badoption.Listable[string] `json:"rule_set,omitempty" reference:"rule_set"`
|
||||
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
||||
MatchResponse *DNSRuleMatchResponse `json:"match_response,omitempty"`
|
||||
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty" schema:"prefixable"`
|
||||
IPCIDR badoption.Listable[*badoption.Prefixable] `json:"ip_cidr,omitempty"`
|
||||
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
||||
IPAcceptAny bool `json:"ip_accept_any,omitempty"`
|
||||
ResponseRcode *DNSRCode `json:"response_rcode,omitempty"`
|
||||
|
|
|
|||
|
|
@ -254,8 +254,8 @@ type DefaultHeadlessRule struct {
|
|||
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty" schema:"prefixable"`
|
||||
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty" schema:"prefixable"`
|
||||
SourceIPCIDR badoption.Listable[*badoption.Prefixable] `json:"source_ip_cidr,omitempty"`
|
||||
IPCIDR badoption.Listable[*badoption.Prefixable] `json:"ip_cidr,omitempty"`
|
||||
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/ipset"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
|
@ -21,20 +21,10 @@ type IPCIDRItem struct {
|
|||
description string
|
||||
}
|
||||
|
||||
func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
||||
func NewIPCIDRItem(isSource bool, prefixables []*badoption.Prefixable) (*IPCIDRItem, error) {
|
||||
var builder netipx.IPSetBuilder
|
||||
for i, prefixString := range prefixStrings {
|
||||
prefix, err := netip.ParsePrefix(prefixString)
|
||||
if err == nil {
|
||||
builder.AddPrefix(prefix)
|
||||
continue
|
||||
}
|
||||
addr, addrErr := netip.ParseAddr(prefixString)
|
||||
if addrErr == nil {
|
||||
builder.Add(addr)
|
||||
continue
|
||||
}
|
||||
return nil, E.Cause(err, "parse [", i, "]")
|
||||
for _, prefixable := range prefixables {
|
||||
builder.AddPrefix(prefixable.Build(netip.Prefix{}))
|
||||
}
|
||||
var description string
|
||||
if isSource {
|
||||
|
|
@ -42,12 +32,15 @@ func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
|||
} else {
|
||||
description = "ip_cidr="
|
||||
}
|
||||
if dLen := len(prefixStrings); dLen == 1 {
|
||||
description += prefixStrings[0]
|
||||
} else if dLen > 3 {
|
||||
description += "[" + strings.Join(prefixStrings[:3], " ") + "...]"
|
||||
prefixString := func(it *badoption.Prefixable) string {
|
||||
return it.Build(netip.Prefix{}).String()
|
||||
}
|
||||
if prefixCount := len(prefixables); prefixCount == 1 {
|
||||
description += prefixString(prefixables[0])
|
||||
} else if prefixCount > 3 {
|
||||
description += "[" + strings.Join(common.Map(prefixables[:3], prefixString), " ") + "...]"
|
||||
} else {
|
||||
description += "[" + strings.Join(prefixStrings, " ") + "]"
|
||||
description += "[" + strings.Join(common.Map(prefixables, prefixString), " ") + "]"
|
||||
}
|
||||
ipSet, err := builder.IPSet()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import (
|
|||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/convertor/adguard"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
slogger "github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
|
@ -1432,7 +1434,7 @@ func addOtherItem(rule *abstractDefaultRule, item RuleItem) {
|
|||
|
||||
func addSourceAddressItem(t *testing.T, rule *abstractDefaultRule, cidrs []string) {
|
||||
t.Helper()
|
||||
item, err := NewIPCIDRItem(true, cidrs)
|
||||
item, err := NewIPCIDRItem(true, parsePrefixables(cidrs))
|
||||
require.NoError(t, err)
|
||||
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
|
|
@ -1462,7 +1464,7 @@ func addDestinationRegexItem(t *testing.T, rule *abstractDefaultRule, regexes []
|
|||
|
||||
func addDestinationIPCIDRItem(t *testing.T, rule *abstractDefaultRule, cidrs []string) {
|
||||
t.Helper()
|
||||
item, err := NewIPCIDRItem(false, cidrs)
|
||||
item, err := NewIPCIDRItem(false, parsePrefixables(cidrs))
|
||||
require.NoError(t, err)
|
||||
rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
|
|
@ -1507,3 +1509,9 @@ func addDestinationPortRangeItem(t *testing.T, rule *abstractDefaultRule, ranges
|
|||
rule.destinationPortItems = append(rule.destinationPortItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func parsePrefixables(cidrs []string) []*badoption.Prefixable {
|
||||
return common.Map(cidrs, func(it string) *badoption.Prefixable {
|
||||
return common.Ptr(badoption.Prefixable(netip.MustParsePrefix(it)))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,9 @@ func (g *generator) FlattenStruct(node *Node, structType reflect.Type) error {
|
|||
if schemaTag == "omit" {
|
||||
continue
|
||||
}
|
||||
if schemaTag != "" {
|
||||
return E.New("unknown schema tag ", schemaTag, " on ", structType.Name(), ".", field.Name)
|
||||
}
|
||||
if field.Anonymous && tagName == "" {
|
||||
err := g.FlattenStruct(node, fieldType)
|
||||
if err != nil {
|
||||
|
|
@ -241,8 +244,8 @@ func (g *generator) FlattenStruct(node *Node, structType reflect.Type) error {
|
|||
g.path = append(g.path, structType.Name()+"."+tagName)
|
||||
var fieldNode *Node
|
||||
var err error
|
||||
if enumTag != "" || examplesTag != "" || referenceTag != "" || schemaTag != "" {
|
||||
fieldNode, err = g.taggedFieldNode(fieldType, enumTag, examplesTag, referenceTag, schemaTag)
|
||||
if enumTag != "" || examplesTag != "" || referenceTag != "" {
|
||||
fieldNode, err = g.taggedFieldNode(fieldType, enumTag, examplesTag, referenceTag)
|
||||
} else {
|
||||
fieldNode, err = g.Describe(fieldType)
|
||||
}
|
||||
|
|
@ -255,7 +258,7 @@ func (g *generator) FlattenStruct(node *Node, structType reflect.Type) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (g *generator) taggedFieldNode(fieldType reflect.Type, enumTag string, examplesTag string, referenceTag string, schemaTag string) (*Node, error) {
|
||||
func (g *generator) taggedFieldNode(fieldType reflect.Type, enumTag string, examplesTag string, referenceTag string) (*Node, error) {
|
||||
elementType := fieldType
|
||||
for elementType.Kind() == reflect.Pointer {
|
||||
elementType = elementType.Elem()
|
||||
|
|
@ -269,17 +272,9 @@ func (g *generator) taggedFieldNode(fieldType reflect.Type, enumTag string, exam
|
|||
}
|
||||
var element *Node
|
||||
var err error
|
||||
switch {
|
||||
case enumTag != "":
|
||||
if enumTag != "" {
|
||||
element, err = taggedValueNode(elementType, strings.Split(enumTag, ","))
|
||||
case schemaTag == "prefixable":
|
||||
if elementType.Kind() != reflect.String {
|
||||
return nil, E.New("prefixable schema tags require a string field, got ", fieldType.String())
|
||||
}
|
||||
element, err = g.Describe(prefixableType)
|
||||
case schemaTag != "":
|
||||
return nil, E.New("unknown schema tag ", schemaTag, " on ", fieldType.String())
|
||||
default:
|
||||
} else {
|
||||
element, err = g.Describe(elementType)
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue