sing-box/common/srs/binary.go

490 lines
12 KiB
Go
Raw Normal View History

2023-12-01 13:24:12 +08:00
package srs
import (
2024-06-24 09:49:15 +08:00
"bufio"
2023-12-01 13:24:12 +08:00
"compress/zlib"
"encoding/binary"
"io"
"net/netip"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/domain"
E "github.com/sagernet/sing/common/exceptions"
2024-06-24 09:49:15 +08:00
"github.com/sagernet/sing/common/varbin"
2023-12-01 13:24:12 +08:00
"go4.org/netipx"
)
var MagicBytes = [3]byte{0x53, 0x52, 0x53} // SRS
const (
ruleItemQueryType uint8 = iota
ruleItemNetwork
ruleItemDomain
ruleItemDomainKeyword
ruleItemDomainRegex
ruleItemSourceIPCIDR
ruleItemIPCIDR
ruleItemSourcePort
ruleItemSourcePortRange
ruleItemPort
ruleItemPortRange
ruleItemProcessName
ruleItemProcessPath
ruleItemPackageName
ruleItemWIFISSID
ruleItemWIFIBSSID
2024-07-26 08:03:08 +08:00
ruleItemAdGuardDomain
2024-09-15 11:42:57 +08:00
ruleItemProcessPathRegex
2023-12-01 13:24:12 +08:00
ruleItemFinal uint8 = 0xFF
)
2024-11-11 16:27:28 +08:00
func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetCompat, err error) {
2023-12-01 13:24:12 +08:00
var magicBytes [3]byte
_, err = io.ReadFull(reader, magicBytes[:])
if err != nil {
return
}
if magicBytes != MagicBytes {
2024-06-26 00:45:10 +08:00
err = E.New("invalid sing-box rule-set file")
2023-12-01 13:24:12 +08:00
return
}
var version uint8
err = binary.Read(reader, binary.BigEndian, &version)
if err != nil {
2024-11-11 16:27:28 +08:00
return ruleSetCompat, err
2023-12-01 13:24:12 +08:00
}
2024-11-11 16:27:28 +08:00
if version > C.RuleSetVersionCurrent {
return ruleSetCompat, E.New("unsupported version: ", version)
2023-12-01 13:24:12 +08:00
}
2024-07-17 17:57:35 +08:00
compressReader, err := zlib.NewReader(reader)
2023-12-01 13:24:12 +08:00
if err != nil {
return
}
2024-07-17 17:57:35 +08:00
bReader := bufio.NewReader(compressReader)
2024-06-24 09:49:15 +08:00
length, err := binary.ReadUvarint(bReader)
2023-12-01 13:24:12 +08:00
if err != nil {
return
}
2024-11-11 16:27:28 +08:00
ruleSetCompat.Version = version
ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
2023-12-01 13:24:12 +08:00
for i := uint64(0); i < length; i++ {
2024-11-11 16:27:28 +08:00
ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
2023-12-01 13:24:12 +08:00
if err != nil {
err = E.Cause(err, "read rule[", i, "]")
return
}
}
return
}
2024-11-11 16:27:28 +08:00
func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateVersion uint8) error {
2023-12-01 13:24:12 +08:00
_, err := writer.Write(MagicBytes[:])
if err != nil {
return err
}
2024-11-11 16:27:28 +08:00
err = binary.Write(writer, binary.BigEndian, generateVersion)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
2024-07-17 17:57:35 +08:00
compressWriter, err := zlib.NewWriterLevel(writer, zlib.BestCompression)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
2024-07-17 17:57:35 +08:00
bWriter := bufio.NewWriter(compressWriter)
2024-06-24 09:49:15 +08:00
_, err = varbin.WriteUvarint(bWriter, uint64(len(ruleSet.Rules)))
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
for _, rule := range ruleSet.Rules {
2024-11-11 16:27:28 +08:00
err = writeRule(bWriter, rule, generateVersion)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
}
2024-06-24 09:49:15 +08:00
err = bWriter.Flush()
if err != nil {
return err
}
2024-07-17 17:57:35 +08:00
return compressWriter.Close()
2023-12-01 13:24:12 +08:00
}
2024-06-24 09:49:15 +08:00
func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err error) {
2023-12-01 13:24:12 +08:00
var ruleType uint8
err = binary.Read(reader, binary.BigEndian, &ruleType)
if err != nil {
return
}
switch ruleType {
case 0:
rule.Type = C.RuleTypeDefault
2024-06-24 09:49:15 +08:00
rule.DefaultOptions, err = readDefaultRule(reader, recover)
2023-12-01 13:24:12 +08:00
case 1:
rule.Type = C.RuleTypeLogical
2024-06-24 09:49:15 +08:00
rule.LogicalOptions, err = readLogicalRule(reader, recover)
2023-12-01 13:24:12 +08:00
default:
err = E.New("unknown rule type: ", ruleType)
}
return
}
2024-11-11 16:27:28 +08:00
func writeRule(writer varbin.Writer, rule option.HeadlessRule, generateVersion uint8) error {
2023-12-01 13:24:12 +08:00
switch rule.Type {
case C.RuleTypeDefault:
2024-11-11 16:27:28 +08:00
return writeDefaultRule(writer, rule.DefaultOptions, generateVersion)
2023-12-01 13:24:12 +08:00
case C.RuleTypeLogical:
2024-11-11 16:27:28 +08:00
return writeLogicalRule(writer, rule.LogicalOptions, generateVersion)
2023-12-01 13:24:12 +08:00
default:
panic("unknown rule type: " + rule.Type)
}
}
2024-06-24 09:49:15 +08:00
func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHeadlessRule, err error) {
2023-12-01 13:24:12 +08:00
var lastItemType uint8
for {
var itemType uint8
err = binary.Read(reader, binary.BigEndian, &itemType)
if err != nil {
return
}
switch itemType {
case ruleItemQueryType:
var rawQueryType []uint16
rawQueryType, err = readRuleItemUint16(reader)
if err != nil {
return
}
rule.QueryType = common.Map(rawQueryType, func(it uint16) option.DNSQueryType {
return option.DNSQueryType(it)
})
case ruleItemNetwork:
rule.Network, err = readRuleItemString(reader)
case ruleItemDomain:
var matcher *domain.Matcher
matcher, err = domain.ReadMatcher(reader)
if err != nil {
return
}
rule.DomainMatcher = matcher
2024-06-24 09:49:15 +08:00
if recover {
rule.Domain, rule.DomainSuffix = matcher.Dump()
}
2023-12-01 13:24:12 +08:00
case ruleItemDomainKeyword:
rule.DomainKeyword, err = readRuleItemString(reader)
case ruleItemDomainRegex:
rule.DomainRegex, err = readRuleItemString(reader)
case ruleItemSourceIPCIDR:
rule.SourceIPSet, err = readIPSet(reader)
if err != nil {
return
}
2024-06-24 09:49:15 +08:00
if recover {
2023-12-01 13:24:12 +08:00
rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), netip.Prefix.String)
}
case ruleItemIPCIDR:
rule.IPSet, err = readIPSet(reader)
if err != nil {
return
}
2024-06-24 09:49:15 +08:00
if recover {
2023-12-01 13:24:12 +08:00
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
}
case ruleItemSourcePort:
rule.SourcePort, err = readRuleItemUint16(reader)
case ruleItemSourcePortRange:
rule.SourcePortRange, err = readRuleItemString(reader)
case ruleItemPort:
rule.Port, err = readRuleItemUint16(reader)
case ruleItemPortRange:
rule.PortRange, err = readRuleItemString(reader)
case ruleItemProcessName:
rule.ProcessName, err = readRuleItemString(reader)
case ruleItemProcessPath:
rule.ProcessPath, err = readRuleItemString(reader)
2024-09-15 11:42:57 +08:00
case ruleItemProcessPathRegex:
rule.ProcessPathRegex, err = readRuleItemString(reader)
2023-12-01 13:24:12 +08:00
case ruleItemPackageName:
rule.PackageName, err = readRuleItemString(reader)
case ruleItemWIFISSID:
rule.WIFISSID, err = readRuleItemString(reader)
case ruleItemWIFIBSSID:
rule.WIFIBSSID, err = readRuleItemString(reader)
2024-07-26 08:03:08 +08:00
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
2023-12-01 13:24:12 +08:00
case ruleItemFinal:
err = binary.Read(reader, binary.BigEndian, &rule.Invert)
return
default:
err = E.New("unknown rule item type: ", itemType, ", last type: ", lastItemType)
}
if err != nil {
return
}
lastItemType = itemType
}
}
2024-11-11 16:27:28 +08:00
func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, generateVersion uint8) error {
2023-12-01 13:24:12 +08:00
err := binary.Write(writer, binary.BigEndian, uint8(0))
if err != nil {
return err
}
if len(rule.QueryType) > 0 {
err = writeRuleItemUint16(writer, ruleItemQueryType, common.Map(rule.QueryType, func(it option.DNSQueryType) uint16 {
return uint16(it)
}))
if err != nil {
return err
}
}
if len(rule.Network) > 0 {
err = writeRuleItemString(writer, ruleItemNetwork, rule.Network)
if err != nil {
return err
}
}
if len(rule.Domain) > 0 || len(rule.DomainSuffix) > 0 {
err = binary.Write(writer, binary.BigEndian, ruleItemDomain)
if err != nil {
return err
}
2024-11-11 16:27:28 +08:00
err = domain.NewMatcher(rule.Domain, rule.DomainSuffix, generateVersion == C.RuleSetVersion1).Write(writer)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
}
if len(rule.DomainKeyword) > 0 {
err = writeRuleItemString(writer, ruleItemDomainKeyword, rule.DomainKeyword)
if err != nil {
return err
}
}
if len(rule.DomainRegex) > 0 {
err = writeRuleItemString(writer, ruleItemDomainRegex, rule.DomainRegex)
if err != nil {
return err
}
}
if len(rule.SourceIPCIDR) > 0 {
err = writeRuleItemCIDR(writer, ruleItemSourceIPCIDR, rule.SourceIPCIDR)
if err != nil {
2024-01-14 13:01:57 +08:00
return E.Cause(err, "source_ip_cidr")
2023-12-01 13:24:12 +08:00
}
}
if len(rule.IPCIDR) > 0 {
err = writeRuleItemCIDR(writer, ruleItemIPCIDR, rule.IPCIDR)
if err != nil {
return E.Cause(err, "ipcidr")
}
}
if len(rule.SourcePort) > 0 {
err = writeRuleItemUint16(writer, ruleItemSourcePort, rule.SourcePort)
if err != nil {
return err
}
}
if len(rule.SourcePortRange) > 0 {
err = writeRuleItemString(writer, ruleItemSourcePortRange, rule.SourcePortRange)
if err != nil {
return err
}
}
if len(rule.Port) > 0 {
err = writeRuleItemUint16(writer, ruleItemPort, rule.Port)
if err != nil {
return err
}
}
if len(rule.PortRange) > 0 {
err = writeRuleItemString(writer, ruleItemPortRange, rule.PortRange)
if err != nil {
return err
}
}
if len(rule.ProcessName) > 0 {
err = writeRuleItemString(writer, ruleItemProcessName, rule.ProcessName)
if err != nil {
return err
}
}
if len(rule.ProcessPath) > 0 {
err = writeRuleItemString(writer, ruleItemProcessPath, rule.ProcessPath)
if err != nil {
return err
}
}
2024-09-15 11:42:57 +08:00
if len(rule.ProcessPathRegex) > 0 {
err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
if err != nil {
return err
}
}
2023-12-01 13:24:12 +08:00
if len(rule.PackageName) > 0 {
err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
if err != nil {
return err
}
}
if len(rule.WIFISSID) > 0 {
err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
if err != nil {
return err
}
}
if len(rule.WIFIBSSID) > 0 {
err = writeRuleItemString(writer, ruleItemWIFIBSSID, rule.WIFIBSSID)
if err != nil {
return err
}
}
2024-07-26 08:03:08 +08:00
if len(rule.AdGuardDomain) > 0 {
2024-11-11 16:27:28 +08:00
if generateVersion < C.RuleSetVersion2 {
return E.New("AdGuard rule items is only supported in version 2 or later")
}
2024-07-26 08:03:08 +08:00
err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain)
if err != nil {
return err
}
err = domain.NewAdGuardMatcher(rule.AdGuardDomain).Write(writer)
if err != nil {
return err
}
}
2023-12-01 13:24:12 +08:00
err = binary.Write(writer, binary.BigEndian, ruleItemFinal)
if err != nil {
return err
}
err = binary.Write(writer, binary.BigEndian, rule.Invert)
if err != nil {
return err
}
return nil
}
2024-06-24 09:49:15 +08:00
func readRuleItemString(reader varbin.Reader) ([]string, error) {
return varbin.ReadValue[[]string](reader, binary.BigEndian)
2023-12-01 13:24:12 +08:00
}
2024-06-24 09:49:15 +08:00
func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) error {
err := writer.WriteByte(itemType)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
2024-06-24 09:49:15 +08:00
return varbin.Write(writer, binary.BigEndian, value)
2023-12-01 13:24:12 +08:00
}
2024-06-24 09:49:15 +08:00
func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
return varbin.ReadValue[[]uint16](reader, binary.BigEndian)
2023-12-01 13:24:12 +08:00
}
2024-06-24 09:49:15 +08:00
func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
err := writer.WriteByte(itemType)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
2024-06-24 09:49:15 +08:00
return varbin.Write(writer, binary.BigEndian, value)
2023-12-01 13:24:12 +08:00
}
2024-06-24 09:49:15 +08:00
func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) error {
2023-12-01 13:24:12 +08:00
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, "]")
}
ipSet, err := builder.IPSet()
if err != nil {
return err
}
err = binary.Write(writer, binary.BigEndian, itemType)
if err != nil {
return err
}
return writeIPSet(writer, ipSet)
}
2024-06-24 09:49:15 +08:00
func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
mode, err := reader.ReadByte()
2023-12-01 13:24:12 +08:00
if err != nil {
return
}
switch mode {
case 0:
logicalRule.Mode = C.LogicalTypeAnd
case 1:
logicalRule.Mode = C.LogicalTypeOr
default:
err = E.New("unknown logical mode: ", mode)
return
}
2024-06-24 09:49:15 +08:00
length, err := binary.ReadUvarint(reader)
2023-12-01 13:24:12 +08:00
if err != nil {
return
}
logicalRule.Rules = make([]option.HeadlessRule, length)
for i := uint64(0); i < length; i++ {
logicalRule.Rules[i], err = readRule(reader, recovery)
if err != nil {
err = E.Cause(err, "read logical rule [", i, "]")
return
}
}
err = binary.Read(reader, binary.BigEndian, &logicalRule.Invert)
if err != nil {
return
}
return
}
2024-11-11 16:27:28 +08:00
func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateVersion uint8) error {
2023-12-01 13:24:12 +08:00
err := binary.Write(writer, binary.BigEndian, uint8(1))
if err != nil {
return err
}
switch logicalRule.Mode {
case C.LogicalTypeAnd:
err = binary.Write(writer, binary.BigEndian, uint8(0))
case C.LogicalTypeOr:
err = binary.Write(writer, binary.BigEndian, uint8(1))
default:
panic("unknown logical mode: " + logicalRule.Mode)
}
if err != nil {
return err
}
2024-06-24 09:49:15 +08:00
_, err = varbin.WriteUvarint(writer, uint64(len(logicalRule.Rules)))
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
for _, rule := range logicalRule.Rules {
2024-11-11 16:27:28 +08:00
err = writeRule(writer, rule, generateVersion)
2023-12-01 13:24:12 +08:00
if err != nil {
return err
}
}
err = binary.Write(writer, binary.BigEndian, logicalRule.Invert)
if err != nil {
return err
}
return nil
}