binary.go 12 KB

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