binary.go 13 KB

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