binary.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. package srs
  2. import (
  3. "bufio"
  4. "compress/zlib"
  5. "encoding/binary"
  6. "io"
  7. "net/netip"
  8. "unsafe"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/common"
  12. "github.com/sagernet/sing/common/domain"
  13. E "github.com/sagernet/sing/common/exceptions"
  14. "github.com/sagernet/sing/common/json/badjson"
  15. "github.com/sagernet/sing/common/json/badoption"
  16. "github.com/sagernet/sing/common/varbin"
  17. "go4.org/netipx"
  18. )
  19. var MagicBytes = [3]byte{0x53, 0x52, 0x53} // SRS
  20. const (
  21. ruleItemQueryType uint8 = iota
  22. ruleItemNetwork
  23. ruleItemDomain
  24. ruleItemDomainKeyword
  25. ruleItemDomainRegex
  26. ruleItemSourceIPCIDR
  27. ruleItemIPCIDR
  28. ruleItemSourcePort
  29. ruleItemSourcePortRange
  30. ruleItemPort
  31. ruleItemPortRange
  32. ruleItemProcessName
  33. ruleItemProcessPath
  34. ruleItemPackageName
  35. ruleItemWIFISSID
  36. ruleItemWIFIBSSID
  37. ruleItemAdGuardDomain
  38. ruleItemProcessPathRegex
  39. ruleItemNetworkType
  40. ruleItemNetworkIsExpensive
  41. ruleItemNetworkIsConstrained
  42. ruleItemNetworkInterfaceAddress
  43. ruleItemDefaultInterfaceAddress
  44. ruleItemPackageNameRegex
  45. ruleItemFinal uint8 = 0xFF
  46. )
  47. func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetCompat, err error) {
  48. var magicBytes [3]byte
  49. _, err = io.ReadFull(reader, magicBytes[:])
  50. if err != nil {
  51. return
  52. }
  53. if magicBytes != MagicBytes {
  54. err = E.New("invalid sing-box rule-set file")
  55. return
  56. }
  57. var version uint8
  58. err = binary.Read(reader, binary.BigEndian, &version)
  59. if err != nil {
  60. return ruleSetCompat, err
  61. }
  62. if version > C.RuleSetVersionCurrent {
  63. return ruleSetCompat, E.New("unsupported version: ", version)
  64. }
  65. compressReader, err := zlib.NewReader(reader)
  66. if err != nil {
  67. return
  68. }
  69. bReader := bufio.NewReader(compressReader)
  70. length, err := binary.ReadUvarint(bReader)
  71. if err != nil {
  72. return
  73. }
  74. ruleSetCompat.Version = version
  75. ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
  76. for i := uint64(0); i < length; i++ {
  77. ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
  78. if err != nil {
  79. err = E.Cause(err, "read rule[", i, "]")
  80. return
  81. }
  82. }
  83. return
  84. }
  85. func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateVersion uint8) error {
  86. _, err := writer.Write(MagicBytes[:])
  87. if err != nil {
  88. return err
  89. }
  90. err = binary.Write(writer, binary.BigEndian, generateVersion)
  91. if err != nil {
  92. return err
  93. }
  94. compressWriter, err := zlib.NewWriterLevel(writer, zlib.BestCompression)
  95. if err != nil {
  96. return err
  97. }
  98. bWriter := bufio.NewWriter(compressWriter)
  99. _, err = varbin.WriteUvarint(bWriter, uint64(len(ruleSet.Rules)))
  100. if err != nil {
  101. return err
  102. }
  103. for _, rule := range ruleSet.Rules {
  104. err = writeRule(bWriter, rule, generateVersion)
  105. if err != nil {
  106. return err
  107. }
  108. }
  109. err = bWriter.Flush()
  110. if err != nil {
  111. return err
  112. }
  113. return compressWriter.Close()
  114. }
  115. func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err error) {
  116. var ruleType uint8
  117. err = binary.Read(reader, binary.BigEndian, &ruleType)
  118. if err != nil {
  119. return
  120. }
  121. switch ruleType {
  122. case 0:
  123. rule.Type = C.RuleTypeDefault
  124. rule.DefaultOptions, err = readDefaultRule(reader, recover)
  125. case 1:
  126. rule.Type = C.RuleTypeLogical
  127. rule.LogicalOptions, err = readLogicalRule(reader, recover)
  128. default:
  129. err = E.New("unknown rule type: ", ruleType)
  130. }
  131. return
  132. }
  133. func writeRule(writer varbin.Writer, rule option.HeadlessRule, generateVersion uint8) error {
  134. switch rule.Type {
  135. case C.RuleTypeDefault:
  136. return writeDefaultRule(writer, rule.DefaultOptions, generateVersion)
  137. case C.RuleTypeLogical:
  138. return writeLogicalRule(writer, rule.LogicalOptions, generateVersion)
  139. default:
  140. panic("unknown rule type: " + rule.Type)
  141. }
  142. }
  143. func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHeadlessRule, err error) {
  144. var lastItemType uint8
  145. for {
  146. var itemType uint8
  147. err = binary.Read(reader, binary.BigEndian, &itemType)
  148. if err != nil {
  149. return
  150. }
  151. switch itemType {
  152. case ruleItemQueryType:
  153. var rawQueryType []uint16
  154. rawQueryType, err = readRuleItemUint16(reader)
  155. if err != nil {
  156. return
  157. }
  158. rule.QueryType = common.Map(rawQueryType, func(it uint16) option.DNSQueryType {
  159. return option.DNSQueryType(it)
  160. })
  161. case ruleItemNetwork:
  162. rule.Network, err = readRuleItemString(reader)
  163. case ruleItemDomain:
  164. var matcher *domain.Matcher
  165. matcher, err = domain.ReadMatcher(reader)
  166. if err != nil {
  167. return
  168. }
  169. rule.DomainMatcher = matcher
  170. if recover {
  171. rule.Domain, rule.DomainSuffix = matcher.Dump()
  172. }
  173. case ruleItemDomainKeyword:
  174. rule.DomainKeyword, err = readRuleItemString(reader)
  175. case ruleItemDomainRegex:
  176. rule.DomainRegex, err = readRuleItemString(reader)
  177. case ruleItemSourceIPCIDR:
  178. rule.SourceIPSet, err = readIPSet(reader)
  179. if err != nil {
  180. return
  181. }
  182. if recover {
  183. rule.SourceIPCIDR = common.Map(rule.SourceIPSet.Prefixes(), netip.Prefix.String)
  184. }
  185. case ruleItemIPCIDR:
  186. rule.IPSet, err = readIPSet(reader)
  187. if err != nil {
  188. return
  189. }
  190. if recover {
  191. rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
  192. }
  193. case ruleItemSourcePort:
  194. rule.SourcePort, err = readRuleItemUint16(reader)
  195. case ruleItemSourcePortRange:
  196. rule.SourcePortRange, err = readRuleItemString(reader)
  197. case ruleItemPort:
  198. rule.Port, err = readRuleItemUint16(reader)
  199. case ruleItemPortRange:
  200. rule.PortRange, err = readRuleItemString(reader)
  201. case ruleItemProcessName:
  202. rule.ProcessName, err = readRuleItemString(reader)
  203. case ruleItemProcessPath:
  204. rule.ProcessPath, err = readRuleItemString(reader)
  205. case ruleItemProcessPathRegex:
  206. rule.ProcessPathRegex, err = readRuleItemString(reader)
  207. case ruleItemPackageName:
  208. rule.PackageName, err = readRuleItemString(reader)
  209. case ruleItemPackageNameRegex:
  210. rule.PackageNameRegex, err = readRuleItemString(reader)
  211. case ruleItemWIFISSID:
  212. rule.WIFISSID, err = readRuleItemString(reader)
  213. case ruleItemWIFIBSSID:
  214. rule.WIFIBSSID, err = readRuleItemString(reader)
  215. case ruleItemAdGuardDomain:
  216. var matcher *domain.AdGuardMatcher
  217. matcher, err = domain.ReadAdGuardMatcher(reader)
  218. if err != nil {
  219. return
  220. }
  221. rule.AdGuardDomainMatcher = matcher
  222. if recover {
  223. rule.AdGuardDomain = matcher.Dump()
  224. }
  225. case ruleItemNetworkType:
  226. rule.NetworkType, err = readRuleItemUint8[option.InterfaceType](reader)
  227. case ruleItemNetworkIsExpensive:
  228. rule.NetworkIsExpensive = true
  229. case ruleItemNetworkIsConstrained:
  230. rule.NetworkIsConstrained = true
  231. case ruleItemNetworkInterfaceAddress:
  232. rule.NetworkInterfaceAddress = new(badjson.TypedMap[option.InterfaceType, badoption.Listable[*badoption.Prefixable]])
  233. var size uint64
  234. size, err = binary.ReadUvarint(reader)
  235. if err != nil {
  236. return
  237. }
  238. for i := uint64(0); i < size; i++ {
  239. var key uint8
  240. err = binary.Read(reader, binary.BigEndian, &key)
  241. if err != nil {
  242. return
  243. }
  244. var value []*badoption.Prefixable
  245. var prefixCount uint64
  246. prefixCount, err = binary.ReadUvarint(reader)
  247. if err != nil {
  248. return
  249. }
  250. for j := uint64(0); j < prefixCount; j++ {
  251. var prefix netip.Prefix
  252. prefix, err = readPrefix(reader)
  253. if err != nil {
  254. return
  255. }
  256. value = append(value, common.Ptr(badoption.Prefixable(prefix)))
  257. }
  258. rule.NetworkInterfaceAddress.Put(option.InterfaceType(key), value)
  259. }
  260. case ruleItemDefaultInterfaceAddress:
  261. var value []*badoption.Prefixable
  262. var prefixCount uint64
  263. prefixCount, err = binary.ReadUvarint(reader)
  264. if err != nil {
  265. return
  266. }
  267. for j := uint64(0); j < prefixCount; j++ {
  268. var prefix netip.Prefix
  269. prefix, err = readPrefix(reader)
  270. if err != nil {
  271. return
  272. }
  273. value = append(value, common.Ptr(badoption.Prefixable(prefix)))
  274. }
  275. rule.DefaultInterfaceAddress = value
  276. case ruleItemFinal:
  277. err = binary.Read(reader, binary.BigEndian, &rule.Invert)
  278. return
  279. default:
  280. err = E.New("unknown rule item type: ", itemType, ", last type: ", lastItemType)
  281. }
  282. if err != nil {
  283. return
  284. }
  285. lastItemType = itemType
  286. }
  287. }
  288. func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, generateVersion uint8) error {
  289. err := binary.Write(writer, binary.BigEndian, uint8(0))
  290. if err != nil {
  291. return err
  292. }
  293. if len(rule.QueryType) > 0 {
  294. err = writeRuleItemUint16(writer, ruleItemQueryType, common.Map(rule.QueryType, func(it option.DNSQueryType) uint16 {
  295. return uint16(it)
  296. }))
  297. if err != nil {
  298. return err
  299. }
  300. }
  301. if len(rule.Network) > 0 {
  302. err = writeRuleItemString(writer, ruleItemNetwork, rule.Network)
  303. if err != nil {
  304. return err
  305. }
  306. }
  307. if len(rule.Domain) > 0 || len(rule.DomainSuffix) > 0 {
  308. err = binary.Write(writer, binary.BigEndian, ruleItemDomain)
  309. if err != nil {
  310. return err
  311. }
  312. err = domain.NewMatcher(rule.Domain, rule.DomainSuffix, generateVersion == C.RuleSetVersion1).Write(writer)
  313. if err != nil {
  314. return err
  315. }
  316. }
  317. if len(rule.DomainKeyword) > 0 {
  318. err = writeRuleItemString(writer, ruleItemDomainKeyword, rule.DomainKeyword)
  319. if err != nil {
  320. return err
  321. }
  322. }
  323. if len(rule.DomainRegex) > 0 {
  324. err = writeRuleItemString(writer, ruleItemDomainRegex, rule.DomainRegex)
  325. if err != nil {
  326. return err
  327. }
  328. }
  329. if len(rule.SourceIPCIDR) > 0 {
  330. err = writeRuleItemCIDR(writer, ruleItemSourceIPCIDR, rule.SourceIPCIDR)
  331. if err != nil {
  332. return E.Cause(err, "source_ip_cidr")
  333. }
  334. }
  335. if len(rule.IPCIDR) > 0 {
  336. err = writeRuleItemCIDR(writer, ruleItemIPCIDR, rule.IPCIDR)
  337. if err != nil {
  338. return E.Cause(err, "ipcidr")
  339. }
  340. }
  341. if len(rule.SourcePort) > 0 {
  342. err = writeRuleItemUint16(writer, ruleItemSourcePort, rule.SourcePort)
  343. if err != nil {
  344. return err
  345. }
  346. }
  347. if len(rule.SourcePortRange) > 0 {
  348. err = writeRuleItemString(writer, ruleItemSourcePortRange, rule.SourcePortRange)
  349. if err != nil {
  350. return err
  351. }
  352. }
  353. if len(rule.Port) > 0 {
  354. err = writeRuleItemUint16(writer, ruleItemPort, rule.Port)
  355. if err != nil {
  356. return err
  357. }
  358. }
  359. if len(rule.PortRange) > 0 {
  360. err = writeRuleItemString(writer, ruleItemPortRange, rule.PortRange)
  361. if err != nil {
  362. return err
  363. }
  364. }
  365. if len(rule.ProcessName) > 0 {
  366. err = writeRuleItemString(writer, ruleItemProcessName, rule.ProcessName)
  367. if err != nil {
  368. return err
  369. }
  370. }
  371. if len(rule.ProcessPath) > 0 {
  372. err = writeRuleItemString(writer, ruleItemProcessPath, rule.ProcessPath)
  373. if err != nil {
  374. return err
  375. }
  376. }
  377. if len(rule.ProcessPathRegex) > 0 {
  378. err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
  379. if err != nil {
  380. return err
  381. }
  382. }
  383. if len(rule.PackageName) > 0 {
  384. err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
  385. if err != nil {
  386. return err
  387. }
  388. }
  389. if len(rule.PackageNameRegex) > 0 {
  390. if generateVersion < C.RuleSetVersion5 {
  391. return E.New("`package_name_regex` rule item is only supported in version 5 or later")
  392. }
  393. err = writeRuleItemString(writer, ruleItemPackageNameRegex, rule.PackageNameRegex)
  394. if err != nil {
  395. return err
  396. }
  397. }
  398. if len(rule.NetworkType) > 0 {
  399. if generateVersion < C.RuleSetVersion3 {
  400. return E.New("`network_type` rule item is only supported in version 3 or later")
  401. }
  402. err = writeRuleItemUint8(writer, ruleItemNetworkType, rule.NetworkType)
  403. if err != nil {
  404. return err
  405. }
  406. }
  407. if rule.NetworkIsExpensive {
  408. if generateVersion < C.RuleSetVersion3 {
  409. return E.New("`network_is_expensive` rule item is only supported in version 3 or later")
  410. }
  411. err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsExpensive)
  412. if err != nil {
  413. return err
  414. }
  415. }
  416. if rule.NetworkIsConstrained {
  417. if generateVersion < C.RuleSetVersion3 {
  418. return E.New("`network_is_constrained` rule item is only supported in version 3 or later")
  419. }
  420. err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsConstrained)
  421. if err != nil {
  422. return err
  423. }
  424. }
  425. if rule.NetworkInterfaceAddress != nil && rule.NetworkInterfaceAddress.Size() > 0 {
  426. if generateVersion < C.RuleSetVersion4 {
  427. return E.New("`network_interface_address` rule item is only supported in version 4 or later")
  428. }
  429. err = writer.WriteByte(ruleItemNetworkInterfaceAddress)
  430. if err != nil {
  431. return err
  432. }
  433. _, err = varbin.WriteUvarint(writer, uint64(rule.NetworkInterfaceAddress.Size()))
  434. if err != nil {
  435. return err
  436. }
  437. for _, entry := range rule.NetworkInterfaceAddress.Entries() {
  438. err = binary.Write(writer, binary.BigEndian, uint8(entry.Key.Build()))
  439. if err != nil {
  440. return err
  441. }
  442. _, err = varbin.WriteUvarint(writer, uint64(len(entry.Value)))
  443. if err != nil {
  444. return err
  445. }
  446. for _, rawPrefix := range entry.Value {
  447. err = writePrefix(writer, rawPrefix.Build(netip.Prefix{}))
  448. if err != nil {
  449. return err
  450. }
  451. }
  452. }
  453. }
  454. if len(rule.DefaultInterfaceAddress) > 0 {
  455. if generateVersion < C.RuleSetVersion4 {
  456. return E.New("`default_interface_address` rule item is only supported in version 4 or later")
  457. }
  458. err = writer.WriteByte(ruleItemDefaultInterfaceAddress)
  459. if err != nil {
  460. return err
  461. }
  462. _, err = varbin.WriteUvarint(writer, uint64(len(rule.DefaultInterfaceAddress)))
  463. if err != nil {
  464. return err
  465. }
  466. for _, rawPrefix := range rule.DefaultInterfaceAddress {
  467. err = writePrefix(writer, rawPrefix.Build(netip.Prefix{}))
  468. if err != nil {
  469. return err
  470. }
  471. }
  472. }
  473. if len(rule.WIFISSID) > 0 {
  474. err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
  475. if err != nil {
  476. return err
  477. }
  478. }
  479. if len(rule.WIFIBSSID) > 0 {
  480. err = writeRuleItemString(writer, ruleItemWIFIBSSID, rule.WIFIBSSID)
  481. if err != nil {
  482. return err
  483. }
  484. }
  485. if len(rule.AdGuardDomain) > 0 {
  486. if generateVersion < C.RuleSetVersion2 {
  487. return E.New("AdGuard rule items is only supported in version 2 or later")
  488. }
  489. err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain)
  490. if err != nil {
  491. return err
  492. }
  493. err = domain.NewAdGuardMatcher(rule.AdGuardDomain).Write(writer)
  494. if err != nil {
  495. return err
  496. }
  497. }
  498. err = binary.Write(writer, binary.BigEndian, ruleItemFinal)
  499. if err != nil {
  500. return err
  501. }
  502. err = binary.Write(writer, binary.BigEndian, rule.Invert)
  503. if err != nil {
  504. return err
  505. }
  506. return nil
  507. }
  508. func readRuleItemString(reader varbin.Reader) ([]string, error) {
  509. length, err := binary.ReadUvarint(reader)
  510. if err != nil {
  511. return nil, err
  512. }
  513. result := make([]string, length)
  514. for i := range result {
  515. strLen, err := binary.ReadUvarint(reader)
  516. if err != nil {
  517. return nil, err
  518. }
  519. buf := make([]byte, strLen)
  520. _, err = io.ReadFull(reader, buf)
  521. if err != nil {
  522. return nil, err
  523. }
  524. result[i] = string(buf)
  525. }
  526. return result, nil
  527. }
  528. func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) error {
  529. err := writer.WriteByte(itemType)
  530. if err != nil {
  531. return err
  532. }
  533. _, err = varbin.WriteUvarint(writer, uint64(len(value)))
  534. if err != nil {
  535. return err
  536. }
  537. for _, s := range value {
  538. _, err = varbin.WriteUvarint(writer, uint64(len(s)))
  539. if err != nil {
  540. return err
  541. }
  542. _, err = writer.Write([]byte(s))
  543. if err != nil {
  544. return err
  545. }
  546. }
  547. return nil
  548. }
  549. func readRuleItemUint8[E ~uint8](reader varbin.Reader) ([]E, error) {
  550. length, err := binary.ReadUvarint(reader)
  551. if err != nil {
  552. return nil, err
  553. }
  554. result := make([]E, length)
  555. _, err = io.ReadFull(reader, *(*[]byte)(unsafe.Pointer(&result)))
  556. if err != nil {
  557. return nil, err
  558. }
  559. return result, nil
  560. }
  561. func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []E) error {
  562. err := writer.WriteByte(itemType)
  563. if err != nil {
  564. return err
  565. }
  566. _, err = varbin.WriteUvarint(writer, uint64(len(value)))
  567. if err != nil {
  568. return err
  569. }
  570. _, err = writer.Write(*(*[]byte)(unsafe.Pointer(&value)))
  571. return err
  572. }
  573. func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
  574. length, err := binary.ReadUvarint(reader)
  575. if err != nil {
  576. return nil, err
  577. }
  578. result := make([]uint16, length)
  579. err = binary.Read(reader, binary.BigEndian, result)
  580. if err != nil {
  581. return nil, err
  582. }
  583. return result, nil
  584. }
  585. func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
  586. err := writer.WriteByte(itemType)
  587. if err != nil {
  588. return err
  589. }
  590. _, err = varbin.WriteUvarint(writer, uint64(len(value)))
  591. if err != nil {
  592. return err
  593. }
  594. return binary.Write(writer, binary.BigEndian, value)
  595. }
  596. func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) error {
  597. var builder netipx.IPSetBuilder
  598. for i, prefixString := range value {
  599. prefix, err := netip.ParsePrefix(prefixString)
  600. if err == nil {
  601. builder.AddPrefix(prefix)
  602. continue
  603. }
  604. addr, addrErr := netip.ParseAddr(prefixString)
  605. if addrErr == nil {
  606. builder.Add(addr)
  607. continue
  608. }
  609. return E.Cause(err, "parse [", i, "]")
  610. }
  611. ipSet, err := builder.IPSet()
  612. if err != nil {
  613. return err
  614. }
  615. err = binary.Write(writer, binary.BigEndian, itemType)
  616. if err != nil {
  617. return err
  618. }
  619. return writeIPSet(writer, ipSet)
  620. }
  621. func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
  622. mode, err := reader.ReadByte()
  623. if err != nil {
  624. return
  625. }
  626. switch mode {
  627. case 0:
  628. logicalRule.Mode = C.LogicalTypeAnd
  629. case 1:
  630. logicalRule.Mode = C.LogicalTypeOr
  631. default:
  632. err = E.New("unknown logical mode: ", mode)
  633. return
  634. }
  635. length, err := binary.ReadUvarint(reader)
  636. if err != nil {
  637. return
  638. }
  639. logicalRule.Rules = make([]option.HeadlessRule, length)
  640. for i := uint64(0); i < length; i++ {
  641. logicalRule.Rules[i], err = readRule(reader, recovery)
  642. if err != nil {
  643. err = E.Cause(err, "read logical rule [", i, "]")
  644. return
  645. }
  646. }
  647. err = binary.Read(reader, binary.BigEndian, &logicalRule.Invert)
  648. if err != nil {
  649. return
  650. }
  651. return
  652. }
  653. func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateVersion uint8) error {
  654. err := binary.Write(writer, binary.BigEndian, uint8(1))
  655. if err != nil {
  656. return err
  657. }
  658. switch logicalRule.Mode {
  659. case C.LogicalTypeAnd:
  660. err = binary.Write(writer, binary.BigEndian, uint8(0))
  661. case C.LogicalTypeOr:
  662. err = binary.Write(writer, binary.BigEndian, uint8(1))
  663. default:
  664. panic("unknown logical mode: " + logicalRule.Mode)
  665. }
  666. if err != nil {
  667. return err
  668. }
  669. _, err = varbin.WriteUvarint(writer, uint64(len(logicalRule.Rules)))
  670. if err != nil {
  671. return err
  672. }
  673. for _, rule := range logicalRule.Rules {
  674. err = writeRule(writer, rule, generateVersion)
  675. if err != nil {
  676. return err
  677. }
  678. }
  679. err = binary.Write(writer, binary.BigEndian, logicalRule.Invert)
  680. if err != nil {
  681. return err
  682. }
  683. return nil
  684. }