cmd_rule_set_match.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package main
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/common/srs"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing-box/log"
  12. "github.com/sagernet/sing-box/option"
  13. "github.com/sagernet/sing-box/route/rule"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. F "github.com/sagernet/sing/common/format"
  16. "github.com/sagernet/sing/common/json"
  17. M "github.com/sagernet/sing/common/metadata"
  18. "github.com/spf13/cobra"
  19. )
  20. var flagRuleSetMatchFormat string
  21. var commandRuleSetMatch = &cobra.Command{
  22. Use: "match <rule-set path> <IP address/domain>",
  23. Short: "Check if an IP address or a domain matches the rule-set",
  24. Args: cobra.ExactArgs(2),
  25. Run: func(cmd *cobra.Command, args []string) {
  26. err := ruleSetMatch(args[0], args[1])
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. },
  31. }
  32. func init() {
  33. commandRuleSetMatch.Flags().StringVarP(&flagRuleSetMatchFormat, "format", "f", "source", "rule-set format")
  34. commandRuleSet.AddCommand(commandRuleSetMatch)
  35. }
  36. func ruleSetMatch(sourcePath string, domain string) error {
  37. var (
  38. reader io.Reader
  39. err error
  40. )
  41. if sourcePath == "stdin" {
  42. reader = os.Stdin
  43. } else {
  44. reader, err = os.Open(sourcePath)
  45. if err != nil {
  46. return E.Cause(err, "read rule-set")
  47. }
  48. }
  49. content, err := io.ReadAll(reader)
  50. if err != nil {
  51. return E.Cause(err, "read rule-set")
  52. }
  53. if flagRuleSetMatchFormat == "" {
  54. switch filepath.Ext(sourcePath) {
  55. case ".json":
  56. flagRuleSetMatchFormat = C.RuleSetFormatSource
  57. case ".srs":
  58. flagRuleSetMatchFormat = C.RuleSetFormatBinary
  59. }
  60. }
  61. var ruleSet option.PlainRuleSetCompat
  62. switch flagRuleSetMatchFormat {
  63. case C.RuleSetFormatSource:
  64. ruleSet, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
  65. if err != nil {
  66. return err
  67. }
  68. case C.RuleSetFormatBinary:
  69. ruleSet, err = srs.Read(bytes.NewReader(content), false)
  70. if err != nil {
  71. return err
  72. }
  73. default:
  74. return E.New("unknown rule-set format: ", flagRuleSetMatchFormat)
  75. }
  76. plainRuleSet, err := ruleSet.Upgrade()
  77. if err != nil {
  78. return err
  79. }
  80. ipAddress := M.ParseAddr(domain)
  81. var metadata adapter.InboundContext
  82. if ipAddress.IsValid() {
  83. metadata.Destination = M.SocksaddrFrom(ipAddress, 0)
  84. } else {
  85. metadata.Domain = domain
  86. }
  87. for i, ruleOptions := range plainRuleSet.Rules {
  88. var currentRule adapter.HeadlessRule
  89. currentRule, err = rule.NewHeadlessRule(context.Background(), ruleOptions)
  90. if err != nil {
  91. return E.Cause(err, "parse rule_set.rules.[", i, "]")
  92. }
  93. if currentRule.Match(&metadata) {
  94. println(F.ToString("match rules.[", i, "]: ", currentRule))
  95. }
  96. }
  97. return nil
  98. }