binary.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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. var matcher *domain.AdGuardMatcher
  209. matcher, err = domain.ReadAdGuardMatcher(reader)
  210. if err != nil {
  211. return
  212. }
  213. rule.AdGuardDomainMatcher = matcher
  214. if recover {
  215. rule.AdGuardDomain = matcher.Dump()
  216. }
  217. case ruleItemNetworkType:
  218. rule.NetworkType, err = readRuleItemUint8[option.InterfaceType](reader)
  219. case ruleItemNetworkIsExpensive:
  220. rule.NetworkIsExpensive = true
  221. case ruleItemNetworkIsConstrained:
  222. rule.NetworkIsConstrained = true
  223. case ruleItemFinal:
  224. err = binary.Read(reader, binary.BigEndian, &rule.Invert)
  225. return
  226. default:
  227. err = E.New("unknown rule item type: ", itemType, ", last type: ", lastItemType)
  228. }
  229. if err != nil {
  230. return
  231. }
  232. lastItemType = itemType
  233. }
  234. }
  235. func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, generateVersion uint8) error {
  236. err := binary.Write(writer, binary.BigEndian, uint8(0))
  237. if err != nil {
  238. return err
  239. }
  240. if len(rule.QueryType) > 0 {
  241. err = writeRuleItemUint16(writer, ruleItemQueryType, common.Map(rule.QueryType, func(it option.DNSQueryType) uint16 {
  242. return uint16(it)
  243. }))
  244. if err != nil {
  245. return err
  246. }
  247. }
  248. if len(rule.Network) > 0 {
  249. err = writeRuleItemString(writer, ruleItemNetwork, rule.Network)
  250. if err != nil {
  251. return err
  252. }
  253. }
  254. if len(rule.Domain) > 0 || len(rule.DomainSuffix) > 0 {
  255. err = binary.Write(writer, binary.BigEndian, ruleItemDomain)
  256. if err != nil {
  257. return err
  258. }
  259. err = domain.NewMatcher(rule.Domain, rule.DomainSuffix, generateVersion == C.RuleSetVersion1).Write(writer)
  260. if err != nil {
  261. return err
  262. }
  263. }
  264. if len(rule.DomainKeyword) > 0 {
  265. err = writeRuleItemString(writer, ruleItemDomainKeyword, rule.DomainKeyword)
  266. if err != nil {
  267. return err
  268. }
  269. }
  270. if len(rule.DomainRegex) > 0 {
  271. err = writeRuleItemString(writer, ruleItemDomainRegex, rule.DomainRegex)
  272. if err != nil {
  273. return err
  274. }
  275. }
  276. if len(rule.SourceIPCIDR) > 0 {
  277. err = writeRuleItemCIDR(writer, ruleItemSourceIPCIDR, rule.SourceIPCIDR)
  278. if err != nil {
  279. return E.Cause(err, "source_ip_cidr")
  280. }
  281. }
  282. if len(rule.IPCIDR) > 0 {
  283. err = writeRuleItemCIDR(writer, ruleItemIPCIDR, rule.IPCIDR)
  284. if err != nil {
  285. return E.Cause(err, "ipcidr")
  286. }
  287. }
  288. if len(rule.SourcePort) > 0 {
  289. err = writeRuleItemUint16(writer, ruleItemSourcePort, rule.SourcePort)
  290. if err != nil {
  291. return err
  292. }
  293. }
  294. if len(rule.SourcePortRange) > 0 {
  295. err = writeRuleItemString(writer, ruleItemSourcePortRange, rule.SourcePortRange)
  296. if err != nil {
  297. return err
  298. }
  299. }
  300. if len(rule.Port) > 0 {
  301. err = writeRuleItemUint16(writer, ruleItemPort, rule.Port)
  302. if err != nil {
  303. return err
  304. }
  305. }
  306. if len(rule.PortRange) > 0 {
  307. err = writeRuleItemString(writer, ruleItemPortRange, rule.PortRange)
  308. if err != nil {
  309. return err
  310. }
  311. }
  312. if len(rule.ProcessName) > 0 {
  313. err = writeRuleItemString(writer, ruleItemProcessName, rule.ProcessName)
  314. if err != nil {
  315. return err
  316. }
  317. }
  318. if len(rule.ProcessPath) > 0 {
  319. err = writeRuleItemString(writer, ruleItemProcessPath, rule.ProcessPath)
  320. if err != nil {
  321. return err
  322. }
  323. }
  324. if len(rule.ProcessPathRegex) > 0 {
  325. err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
  326. if err != nil {
  327. return err
  328. }
  329. }
  330. if len(rule.PackageName) > 0 {
  331. err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
  332. if err != nil {
  333. return err
  334. }
  335. }
  336. if len(rule.NetworkType) > 0 {
  337. if generateVersion < C.RuleSetVersion3 {
  338. return E.New("network_type rule item is only supported in version 3 or later")
  339. }
  340. err = writeRuleItemUint8(writer, ruleItemNetworkType, rule.NetworkType)
  341. if err != nil {
  342. return err
  343. }
  344. }
  345. if rule.NetworkIsExpensive {
  346. err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsExpensive)
  347. if err != nil {
  348. return err
  349. }
  350. }
  351. if rule.NetworkIsConstrained {
  352. err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsConstrained)
  353. if err != nil {
  354. return err
  355. }
  356. }
  357. if len(rule.WIFISSID) > 0 {
  358. err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
  359. if err != nil {
  360. return err
  361. }
  362. }
  363. if len(rule.WIFIBSSID) > 0 {
  364. err = writeRuleItemString(writer, ruleItemWIFIBSSID, rule.WIFIBSSID)
  365. if err != nil {
  366. return err
  367. }
  368. }
  369. if len(rule.AdGuardDomain) > 0 {
  370. if generateVersion < C.RuleSetVersion2 {
  371. return E.New("AdGuard rule items is only supported in version 2 or later")
  372. }
  373. err = binary.Write(writer, binary.BigEndian, ruleItemAdGuardDomain)
  374. if err != nil {
  375. return err
  376. }
  377. err = domain.NewAdGuardMatcher(rule.AdGuardDomain).Write(writer)
  378. if err != nil {
  379. return err
  380. }
  381. }
  382. err = binary.Write(writer, binary.BigEndian, ruleItemFinal)
  383. if err != nil {
  384. return err
  385. }
  386. err = binary.Write(writer, binary.BigEndian, rule.Invert)
  387. if err != nil {
  388. return err
  389. }
  390. return nil
  391. }
  392. func readRuleItemString(reader varbin.Reader) ([]string, error) {
  393. return varbin.ReadValue[[]string](reader, binary.BigEndian)
  394. }
  395. func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) error {
  396. err := writer.WriteByte(itemType)
  397. if err != nil {
  398. return err
  399. }
  400. return varbin.Write(writer, binary.BigEndian, value)
  401. }
  402. func readRuleItemUint8[E ~uint8](reader varbin.Reader) ([]E, error) {
  403. return varbin.ReadValue[[]E](reader, binary.BigEndian)
  404. }
  405. func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []E) error {
  406. err := writer.WriteByte(itemType)
  407. if err != nil {
  408. return err
  409. }
  410. return varbin.Write(writer, binary.BigEndian, value)
  411. }
  412. func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
  413. return varbin.ReadValue[[]uint16](reader, binary.BigEndian)
  414. }
  415. func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
  416. err := writer.WriteByte(itemType)
  417. if err != nil {
  418. return err
  419. }
  420. return varbin.Write(writer, binary.BigEndian, value)
  421. }
  422. func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) error {
  423. var builder netipx.IPSetBuilder
  424. for i, prefixString := range value {
  425. prefix, err := netip.ParsePrefix(prefixString)
  426. if err == nil {
  427. builder.AddPrefix(prefix)
  428. continue
  429. }
  430. addr, addrErr := netip.ParseAddr(prefixString)
  431. if addrErr == nil {
  432. builder.Add(addr)
  433. continue
  434. }
  435. return E.Cause(err, "parse [", i, "]")
  436. }
  437. ipSet, err := builder.IPSet()
  438. if err != nil {
  439. return err
  440. }
  441. err = binary.Write(writer, binary.BigEndian, itemType)
  442. if err != nil {
  443. return err
  444. }
  445. return writeIPSet(writer, ipSet)
  446. }
  447. func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
  448. mode, err := reader.ReadByte()
  449. if err != nil {
  450. return
  451. }
  452. switch mode {
  453. case 0:
  454. logicalRule.Mode = C.LogicalTypeAnd
  455. case 1:
  456. logicalRule.Mode = C.LogicalTypeOr
  457. default:
  458. err = E.New("unknown logical mode: ", mode)
  459. return
  460. }
  461. length, err := binary.ReadUvarint(reader)
  462. if err != nil {
  463. return
  464. }
  465. logicalRule.Rules = make([]option.HeadlessRule, length)
  466. for i := uint64(0); i < length; i++ {
  467. logicalRule.Rules[i], err = readRule(reader, recovery)
  468. if err != nil {
  469. err = E.Cause(err, "read logical rule [", i, "]")
  470. return
  471. }
  472. }
  473. err = binary.Read(reader, binary.BigEndian, &logicalRule.Invert)
  474. if err != nil {
  475. return
  476. }
  477. return
  478. }
  479. func writeLogicalRule(writer varbin.Writer, logicalRule option.LogicalHeadlessRule, generateVersion uint8) error {
  480. err := binary.Write(writer, binary.BigEndian, uint8(1))
  481. if err != nil {
  482. return err
  483. }
  484. switch logicalRule.Mode {
  485. case C.LogicalTypeAnd:
  486. err = binary.Write(writer, binary.BigEndian, uint8(0))
  487. case C.LogicalTypeOr:
  488. err = binary.Write(writer, binary.BigEndian, uint8(1))
  489. default:
  490. panic("unknown logical mode: " + logicalRule.Mode)
  491. }
  492. if err != nil {
  493. return err
  494. }
  495. _, err = varbin.WriteUvarint(writer, uint64(len(logicalRule.Rules)))
  496. if err != nil {
  497. return err
  498. }
  499. for _, rule := range logicalRule.Rules {
  500. err = writeRule(writer, rule, generateVersion)
  501. if err != nil {
  502. return err
  503. }
  504. }
  505. err = binary.Write(writer, binary.BigEndian, logicalRule.Invert)
  506. if err != nil {
  507. return err
  508. }
  509. return nil
  510. }