binary.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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, 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, 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. for _, rawPrefix := range entry.Value {
  430. err = writePrefix(writer, rawPrefix.Build(netip.Prefix{}))
  431. if err != nil {
  432. return err
  433. }
  434. }
  435. }
  436. }
  437. if len(rule.DefaultInterfaceAddress) > 0 {
  438. if generateVersion < C.RuleSetVersion4 {
  439. return E.New("`default_interface_address` rule item is only supported in version 4 or later")
  440. }
  441. err = writer.WriteByte(ruleItemDefaultInterfaceAddress)
  442. if err != nil {
  443. return err
  444. }
  445. _, err = varbin.WriteUvarint(writer, uint64(len(rule.DefaultInterfaceAddress)))
  446. if err != nil {
  447. return err
  448. }
  449. for _, rawPrefix := range rule.DefaultInterfaceAddress {
  450. err = writePrefix(writer, rawPrefix.Build(netip.Prefix{}))
  451. if err != nil {
  452. return err
  453. }
  454. }
  455. }
  456. if len(rule.WIFISSID) > 0 {
  457. err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
  458. if err != nil {
  459. return err
  460. }
  461. }
  462. if len(rule.WIFIBSSID) > 0 {
  463. err = writeRuleItemString(writer, ruleItemWIFIBSSID, rule.WIFIBSSID)
  464. if err != nil {
  465. return err
  466. }
  467. }
  468. if len(rule.AdGuardDomain) > 0 {
  469. if generateVersion < C.RuleSetVersion2 {
  470. return E.New("AdGuard rule items is only supported in version 2 or later")
  471. }
  472. err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain)
  473. if err != nil {
  474. return err
  475. }
  476. err = domain.NewAdGuardMatcher(rule.AdGuardDomain).Write(writer)
  477. if err != nil {
  478. return err
  479. }
  480. }
  481. err = binary.Write(writer, binary.BigEndian, ruleItemFinal)
  482. if err != nil {
  483. return err
  484. }
  485. err = binary.Write(writer, binary.BigEndian, rule.Invert)
  486. if err != nil {
  487. return err
  488. }
  489. return nil
  490. }
  491. func readRuleItemString(reader varbin.Reader) ([]string, error) {
  492. return varbin.ReadValue[[]string](reader, binary.BigEndian)
  493. }
  494. func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) error {
  495. err := writer.WriteByte(itemType)
  496. if err != nil {
  497. return err
  498. }
  499. return varbin.Write(writer, binary.BigEndian, value)
  500. }
  501. func readRuleItemUint8[E ~uint8](reader varbin.Reader) ([]E, error) {
  502. return varbin.ReadValue[[]E](reader, binary.BigEndian)
  503. }
  504. func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []E) error {
  505. err := writer.WriteByte(itemType)
  506. if err != nil {
  507. return err
  508. }
  509. return varbin.Write(writer, binary.BigEndian, value)
  510. }
  511. func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
  512. return varbin.ReadValue[[]uint16](reader, binary.BigEndian)
  513. }
  514. func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
  515. err := writer.WriteByte(itemType)
  516. if err != nil {
  517. return err
  518. }
  519. return varbin.Write(writer, binary.BigEndian, value)
  520. }
  521. func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) error {
  522. var builder netipx.IPSetBuilder
  523. for i, prefixString := range value {
  524. prefix, err := netip.ParsePrefix(prefixString)
  525. if err == nil {
  526. builder.AddPrefix(prefix)
  527. continue
  528. }
  529. addr, addrErr := netip.ParseAddr(prefixString)
  530. if addrErr == nil {
  531. builder.Add(addr)
  532. continue
  533. }
  534. return E.Cause(err, "parse [", i, "]")
  535. }
  536. ipSet, err := builder.IPSet()
  537. if err != nil {
  538. return err
  539. }
  540. err = binary.Write(writer, binary.BigEndian, itemType)
  541. if err != nil {
  542. return err
  543. }
  544. return writeIPSet(writer, ipSet)
  545. }
  546. func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
  547. mode, err := reader.ReadByte()
  548. if err != nil {
  549. return
  550. }
  551. switch mode {
  552. case 0:
  553. logicalRule.Mode = C.LogicalTypeAnd
  554. case 1:
  555. logicalRule.Mode = C.LogicalTypeOr
  556. default:
  557. err = E.New("unknown logical mode: ", mode)
  558. return
  559. }
  560. length, err := binary.ReadUvarint(reader)
  561. if err != nil {
  562. return
  563. }
  564. logicalRule.Rules = make([]option.HeadlessRule, length)
  565. for i := uint64(0); i < length; i++ {
  566. logicalRule.Rules[i], err = readRule(reader, recovery)
  567. if err != nil {
  568. err = E.Cause(err, "read logical rule [", i, "]")
  569. return
  570. }
  571. }
  572. err = binary.Read(reader, binary.BigEndian, &logicalRule.Invert)
  573. if err != nil {
  574. return
  575. }
  576. return
  577. }
  578. func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateVersion uint8) error {
  579. err := binary.Write(writer, binary.BigEndian, uint8(1))
  580. if err != nil {
  581. return err
  582. }
  583. switch logicalRule.Mode {
  584. case C.LogicalTypeAnd:
  585. err = binary.Write(writer, binary.BigEndian, uint8(0))
  586. case C.LogicalTypeOr:
  587. err = binary.Write(writer, binary.BigEndian, uint8(1))
  588. default:
  589. panic("unknown logical mode: " + logicalRule.Mode)
  590. }
  591. if err != nil {
  592. return err
  593. }
  594. _, err = varbin.WriteUvarint(writer, uint64(len(logicalRule.Rules)))
  595. if err != nil {
  596. return err
  597. }
  598. for _, rule := range logicalRule.Rules {
  599. err = writeRule(writer, rule, generateVersion)
  600. if err != nil {
  601. return err
  602. }
  603. }
  604. err = binary.Write(writer, binary.BigEndian, logicalRule.Invert)
  605. if err != nil {
  606. return err
  607. }
  608. return nil
  609. }