1
0

rule_nested.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package option
  2. import (
  3. "context"
  4. "reflect"
  5. "strings"
  6. E "github.com/sagernet/sing/common/exceptions"
  7. "github.com/sagernet/sing/common/json"
  8. "github.com/sagernet/sing/common/json/badjson"
  9. )
  10. type nestedRuleDepthContextKey struct{}
  11. const (
  12. RouteRuleActionNestedUnsupportedMessage = "rule action is not supported in nested rules"
  13. DNSRuleActionNestedUnsupportedMessage = "DNS rule action is not supported in nested rules"
  14. )
  15. var (
  16. routeRuleActionKeys = jsonFieldNames(reflect.TypeFor[_RuleAction](), reflect.TypeFor[RouteActionOptions]())
  17. dnsRuleActionKeys = jsonFieldNames(reflect.TypeFor[_DNSRuleAction](), reflect.TypeFor[DNSRouteActionOptions]())
  18. )
  19. func nestedRuleChildContext(ctx context.Context) context.Context {
  20. return context.WithValue(ctx, nestedRuleDepthContextKey{}, nestedRuleDepth(ctx)+1)
  21. }
  22. func rejectNestedRouteRuleAction(ctx context.Context, content []byte) error {
  23. return rejectNestedRuleAction(ctx, content, routeRuleActionKeys, RouteRuleActionNestedUnsupportedMessage)
  24. }
  25. func rejectNestedDNSRuleAction(ctx context.Context, content []byte) error {
  26. return rejectNestedRuleAction(ctx, content, dnsRuleActionKeys, DNSRuleActionNestedUnsupportedMessage)
  27. }
  28. func nestedRuleDepth(ctx context.Context) int {
  29. depth, _ := ctx.Value(nestedRuleDepthContextKey{}).(int)
  30. return depth
  31. }
  32. func rejectNestedRuleAction(ctx context.Context, content []byte, keys []string, message string) error {
  33. if nestedRuleDepth(ctx) == 0 {
  34. return nil
  35. }
  36. hasActionKey, err := hasAnyJSONKey(ctx, content, keys...)
  37. if err != nil {
  38. return err
  39. }
  40. if hasActionKey {
  41. return E.New(message)
  42. }
  43. return nil
  44. }
  45. func hasAnyJSONKey(ctx context.Context, content []byte, keys ...string) (bool, error) {
  46. var object badjson.JSONObject
  47. err := object.UnmarshalJSONContext(ctx, content)
  48. if err != nil {
  49. return false, err
  50. }
  51. for _, key := range keys {
  52. if object.ContainsKey(key) {
  53. return true, nil
  54. }
  55. }
  56. return false, nil
  57. }
  58. func inspectRouteRuleAction(ctx context.Context, content []byte) (string, RouteActionOptions, error) {
  59. var rawAction _RuleAction
  60. err := json.UnmarshalContext(ctx, content, &rawAction)
  61. if err != nil {
  62. return "", RouteActionOptions{}, err
  63. }
  64. var routeOptions RouteActionOptions
  65. err = json.UnmarshalContext(ctx, content, &routeOptions)
  66. if err != nil {
  67. return "", RouteActionOptions{}, err
  68. }
  69. return rawAction.Action, routeOptions, nil
  70. }
  71. func inspectDNSRuleAction(ctx context.Context, content []byte) (string, DNSRouteActionOptions, error) {
  72. var rawAction _DNSRuleAction
  73. err := json.UnmarshalContext(ctx, content, &rawAction)
  74. if err != nil {
  75. return "", DNSRouteActionOptions{}, err
  76. }
  77. var routeOptions DNSRouteActionOptions
  78. err = json.UnmarshalContext(ctx, content, &routeOptions)
  79. if err != nil {
  80. return "", DNSRouteActionOptions{}, err
  81. }
  82. return rawAction.Action, routeOptions, nil
  83. }
  84. func jsonFieldNames(types ...reflect.Type) []string {
  85. fieldMap := make(map[string]struct{})
  86. for _, fieldType := range types {
  87. appendJSONFieldNames(fieldMap, fieldType)
  88. }
  89. fieldNames := make([]string, 0, len(fieldMap))
  90. for fieldName := range fieldMap {
  91. fieldNames = append(fieldNames, fieldName)
  92. }
  93. return fieldNames
  94. }
  95. func appendJSONFieldNames(fieldMap map[string]struct{}, fieldType reflect.Type) {
  96. for fieldType.Kind() == reflect.Pointer {
  97. fieldType = fieldType.Elem()
  98. }
  99. if fieldType.Kind() != reflect.Struct {
  100. return
  101. }
  102. for i := range fieldType.NumField() {
  103. field := fieldType.Field(i)
  104. tagValue := field.Tag.Get("json")
  105. tagName, _, _ := strings.Cut(tagValue, ",")
  106. if tagName == "-" {
  107. continue
  108. }
  109. if field.Anonymous && tagName == "" {
  110. appendJSONFieldNames(fieldMap, field.Type)
  111. continue
  112. }
  113. if tagName == "" {
  114. tagName = field.Name
  115. }
  116. fieldMap[tagName] = struct{}{}
  117. }
  118. }