geodb.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package geodb
  2. import (
  3. _ "embed"
  4. "net/http"
  5. "os"
  6. "sync"
  7. "time"
  8. "imuslab.com/zoraxy/mod/database"
  9. "imuslab.com/zoraxy/mod/info/logger"
  10. "imuslab.com/zoraxy/mod/netutils"
  11. "imuslab.com/zoraxy/mod/utils"
  12. )
  13. //go:embed geoipv4.csv
  14. var geoipv4 []byte //Geodb dataset for ipv4
  15. //go:embed geoipv6.csv
  16. var geoipv6 []byte //Geodb dataset for ipv6
  17. type Store struct {
  18. geodb [][]string //Parsed geodb list
  19. geodbIpv6 [][]string //Parsed geodb list for ipv6
  20. geotrie *trie
  21. geotrieIpv6 *trie
  22. sysdb *database.Database
  23. slowLookupCacheIpv4 sync.Map //Cache for slow lookup, ip -> cc
  24. slowLookupCacheIpv6 sync.Map //Cache for slow lookup ipv6, ip -> cc
  25. cacheClearTicker *time.Ticker //Ticker for clearing cache
  26. cacheClearTickerStopChan chan bool //Stop channel for cache clear ticker
  27. option *StoreOptions
  28. }
  29. type StoreOptions struct {
  30. AllowSlowIpv4LookUp bool
  31. AllowSlowIpv6Lookup bool
  32. Logger *logger.Logger
  33. SlowLookupCacheClearInterval time.Duration //Clear slow lookup cache interval
  34. }
  35. type CountryInfo struct {
  36. CountryIsoCode string
  37. ContinetCode string
  38. }
  39. func NewGeoDb(sysdb *database.Database, option *StoreOptions) (*Store, error) {
  40. //Check if external geoDB data is available
  41. if utils.FileExists("./conf/geodb/geoipv4.csv") {
  42. externalV4Db, err := os.ReadFile("./conf/geodb/geoipv4.csv")
  43. if err == nil {
  44. option.Logger.PrintAndLog("GeoDB", "External GeoDB data found, using external IPv4 GeoIP data", nil)
  45. geoipv4 = externalV4Db
  46. }
  47. }
  48. if utils.FileExists("./conf/geodb/geoipv6.csv") {
  49. externalV6Db, err := os.ReadFile("./conf/geodb/geoipv6.csv")
  50. if err == nil {
  51. option.Logger.PrintAndLog("GeoDB", "External GeoDB data found, using external IPv6 GeoIP data", nil)
  52. geoipv6 = externalV6Db
  53. }
  54. }
  55. parsedGeoData, err := parseCSV(geoipv4)
  56. if err != nil {
  57. return nil, err
  58. }
  59. parsedGeoDataIpv6, err := parseCSV(geoipv6)
  60. if err != nil {
  61. return nil, err
  62. }
  63. var ipv4Trie *trie
  64. if !option.AllowSlowIpv4LookUp {
  65. ipv4Trie = constrctTrieTree(parsedGeoData)
  66. }
  67. var ipv6Trie *trie
  68. if !option.AllowSlowIpv6Lookup {
  69. ipv6Trie = constrctTrieTree(parsedGeoDataIpv6)
  70. }
  71. if option.SlowLookupCacheClearInterval == 0 {
  72. option.SlowLookupCacheClearInterval = 30 * time.Minute
  73. }
  74. //Create a new store
  75. thisGeoDBStore := &Store{
  76. geodb: parsedGeoData,
  77. geotrie: ipv4Trie,
  78. geodbIpv6: parsedGeoDataIpv6,
  79. geotrieIpv6: ipv6Trie,
  80. sysdb: sysdb,
  81. slowLookupCacheIpv4: sync.Map{},
  82. slowLookupCacheIpv6: sync.Map{},
  83. cacheClearTicker: time.NewTicker(option.SlowLookupCacheClearInterval),
  84. cacheClearTickerStopChan: make(chan bool),
  85. option: option,
  86. }
  87. //Start cache clear ticker
  88. if option.AllowSlowIpv4LookUp || option.AllowSlowIpv6Lookup {
  89. go func(store *Store) {
  90. for {
  91. select {
  92. case <-store.cacheClearTickerStopChan:
  93. return
  94. case <-thisGeoDBStore.cacheClearTicker.C:
  95. thisGeoDBStore.slowLookupCacheIpv4 = sync.Map{}
  96. thisGeoDBStore.slowLookupCacheIpv6 = sync.Map{}
  97. }
  98. }
  99. }(thisGeoDBStore)
  100. }
  101. return thisGeoDBStore, nil
  102. }
  103. func (s *Store) ResolveCountryCodeFromIP(ipstring string) (*CountryInfo, error) {
  104. cc := s.search(ipstring)
  105. return &CountryInfo{
  106. CountryIsoCode: cc,
  107. ContinetCode: "",
  108. }, nil
  109. }
  110. // Close the store
  111. func (s *Store) Close() {
  112. if s.option.AllowSlowIpv4LookUp || s.option.AllowSlowIpv6Lookup {
  113. //Stop cache clear ticker
  114. s.cacheClearTickerStopChan <- true
  115. }
  116. }
  117. func (s *Store) GetRequesterCountryISOCode(r *http.Request) string {
  118. ipAddr := netutils.GetRequesterIP(r)
  119. if ipAddr == "" {
  120. return ""
  121. }
  122. if netutils.IsPrivateIP(ipAddr) {
  123. return "LAN"
  124. }
  125. countryCode, err := s.ResolveCountryCodeFromIP(ipAddr)
  126. if err != nil {
  127. return ""
  128. }
  129. return countryCode.CountryIsoCode
  130. }