1
0

slowSearch.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package geodb
  2. import (
  3. "errors"
  4. "math/big"
  5. "net"
  6. )
  7. /*
  8. slowSearch.go
  9. This script implement the slow search method for ip to country code
  10. lookup. If you have the memory allocation for near O(1) lookup,
  11. you should not be using slow search mode.
  12. */
  13. func ipv4ToUInt32(ip net.IP) uint32 {
  14. ip = ip.To4()
  15. return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
  16. }
  17. func isIPv4InRange(startIP, endIP, testIP string) (bool, error) {
  18. start := net.ParseIP(startIP)
  19. end := net.ParseIP(endIP)
  20. test := net.ParseIP(testIP)
  21. if start == nil || end == nil || test == nil {
  22. return false, errors.New("invalid IP address format")
  23. }
  24. startUint := ipv4ToUInt32(start)
  25. endUint := ipv4ToUInt32(end)
  26. testUint := ipv4ToUInt32(test)
  27. return testUint >= startUint && testUint <= endUint, nil
  28. }
  29. func isIPv6InRange(startIP, endIP, testIP string) (bool, error) {
  30. start := net.ParseIP(startIP)
  31. end := net.ParseIP(endIP)
  32. test := net.ParseIP(testIP)
  33. if start == nil || end == nil || test == nil {
  34. return false, errors.New("invalid IP address format")
  35. }
  36. startInt := new(big.Int).SetBytes(start.To16())
  37. endInt := new(big.Int).SetBytes(end.To16())
  38. testInt := new(big.Int).SetBytes(test.To16())
  39. return testInt.Cmp(startInt) >= 0 && testInt.Cmp(endInt) <= 0, nil
  40. }
  41. // Slow country code lookup for
  42. func (s *Store) slowSearchIpv4(ipAddr string) string {
  43. if isReservedIP(ipAddr) {
  44. return ""
  45. }
  46. //Check if already in cache
  47. cc := s.GetSlowSearchCachedIpv4(ipAddr)
  48. if cc != "" {
  49. return cc
  50. }
  51. for _, ipRange := range s.geodb {
  52. startIp := ipRange[0]
  53. endIp := ipRange[1]
  54. cc := ipRange[2]
  55. inRange, _ := isIPv4InRange(startIp, endIp, ipAddr)
  56. if inRange {
  57. //Add to cache
  58. s.slowLookupCacheIpv4.Store(ipAddr, cc)
  59. return cc
  60. }
  61. }
  62. return ""
  63. }
  64. func (s *Store) slowSearchIpv6(ipAddr string) string {
  65. if isReservedIP(ipAddr) {
  66. return ""
  67. }
  68. //Check if already in cache
  69. cc := s.GetSlowSearchCachedIpv6(ipAddr)
  70. if cc != "" {
  71. return cc
  72. }
  73. for _, ipRange := range s.geodbIpv6 {
  74. startIp := ipRange[0]
  75. endIp := ipRange[1]
  76. cc := ipRange[2]
  77. inRange, _ := isIPv6InRange(startIp, endIp, ipAddr)
  78. if inRange {
  79. //Add to cache
  80. s.slowLookupCacheIpv6.Store(ipAddr, cc)
  81. return cc
  82. }
  83. }
  84. return ""
  85. }
  86. // GetSlowSearchCachedIpv4 return the country code for the given ipv4 address, return empty string if not found
  87. func (s *Store) GetSlowSearchCachedIpv4(ipAddr string) string {
  88. cc, ok := s.slowLookupCacheIpv4.Load(ipAddr)
  89. if ok {
  90. return cc.(string)
  91. }
  92. return ""
  93. }
  94. // GetSlowSearchCachedIpv6 return the country code for the given ipv6 address, return empty string if not found
  95. func (s *Store) GetSlowSearchCachedIpv6(ipAddr string) string {
  96. cc, ok := s.slowLookupCacheIpv6.Load(ipAddr)
  97. if ok {
  98. return cc.(string)
  99. }
  100. return ""
  101. }