generate-ip-mappings.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #!/usr/bin/env python3
  2. # usage: generate-ip-mappings.py
  3. # 2 files ipv4.csv and ipv6.csv will be generated
  4. # in sqlite3 terminal:
  5. #
  6. # .mode csv
  7. # .import 'full path to ipv4.csv' ip_mapping
  8. # .import 'full path to ipv6.csv' ipv6_mapping
  9. #
  10. # For query by ip:
  11. # SELECT * FROM ip_mapping WHERE `ip_start` <= ip-in-decimal AND `ip_end` >= ip-in-decimal ORDER BY `ip_start` DESC LIMIT 1;
  12. # SELECT * FROM ipv6_mapping WHERE `ip_start` <= upperIPv6("ipv6_addr") AND `ip_end` >= upperIPv6("ipv6_addr") ORDER BY `ip_start` DESC LIMIT 1;
  13. import socket
  14. import struct
  15. import csv
  16. import os
  17. import sys
  18. # import zipfile
  19. # import urllib.request
  20. def ip2int(addr):
  21. return struct.unpack("!I", socket.inet_aton(addr))[0]
  22. # Keep only the upper 64bit, as we only need that for geolocation
  23. def ipv62int64(addr):
  24. hi, lo = struct.unpack('!QQ', socket.inet_pton(socket.AF_INET6, addr))
  25. return hi
  26. CSV_WEB_LINK = 'https://download.db-ip.com/free/dbip-city-lite-2025-01.csv.gz'
  27. CSV_FILE = 'dbip-city-lite-2025-01.csv'
  28. if not os.path.exists(CSV_FILE):
  29. print("File = {} does not exist. Download it from = {} ".format(CSV_FILE, CSV_WEB_LINK))
  30. sys.exit(1)
  31. # Format: 1.0.0.0,1.0.0.255,OC,AU,Queensland,"South Brisbane",-27.4748,153.017
  32. with open(CSV_FILE, 'r') as csvfile, open('ipv4.csv', 'w') as ipv4, open('ipv6.csv', 'w') as ipv6:
  33. iplist = csv.reader(csvfile, delimiter=',', quotechar='"')
  34. for row in iplist:
  35. # Skip reserved range
  36. if row[3] == "ZZ":
  37. continue
  38. # Skip empty latitude and longitude
  39. if row[6] == "" or row[7] == "":
  40. continue
  41. if row[0].find(':') == -1:
  42. ipv4_line = True
  43. else:
  44. ipv4_line = False
  45. if ipv4_line:
  46. ip_start = ip2int(row[0])
  47. ip_end = ip2int(row[1])
  48. else:
  49. ip_start = ipv62int64(row[0])
  50. ip_end = ipv62int64(row[1])
  51. # Some IPv6 entries are duplicated after removing the lower 64bit
  52. if ip_start == ip_end:
  53. continue
  54. # Sqlite doesn't support unsigned int 64
  55. _int64_max = pow(2, 63) - 1
  56. if ip_start > _int64_max or ip_end > _int64_max:
  57. continue
  58. latitude = float(row[6])
  59. longitude = float(row[7])
  60. country = row[3]
  61. if ipv4_line:
  62. print('%d,%d,%f,%f,%s' % (ip_start, ip_end, latitude, longitude, country), file = ipv4)
  63. else:
  64. print('%d,%d,%f,%f,%s' % (ip_start, ip_end, latitude, longitude, country), file = ipv6)