diff --git a/docs/configuration/dns/rule.md b/docs/configuration/dns/rule.md index 2a3a7ff0..801edacc 100644 --- a/docs/configuration/dns/rule.md +++ b/docs/configuration/dns/rule.md @@ -38,7 +38,8 @@ "private" ], "source_ip_cidr": [ - "10.0.0.0/24" + "10.0.0.0/24", + "192.168.0.1" ], "source_port": [ 12345 diff --git a/docs/configuration/route/rule.md b/docs/configuration/route/rule.md index 04b53b84..c9f9bba0 100644 --- a/docs/configuration/route/rule.md +++ b/docs/configuration/route/rule.md @@ -41,10 +41,12 @@ "cn" ], "source_ip_cidr": [ - "10.0.0.0/24" + "10.0.0.0/24", + "192.168.0.1" ], "ip_cidr": [ - "10.0.0.0/24" + "10.0.0.0/24", + "192.168.0.1" ], "source_port": [ 12345 diff --git a/go.mod b/go.mod index 8be39b48..93c6aeed 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.0 go.uber.org/atomic v1.10.0 + go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 @@ -62,11 +63,10 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.22.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index fd31d2d6..4abf17e0 100644 --- a/go.sum +++ b/go.sum @@ -181,6 +181,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= +go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d h1:ggxwEf5eu0l8v+87VhX1czFh8zJul3hK16Gmruxn7hw= +go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -199,8 +201,8 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -274,12 +276,11 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg= +golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= 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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= diff --git a/route/rule_cidr.go b/route/rule_cidr.go index 95bf0f64..b72d1e10 100644 --- a/route/rule_cidr.go +++ b/route/rule_cidr.go @@ -6,51 +6,67 @@ import ( "github.com/sagernet/sing-box/adapter" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" + + "go4.org/netipx" ) var _ RuleItem = (*IPCIDRItem)(nil) type IPCIDRItem struct { - prefixes []netip.Prefix - isSource bool + ipSet *netipx.IPSet + isSource bool + description string } func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) { - prefixes := make([]netip.Prefix, 0, len(prefixStrings)) + var builder netipx.IPSetBuilder for i, prefixString := range prefixStrings { prefix, err := netip.ParsePrefix(prefixString) - if err != nil { - return nil, E.Cause(err, "parse prefix [", i, "]") + if err == nil { + builder.AddPrefix(prefix) + continue } - prefixes = append(prefixes, prefix) + addr, addrErr := netip.ParseAddr(prefixString) + if addrErr == nil { + builder.Add(addr) + continue + } + return nil, E.Cause(err, "parse ip_cidr [", i, "]") + } + var description string + if isSource { + description = "source_ipcidr=" + } else { + description = "ipcidr=" + } + if dLen := len(prefixStrings); dLen == 1 { + description += prefixStrings[0] + } else if dLen > 3 { + description += "[" + strings.Join(prefixStrings[:3], " ") + "...]" + } else { + description += "[" + strings.Join(prefixStrings, " ") + "]" + } + ipSet, err := builder.IPSet() + if err != nil { + return nil, err } return &IPCIDRItem{ - prefixes: prefixes, - isSource: isSource, + ipSet: ipSet, + isSource: isSource, + description: description, }, nil } func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool { if r.isSource { - for _, prefix := range r.prefixes { - if prefix.Contains(metadata.Source.Addr) { - return true - } - } + return r.ipSet.Contains(metadata.Source.Addr) } else { if metadata.Destination.IsIP() { - for _, prefix := range r.prefixes { - if prefix.Contains(metadata.Destination.Addr) { - return true - } - } + return r.ipSet.Contains(metadata.Destination.Addr) } else { for _, address := range metadata.DestinationAddresses { - for _, prefix := range r.prefixes { - if prefix.Contains(address) { - return true - } + if r.ipSet.Contains(address) { + return true } } } @@ -59,17 +75,5 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool { } func (r *IPCIDRItem) String() string { - var description string - if r.isSource { - description = "source_ipcidr=" - } else { - description = "ipcidr=" - } - pLen := len(r.prefixes) - if pLen == 1 { - description += r.prefixes[0].String() - } else { - description += "[" + strings.Join(F.MapToString(r.prefixes), " ") + "]" - } - return description + return r.description }