IPGenerator.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import random
  2. import re
  3. class IPGenerator:
  4. # see wikipedia
  5. PRIVATE_IP_SEGMENTS = [
  6. "10.0.0.0/8",
  7. "172.16.0.0/12",
  8. "192.168.0.0/16"
  9. ]
  10. LOCALHOST_SEGMENT = "127.0.0.0/8"
  11. MULTICAST_SEGMENT = "224.0.0.0/4" # class D segment
  12. RESERVED_SEGMENT = "240.0.0.0/4" # class E segment
  13. ZERO_CONF_SEGMENT = "169.254.0.0/16" # link local segment
  14. # a number between 0 and 255, no leading zeros
  15. _IP_NUMBER_REGEXP = r"(25[0-5]|2[0-4]\d|1?[1-9]?\d)"
  16. # 4 numbers between 0 and 255, joined together with dots
  17. IP_REGEXP = r"{0}\.{0}\.{0}\.{0}".format(_IP_NUMBER_REGEXP)
  18. # an ip address with an optional cidr-suffix
  19. CIDR_REGEXP = IP_REGEXP + r"(\/(3[0-2]|[12]?\d)|)?"
  20. def __init__(self, include_private_ips = False, include_localhost = False,
  21. include_multicast = False, include_reserved = False,
  22. include_link_local = False, blacklist = None):
  23. self.blacklist = []
  24. self.generated_ips = set()
  25. if not include_private_ips:
  26. for segment in self.PRIVATE_IP_SEGMENTS:
  27. self.add_to_blacklist(segment)
  28. if not include_localhost:
  29. self.add_to_blacklist(self.LOCALHOST_SEGMENT)
  30. if not include_multicast:
  31. self.add_to_blacklist(self.MULTICAST_SEGMENT)
  32. if not include_reserved:
  33. self.add_to_blacklist(self.RESERVED_SEGMENT)
  34. if not include_link_local:
  35. self.add_to_blacklist(self.ZERO_CONF_SEGMENT)
  36. if blacklist:
  37. for segment in blacklist:
  38. self.add_to_blacklist(segment)
  39. def add_to_blacklist(self, ip_segment: str):
  40. self.blacklist.append(self._parse_cidr(ip_segment))
  41. def random_ip(self):
  42. while True:
  43. ip = random.randrange(0, 1 << 32)
  44. if not self._is_in_blacklist(ip) and ip not in self.generated_ips:
  45. self.generated_ips.add(ip)
  46. return self._ip_to_str(ip)
  47. def clear(self, clear_blacklist = True, clear_generated_ips = True):
  48. if clear_blacklist: self.blacklist.clear()
  49. if clear_generated_ips: self.generated_ips.clear()
  50. # parses a str in cidr-notation and returns a tuple with 2 elements
  51. # the first element is the ip-address as int, the second one is the cidr-suffix as int
  52. def _parse_cidr(self, ip_segment: str):
  53. match = re.match("^" + IPGenerator.CIDR_REGEXP + "$", ip_segment)
  54. if not match:
  55. raise ValueError("%s is no ip in cidr-notation" % ip_segment)
  56. ip = [int(match.group(i)) for i in range(1, 5)]
  57. suffix = 32 if not match.group(6) else int(match.group(6))
  58. numeric_ip = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | ip[3]
  59. return (numeric_ip & self._netmask(suffix), suffix)
  60. def _is_in_blacklist(self, ip: int):
  61. for black_ip, cidr in self.blacklist:
  62. if (ip & self._netmask(cidr)) == black_ip:
  63. return True
  64. return False
  65. def _netmask(self, suffix: int):
  66. ones = lambda x: (1 << x) - 1
  67. return ones(32) ^ ones(32 - suffix)
  68. def _ip_to_str(self, ip: int):
  69. return "%i.%i.%i.%i" % (
  70. ip >> 24,
  71. (ip >> 16) & 255,
  72. (ip >> 8) & 255,
  73. ip & 255
  74. )
  75. class MappingIPGenerator(IPGenerator):
  76. def __init__(self, *args, **kwargs):
  77. super().__init__(self, *args, **kwargs)
  78. self.mapping = {}
  79. def clear(self, clear_generated_ips = True, *args, **kwargs):
  80. super().clear(self, clear_generated_ips = clear_generated_ips, *args, **kwargs)
  81. if clear_generated_ips:
  82. self.mapping = {}
  83. def get_mapped_ip(self, key):
  84. if key not in self.mapping:
  85. self.mapping[key] = self.random_ip()
  86. return self.mapping[key]
  87. def __getitem__(self, item):
  88. return self.get_mapped_ip(item)