binary.go 12 KB

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