condition.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package router
  2. import (
  3. "fmt"
  4. "net/netip"
  5. "strings"
  6. "github.com/metacubex/mihomo/component/cidr"
  7. "github.com/metacubex/mihomo/component/geodata/strmatcher"
  8. "github.com/metacubex/mihomo/component/trie"
  9. )
  10. var matcherTypeMap = map[Domain_Type]strmatcher.Type{
  11. Domain_Plain: strmatcher.Substr,
  12. Domain_Regex: strmatcher.Regex,
  13. Domain_Domain: strmatcher.Domain,
  14. Domain_Full: strmatcher.Full,
  15. }
  16. func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
  17. matcherType, f := matcherTypeMap[domain.Type]
  18. if !f {
  19. return nil, fmt.Errorf("unsupported domain type %v", domain.Type)
  20. }
  21. matcher, err := matcherType.New(domain.Value)
  22. if err != nil {
  23. return nil, fmt.Errorf("failed to create domain matcher, base error: %s", err.Error())
  24. }
  25. return matcher, nil
  26. }
  27. type DomainMatcher interface {
  28. ApplyDomain(string) bool
  29. }
  30. type succinctDomainMatcher struct {
  31. set *trie.DomainSet
  32. otherMatchers []strmatcher.Matcher
  33. not bool
  34. }
  35. func (m *succinctDomainMatcher) ApplyDomain(domain string) bool {
  36. isMatched := m.set.Has(domain)
  37. if !isMatched {
  38. for _, matcher := range m.otherMatchers {
  39. isMatched = matcher.Match(domain)
  40. if isMatched {
  41. break
  42. }
  43. }
  44. }
  45. if m.not {
  46. isMatched = !isMatched
  47. }
  48. return isMatched
  49. }
  50. func NewSuccinctMatcherGroup(domains []*Domain, not bool) (DomainMatcher, error) {
  51. t := trie.New[struct{}]()
  52. m := &succinctDomainMatcher{
  53. not: not,
  54. }
  55. for _, d := range domains {
  56. switch d.Type {
  57. case Domain_Plain, Domain_Regex:
  58. matcher, err := matcherTypeMap[d.Type].New(d.Value)
  59. if err != nil {
  60. return nil, err
  61. }
  62. m.otherMatchers = append(m.otherMatchers, matcher)
  63. case Domain_Domain:
  64. err := t.Insert("+."+d.Value, struct{}{})
  65. if err != nil {
  66. return nil, err
  67. }
  68. case Domain_Full:
  69. err := t.Insert(d.Value, struct{}{})
  70. if err != nil {
  71. return nil, err
  72. }
  73. }
  74. }
  75. m.set = t.NewDomainSet()
  76. return m, nil
  77. }
  78. type v2rayDomainMatcher struct {
  79. matchers strmatcher.IndexMatcher
  80. not bool
  81. }
  82. func NewMphMatcherGroup(domains []*Domain, not bool) (DomainMatcher, error) {
  83. g := strmatcher.NewMphMatcherGroup()
  84. for _, d := range domains {
  85. matcherType, f := matcherTypeMap[d.Type]
  86. if !f {
  87. return nil, fmt.Errorf("unsupported domain type %v", d.Type)
  88. }
  89. _, err := g.AddPattern(d.Value, matcherType)
  90. if err != nil {
  91. return nil, err
  92. }
  93. }
  94. g.Build()
  95. return &v2rayDomainMatcher{
  96. matchers: g,
  97. not: not,
  98. }, nil
  99. }
  100. func (m *v2rayDomainMatcher) ApplyDomain(domain string) bool {
  101. isMatched := len(m.matchers.Match(strings.ToLower(domain))) > 0
  102. if m.not {
  103. isMatched = !isMatched
  104. }
  105. return isMatched
  106. }
  107. type GeoIPMatcher struct {
  108. countryCode string
  109. reverseMatch bool
  110. cidrSet *cidr.IpCidrSet
  111. }
  112. func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
  113. for _, cidr := range cidrs {
  114. addr, ok := netip.AddrFromSlice(cidr.Ip)
  115. if !ok {
  116. return fmt.Errorf("error when loading GeoIP: invalid IP: %s", cidr.Ip)
  117. }
  118. err := m.cidrSet.AddIpCidr(netip.PrefixFrom(addr, int(cidr.Prefix)))
  119. if err != nil {
  120. return fmt.Errorf("error when loading GeoIP: %w", err)
  121. }
  122. }
  123. return m.cidrSet.Merge()
  124. }
  125. func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
  126. m.reverseMatch = isReverseMatch
  127. }
  128. // Match returns true if the given ip is included by the GeoIP.
  129. func (m *GeoIPMatcher) Match(ip netip.Addr) bool {
  130. match := m.cidrSet.IsContain(ip)
  131. if m.reverseMatch {
  132. return !match
  133. }
  134. return match
  135. }
  136. // GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
  137. type GeoIPMatcherContainer struct {
  138. matchers []*GeoIPMatcher
  139. }
  140. // Add adds a new GeoIP set into the container.
  141. // If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
  142. func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
  143. if len(geoip.CountryCode) > 0 {
  144. for _, m := range c.matchers {
  145. if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
  146. return m, nil
  147. }
  148. }
  149. }
  150. m := &GeoIPMatcher{
  151. countryCode: geoip.CountryCode,
  152. reverseMatch: geoip.ReverseMatch,
  153. cidrSet: cidr.NewIpCidrSet(),
  154. }
  155. if err := m.Init(geoip.Cidr); err != nil {
  156. return nil, err
  157. }
  158. if len(geoip.CountryCode) > 0 {
  159. c.matchers = append(c.matchers, m)
  160. }
  161. return m, nil
  162. }
  163. var globalGeoIPContainer GeoIPMatcherContainer
  164. type MultiGeoIPMatcher struct {
  165. matchers []*GeoIPMatcher
  166. }
  167. func NewGeoIPMatcher(geoip *GeoIP) (*GeoIPMatcher, error) {
  168. matcher, err := globalGeoIPContainer.Add(geoip)
  169. if err != nil {
  170. return nil, err
  171. }
  172. return matcher, nil
  173. }
  174. func (m *MultiGeoIPMatcher) ApplyIp(ip netip.Addr) bool {
  175. for _, matcher := range m.matchers {
  176. if matcher.Match(ip) {
  177. return true
  178. }
  179. }
  180. return false
  181. }
  182. func NewMultiGeoIPMatcher(geoips []*GeoIP) (*MultiGeoIPMatcher, error) {
  183. var matchers []*GeoIPMatcher
  184. for _, geoip := range geoips {
  185. matcher, err := globalGeoIPContainer.Add(geoip)
  186. if err != nil {
  187. return nil, err
  188. }
  189. matchers = append(matchers, matcher)
  190. }
  191. matcher := &MultiGeoIPMatcher{
  192. matchers: matchers,
  193. }
  194. return matcher, nil
  195. }