binary.go 11 KB

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