binary.go 12 KB

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