geoip.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package common
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/metacubex/mihomo/component/geodata"
  6. "github.com/metacubex/mihomo/component/geodata/router"
  7. "github.com/metacubex/mihomo/component/mmdb"
  8. "github.com/metacubex/mihomo/component/resolver"
  9. C "github.com/metacubex/mihomo/constant"
  10. "github.com/metacubex/mihomo/log"
  11. )
  12. type GEOIP struct {
  13. *Base
  14. country string
  15. adapter string
  16. noResolveIP bool
  17. isSourceIP bool
  18. geoIPMatcher *router.GeoIPMatcher
  19. recodeSize int
  20. }
  21. var _ C.Rule = (*GEOIP)(nil)
  22. func (g *GEOIP) RuleType() C.RuleType {
  23. if g.isSourceIP {
  24. return C.SrcGEOIP
  25. }
  26. return C.GEOIP
  27. }
  28. func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
  29. ip := metadata.DstIP
  30. if g.isSourceIP {
  31. ip = metadata.SrcIP
  32. }
  33. if !ip.IsValid() {
  34. return false, ""
  35. }
  36. if g.country == "lan" {
  37. return ip.IsPrivate() ||
  38. ip.IsUnspecified() ||
  39. ip.IsLoopback() ||
  40. ip.IsMulticast() ||
  41. ip.IsLinkLocalUnicast() ||
  42. resolver.IsFakeBroadcastIP(ip), g.adapter
  43. }
  44. for _, code := range metadata.DstGeoIP {
  45. if g.country == code {
  46. return true, g.adapter
  47. }
  48. }
  49. if !C.GeodataMode {
  50. if g.isSourceIP {
  51. codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
  52. for _, code := range codes {
  53. if g.country == code {
  54. return true, g.adapter
  55. }
  56. }
  57. return false, g.adapter
  58. }
  59. if metadata.DstGeoIP != nil {
  60. return false, g.adapter
  61. }
  62. metadata.DstGeoIP = mmdb.IPInstance().LookupCode(ip.AsSlice())
  63. for _, code := range metadata.DstGeoIP {
  64. if g.country == code {
  65. return true, g.adapter
  66. }
  67. }
  68. return false, g.adapter
  69. }
  70. match := g.geoIPMatcher.Match(ip)
  71. if match && !g.isSourceIP {
  72. metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
  73. }
  74. return match, g.adapter
  75. }
  76. func (g *GEOIP) Adapter() string {
  77. return g.adapter
  78. }
  79. func (g *GEOIP) Payload() string {
  80. return g.country
  81. }
  82. func (g *GEOIP) ShouldResolveIP() bool {
  83. return !g.noResolveIP
  84. }
  85. func (g *GEOIP) GetCountry() string {
  86. return g.country
  87. }
  88. func (g *GEOIP) GetIPMatcher() *router.GeoIPMatcher {
  89. return g.geoIPMatcher
  90. }
  91. func (g *GEOIP) GetRecodeSize() int {
  92. return g.recodeSize
  93. }
  94. func NewGEOIP(country string, adapter string, isSrc, noResolveIP bool) (*GEOIP, error) {
  95. if err := geodata.InitGeoIP(); err != nil {
  96. log.Errorln("can't initial GeoIP: %s", err)
  97. return nil, err
  98. }
  99. country = strings.ToLower(country)
  100. if !C.GeodataMode || country == "lan" {
  101. geoip := &GEOIP{
  102. Base: &Base{},
  103. country: country,
  104. adapter: adapter,
  105. noResolveIP: noResolveIP,
  106. isSourceIP: isSrc,
  107. }
  108. return geoip, nil
  109. }
  110. geoIPMatcher, size, err := geodata.LoadGeoIPMatcher(country)
  111. if err != nil {
  112. return nil, fmt.Errorf("[GeoIP] %w", err)
  113. }
  114. log.Infoln("Start initial GeoIP rule %s => %s, records: %d", country, adapter, size)
  115. geoip := &GEOIP{
  116. Base: &Base{},
  117. country: country,
  118. adapter: adapter,
  119. noResolveIP: noResolveIP,
  120. isSourceIP: isSrc,
  121. geoIPMatcher: geoIPMatcher,
  122. recodeSize: size,
  123. }
  124. return geoip, nil
  125. }