Browse Source

Improve ip_cidr rule

世界 3 years ago
parent
commit
9f6628445e
5 changed files with 55 additions and 47 deletions
  1. 2 1
      docs/configuration/dns/rule.md
  2. 4 2
      docs/configuration/route/rule.md
  3. 3 3
      go.mod
  4. 6 5
      go.sum
  5. 40 36
      route/rule_cidr.go

+ 2 - 1
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

+ 4 - 2
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

+ 3 - 3
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

+ 6 - 5
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=

+ 40 - 36
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
+		}
+		addr, addrErr := netip.ParseAddr(prefixString)
+		if addrErr == nil {
+			builder.Add(addr)
+			continue
 		}
-		prefixes = append(prefixes, prefix)
+		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
 }