binary.go 17 KB

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