geodb.go 3.3 KB

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