فهرست منبع

Fix decompile rule-set

世界 1 سال پیش
والد
کامیت
e3e203844e

+ 1 - 6
cmd/sing-box/cmd_rule_set_compile.go

@@ -6,7 +6,6 @@ import (
 	"strings"
 
 	"github.com/sagernet/sing-box/common/srs"
-	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/log"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing/common/json"
@@ -56,10 +55,6 @@ func compileRuleSet(sourcePath string) error {
 	if err != nil {
 		return err
 	}
-	ruleSet, err := plainRuleSet.Upgrade()
-	if err != nil {
-		return err
-	}
 	var outputPath string
 	if flagRuleSetCompileOutput == flagRuleSetCompileDefaultOutput {
 		if strings.HasSuffix(sourcePath, ".json") {
@@ -74,7 +69,7 @@ func compileRuleSet(sourcePath string) error {
 	if err != nil {
 		return err
 	}
-	err = srs.Write(outputFile, ruleSet, plainRuleSet.Version == C.RuleSetVersion2)
+	err = srs.Write(outputFile, plainRuleSet.Options, plainRuleSet.Version)
 	if err != nil {
 		outputFile.Close()
 		os.Remove(outputPath)

+ 2 - 1
cmd/sing-box/cmd_rule_set_convert.go

@@ -7,6 +7,7 @@ import (
 
 	"github.com/sagernet/sing-box/cmd/sing-box/internal/convertor/adguard"
 	"github.com/sagernet/sing-box/common/srs"
+	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/log"
 	"github.com/sagernet/sing-box/option"
 	E "github.com/sagernet/sing/common/exceptions"
@@ -77,7 +78,7 @@ func convertRuleSet(sourcePath string) error {
 		return err
 	}
 	defer outputFile.Close()
-	err = srs.Write(outputFile, option.PlainRuleSet{Rules: rules}, true)
+	err = srs.Write(outputFile, option.PlainRuleSet{Rules: rules}, C.RuleSetVersion2)
 	if err != nil {
 		outputFile.Close()
 		os.Remove(outputPath)

+ 1 - 7
cmd/sing-box/cmd_rule_set_decompile.go

@@ -6,9 +6,7 @@ import (
 	"strings"
 
 	"github.com/sagernet/sing-box/common/srs"
-	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/log"
-	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing/common/json"
 
 	"github.com/spf13/cobra"
@@ -48,14 +46,10 @@ func decompileRuleSet(sourcePath string) error {
 			return err
 		}
 	}
-	plainRuleSet, err := srs.Read(reader, true)
+	ruleSet, err := srs.Read(reader, true)
 	if err != nil {
 		return err
 	}
-	ruleSet := option.PlainRuleSetCompat{
-		Version: C.RuleSetVersion1,
-		Options: plainRuleSet,
-	}
 	var outputPath string
 	if flagRuleSetDecompileOutput == flagRuleSetDecompileDefaultOutput {
 		if strings.HasSuffix(sourcePath, ".srs") {

+ 7 - 8
cmd/sing-box/cmd_rule_set_match.go

@@ -55,26 +55,25 @@ func ruleSetMatch(sourcePath string, domain string) error {
 	if err != nil {
 		return E.Cause(err, "read rule-set")
 	}
-	var plainRuleSet option.PlainRuleSet
+	var ruleSet option.PlainRuleSetCompat
 	switch flagRuleSetMatchFormat {
 	case C.RuleSetFormatSource:
-		var compat option.PlainRuleSetCompat
-		compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
-		if err != nil {
-			return err
-		}
-		plainRuleSet, err = compat.Upgrade()
+		ruleSet, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
 		if err != nil {
 			return err
 		}
 	case C.RuleSetFormatBinary:
-		plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
+		ruleSet, err = srs.Read(bytes.NewReader(content), false)
 		if err != nil {
 			return err
 		}
 	default:
 		return E.New("unknown rule-set format: ", flagRuleSetMatchFormat)
 	}
+	plainRuleSet, err := ruleSet.Upgrade()
+	if err != nil {
+		return err
+	}
 	ipAddress := M.ParseAddr(domain)
 	var metadata adapter.InboundContext
 	if ipAddress.IsValid() {

+ 20 - 22
common/srs/binary.go

@@ -41,7 +41,7 @@ const (
 	ruleItemFinal uint8 = 0xFF
 )
 
-func Read(reader io.Reader, recover bool) (ruleSet option.PlainRuleSet, err error) {
+func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetCompat, err error) {
 	var magicBytes [3]byte
 	_, err = io.ReadFull(reader, magicBytes[:])
 	if err != nil {
@@ -54,10 +54,10 @@ func Read(reader io.Reader, recover bool) (ruleSet option.PlainRuleSet, err erro
 	var version uint8
 	err = binary.Read(reader, binary.BigEndian, &version)
 	if err != nil {
-		return ruleSet, err
+		return ruleSetCompat, err
 	}
-	if version > C.RuleSetVersion2 {
-		return ruleSet, E.New("unsupported version: ", version)
+	if version > C.RuleSetVersionCurrent {
+		return ruleSetCompat, E.New("unsupported version: ", version)
 	}
 	compressReader, err := zlib.NewReader(reader)
 	if err != nil {
@@ -68,9 +68,10 @@ func Read(reader io.Reader, recover bool) (ruleSet option.PlainRuleSet, err erro
 	if err != nil {
 		return
 	}
-	ruleSet.Rules = make([]option.HeadlessRule, length)
+	ruleSetCompat.Version = version
+	ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
 	for i := uint64(0); i < length; i++ {
-		ruleSet.Rules[i], err = readRule(bReader, recover)
+		ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
 		if err != nil {
 			err = E.Cause(err, "read rule[", i, "]")
 			return
@@ -79,18 +80,12 @@ func Read(reader io.Reader, recover bool) (ruleSet option.PlainRuleSet, err erro
 	return
 }
 
-func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateUnstable bool) error {
+func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateVersion uint8) error {
 	_, err := writer.Write(MagicBytes[:])
 	if err != nil {
 		return err
 	}
-	var version uint8
-	if generateUnstable {
-		version = C.RuleSetVersion2
-	} else {
-		version = C.RuleSetVersion1
-	}
-	err = binary.Write(writer, binary.BigEndian, version)
+	err = binary.Write(writer, binary.BigEndian, generateVersion)
 	if err != nil {
 		return err
 	}
@@ -104,7 +99,7 @@ func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateUnstable bool)
 		return err
 	}
 	for _, rule := range ruleSet.Rules {
-		err = writeRule(bWriter, rule, generateUnstable)
+		err = writeRule(bWriter, rule, generateVersion)
 		if err != nil {
 			return err
 		}
@@ -135,12 +130,12 @@ func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err
 	return
 }
 
-func writeRule(writer varbin.Writer, rule option.HeadlessRule, generateUnstable bool) error {
+func writeRule(writer varbin.Writer, rule option.HeadlessRule, generateVersion uint8) error {
 	switch rule.Type {
 	case C.RuleTypeDefault:
-		return writeDefaultRule(writer, rule.DefaultOptions, generateUnstable)
+		return writeDefaultRule(writer, rule.DefaultOptions, generateVersion)
 	case C.RuleTypeLogical:
-		return writeLogicalRule(writer, rule.LogicalOptions, generateUnstable)
+		return writeLogicalRule(writer, rule.LogicalOptions, generateVersion)
 	default:
 		panic("unknown rule type: " + rule.Type)
 	}
@@ -240,7 +235,7 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
 	}
 }
 
-func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, generateUnstable bool) error {
+func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, generateVersion uint8) error {
 	err := binary.Write(writer, binary.BigEndian, uint8(0))
 	if err != nil {
 		return err
@@ -264,7 +259,7 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
 		if err != nil {
 			return err
 		}
-		err = domain.NewMatcher(rule.Domain, rule.DomainSuffix, !generateUnstable).Write(writer)
+		err = domain.NewMatcher(rule.Domain, rule.DomainSuffix, generateVersion == C.RuleSetVersion1).Write(writer)
 		if err != nil {
 			return err
 		}
@@ -354,6 +349,9 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
 		}
 	}
 	if len(rule.AdGuardDomain) > 0 {
+		if generateVersion < C.RuleSetVersion2 {
+			return E.New("AdGuard rule items is only supported in version 2 or later")
+		}
 		err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain)
 		if err != nil {
 			return err
@@ -457,7 +455,7 @@ func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.Lo
 	return
 }
 
-func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateUnstable bool) error {
+func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateVersion uint8) error {
 	err := binary.Write(writer, binary.BigEndian, uint8(1))
 	if err != nil {
 		return err
@@ -478,7 +476,7 @@ func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRu
 		return err
 	}
 	for _, rule := range logicalRule.Rules {
-		err = writeRule(writer, rule, generateUnstable)
+		err = writeRule(writer, rule, generateVersion)
 		if err != nil {
 			return err
 		}

+ 1 - 0
constant/rule.go

@@ -21,4 +21,5 @@ const (
 const (
 	RuleSetVersion1 = 1 + iota
 	RuleSetVersion2
+	RuleSetVersionCurrent = RuleSetVersion2
 )

+ 1 - 1
option/rule_set.go

@@ -189,7 +189,7 @@ func (r LogicalHeadlessRule) IsValid() bool {
 }
 
 type _PlainRuleSetCompat struct {
-	Version int          `json:"version"`
+	Version uint8        `json:"version"`
 	Options PlainRuleSet `json:"-"`
 }
 

+ 8 - 7
route/rule_set_local.go

@@ -95,33 +95,34 @@ func (s *LocalRuleSet) StartContext(ctx context.Context, startContext *adapter.H
 }
 
 func (s *LocalRuleSet) reloadFile(path string) error {
-	var plainRuleSet option.PlainRuleSet
+	var ruleSet option.PlainRuleSetCompat
 	switch s.fileFormat {
 	case C.RuleSetFormatSource, "":
 		content, err := os.ReadFile(path)
 		if err != nil {
 			return err
 		}
-		compat, err := json.UnmarshalExtended[option.PlainRuleSetCompat](content)
-		if err != nil {
-			return err
-		}
-		plainRuleSet, err = compat.Upgrade()
+		ruleSet, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
 		if err != nil {
 			return err
 		}
+
 	case C.RuleSetFormatBinary:
 		setFile, err := os.Open(path)
 		if err != nil {
 			return err
 		}
-		plainRuleSet, err = srs.Read(setFile, false)
+		ruleSet, err = srs.Read(setFile, false)
 		if err != nil {
 			return err
 		}
 	default:
 		return E.New("unknown rule-set format: ", s.fileFormat)
 	}
+	plainRuleSet, err := ruleSet.Upgrade()
+	if err != nil {
+		return err
+	}
 	return s.reloadRules(plainRuleSet.Rules)
 }
 

+ 8 - 9
route/rule_set_remote.go

@@ -159,28 +159,27 @@ func (s *RemoteRuleSet) UnregisterCallback(element *list.Element[adapter.RuleSet
 
 func (s *RemoteRuleSet) loadBytes(content []byte) error {
 	var (
-		plainRuleSet option.PlainRuleSet
-		err          error
+		ruleSet option.PlainRuleSetCompat
+		err     error
 	)
 	switch s.options.Format {
 	case C.RuleSetFormatSource:
-		var compat option.PlainRuleSetCompat
-		compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
-		if err != nil {
-			return err
-		}
-		plainRuleSet, err = compat.Upgrade()
+		ruleSet, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
 		if err != nil {
 			return err
 		}
 	case C.RuleSetFormatBinary:
-		plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
+		ruleSet, err = srs.Read(bytes.NewReader(content), false)
 		if err != nil {
 			return err
 		}
 	default:
 		return E.New("unknown rule-set format: ", s.options.Format)
 	}
+	plainRuleSet, err := ruleSet.Upgrade()
+	if err != nil {
+		return err
+	}
 	rules := make([]adapter.HeadlessRule, len(plainRuleSet.Rules))
 	for i, ruleOptions := range plainRuleSet.Rules {
 		rules[i], err = NewHeadlessRule(s.router, ruleOptions)