PcapAddressOperations.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. from random import choice
  2. from ID2TLib import Statistics
  3. from ID2TLib.IPv4 import IPAddress
  4. is_ipv4 = IPAddress.is_ipv4
  5. class PcapAddressOperations():
  6. def __init__(self, statistics: Statistics, uncertain_ip_mult: int=3):
  7. """
  8. Initializes a pcap information extractor that uses the provided statistics for its operations.
  9. :param statistics: The statistics of the pcap file
  10. :param uncertain_ip_mult: the mutliplier to create new address space when the remaining observed space has been drained
  11. """
  12. self.statistics = statistics
  13. self.UNCERTAIN_IPSPACE_MULTIPLIER = uncertain_ip_mult
  14. self._init_ipaddress_ops()
  15. def get_probable_router_mac(self):
  16. """
  17. Returns the most probable router MAC address based on the most used MAC address in the statistics.
  18. """
  19. self.probable_router_mac, count = self.statistics.process_db_query("most_used(macAddress)", print_results=False)[0]
  20. return self.probable_router_mac # and count as a measure of certainty?
  21. def pcap_contains_priv_ips(self):
  22. """
  23. Returns True if the provided traffic contains private IPs, otherwise False.
  24. """
  25. return self.contains_priv_ips
  26. def get_local_address_range(self):
  27. """
  28. Returns a tuple with the start and end of the observed local IP range.
  29. """
  30. return str(self.min_local_ip), str(self.max_local_ip)
  31. def get_count_rem_local_ips(self):
  32. """
  33. Returns the number of local IPs in the pcap file that have not aldready been returned by get_existing_local_ips.
  34. """
  35. return len(self.remaining_local_ips)
  36. def get_existing_local_ips(self, count: int=1):
  37. """
  38. Returns the given number of local IPs that are existent in the pcap file.
  39. :param count: the number of local IPs to return
  40. :return: the chosen local IPs
  41. """
  42. if count > len(self.remaining_local_ips):
  43. print("Warning: There are no more {} local IPs in the .pcap file. Returning all remaining local IPs.".format(count))
  44. total = min(len(self.remaining_local_ips), count)
  45. retr_local_ips = []
  46. local_ips = self.remaining_local_ips
  47. for _ in range(0, total):
  48. random_local_ip = choice(sorted(local_ips))
  49. retr_local_ips.append(str(random_local_ip))
  50. local_ips.remove(random_local_ip)
  51. # if count == 1:
  52. # return retr_local_ips[0]
  53. return retr_local_ips
  54. # also use IPs below minimum observed IP?
  55. # offset for later, start at x after minimum? e.g. start at 192.168.0.100
  56. # exclude the last IP of an IP segment because its broadcast?
  57. def get_new_local_ips(self, count: int=1):
  58. """
  59. Returns in the pcap not existent local IPs that are in proximity of the observed local IPs. IPs can be returned
  60. that are either between the minimum and maximum observed IP and are therefore considered certain
  61. or that are above the observed maximum address, are more likely to not belong to the local network
  62. and are therefore considered uncertain.
  63. :param count: the number of new local IPs to return
  64. :return: the newly created local IP addresses
  65. """
  66. unused_local_ips = self.unused_local_ips
  67. uncertain_local_ips = self.uncertain_local_ips
  68. # warning reasonable?
  69. if count > len(unused_local_ips):
  70. print("Warning: there are no {0} unused certain local IPs in the .pcap file.\n \
  71. Returning {1} certain and {2} uncertain local IPs.".format(count, len(unused_local_ips), count-len(unused_local_ips)))
  72. count_certain = min(count, len(unused_local_ips))
  73. retr_local_ips = []
  74. for _ in range(0, count_certain):
  75. random_local_ip = choice(sorted(unused_local_ips))
  76. retr_local_ips.append(str(random_local_ip))
  77. unused_local_ips.remove(random_local_ip)
  78. # retrieve uncertain local ips
  79. if count_certain < count:
  80. count_uncertain = count - count_certain
  81. # check if new uncertain IPs have to be created
  82. if len(uncertain_local_ips) < count_uncertain:
  83. ipspace_multiplier = self.UNCERTAIN_IPSPACE_MULTIPLIER
  84. max_new_ip = self.max_uncertain_local_ip.to_int() + ipspace_multiplier * count_uncertain
  85. count_new_ips = max_new_ip - self.max_uncertain_local_ip.to_int()
  86. # create ipspace_multiplier * count_uncertain new uncertain local IP addresses
  87. last_gen_ip = None
  88. for i in range(1, count_new_ips + 1):
  89. ip = IPAddress.from_int(self.max_uncertain_local_ip.to_int() + i)
  90. # exclude the definite broadcast address
  91. if self.priv_ip_segment:
  92. if ip.to_int() >= self.priv_ip_segment.last_address().to_int():
  93. break
  94. uncertain_local_ips.add(ip)
  95. last_gen_ip = ip
  96. self.max_uncertain_local_ip = last_gen_ip
  97. # choose the uncertain IPs to return
  98. total_uncertain = min(count_uncertain, len(uncertain_local_ips))
  99. for _ in range(0, total_uncertain):
  100. random_local_ip = choice(sorted(uncertain_local_ips))
  101. retr_local_ips.append(str(random_local_ip))
  102. uncertain_local_ips.remove(random_local_ip)
  103. # if count == 1:
  104. # return retr_local_ips[0]
  105. return retr_local_ips
  106. def get_existing_external_ips(self, count: int=1):
  107. """
  108. Returns the given number of external IPs that are existent in the pcap file.
  109. :param count: the number of external IPs to return
  110. :return: the chosen external IPs
  111. """
  112. # reasonable to include this?
  113. if not (len(self.external_ips) > 0):
  114. print("Warning: .pcap does not contain any external ips.")
  115. return []
  116. if count > len(self.remaining_external_ips):
  117. print("Warning: There are no more %d external IPs in the .pcap file.\n" % count +
  118. "Returning all %d existing external IPs." % len(self.remaining_external_ips))
  119. total = min(len(self.remaining_external_ips), count)
  120. retr_external_ips = []
  121. external_ips = self.remaining_external_ips
  122. for _ in range(0, total):
  123. random_external_ip = choice(sorted(external_ips))
  124. retr_external_ips.append(str(random_external_ip))
  125. external_ips.remove(random_external_ip)
  126. # if count == 1:
  127. # return retr_external_ips[0]
  128. return retr_external_ips
  129. def _init_ipaddress_ops(self):
  130. """
  131. Load and process data needed to perform functions on the IP addresses contained in the statistics
  132. """
  133. # retrieve local and external IPs
  134. all_ips_str = set(self.statistics.process_db_query("all(ipAddress)", print_results=False))
  135. external_ips_str = set(self.statistics.process_db_query("ipAddress(macAddress=%s)" % self.get_probable_router_mac(), print_results=False))
  136. local_ips_str = all_ips_str - external_ips_str
  137. external_ips = set()
  138. local_ips = set()
  139. self.contains_priv_ips = False
  140. self.priv_ip_segment = None
  141. # convert local IP strings to IPv4.IPAddress representation
  142. for ip in local_ips_str:
  143. if is_ipv4(ip):
  144. ip = IPAddress.parse(ip)
  145. if ip.is_private() and not self.contains_priv_ips:
  146. self.contains_priv_ips = True
  147. self.priv_ip_segment = ip.get_private_segment()
  148. if (not str(ip) == "255.255.255.255") and (not ip.is_localhost()) and (not ip.is_multicast()) and (not ip.is_reserved()) and (not ip.is_zero_conf()):
  149. local_ips.add(ip)
  150. # convert external IP strings to IPv4.IPAddress representation
  151. for ip in external_ips_str:
  152. if is_ipv4(ip):
  153. ip = IPAddress.parse(ip)
  154. # if router MAC can definitely be mapped to local/private IP, add it to local_ips
  155. if ip.is_private():
  156. local_ips.add(ip)
  157. # new function in IPv4 to shorten this?
  158. # exclude local broadcast address
  159. elif (not str(ip) == "255.255.255.255") and (not ip.is_localhost()) and (not ip.is_multicast()) and (not ip.is_reserved()) and (not ip.is_zero_conf()):
  160. external_ips.add(ip)
  161. min_local_ip, max_local_ip = min(local_ips), max(local_ips)
  162. # save the certain unused local IPs of the network
  163. unused_local_ips = set()
  164. for i in range(min_local_ip.to_int() + 1, max_local_ip.to_int()):
  165. ip = IPAddress.from_int(i)
  166. if not ip in local_ips:
  167. unused_local_ips.add(ip)
  168. # save the gathered information for efficient later use
  169. self.external_ips = frozenset(external_ips)
  170. self.remaining_external_ips = external_ips
  171. self.min_local_ip, self.max_local_ip = min_local_ip, max_local_ip
  172. self.max_uncertain_local_ip = max_local_ip
  173. self.local_ips = frozenset(local_ips)
  174. self.remaining_local_ips = local_ips
  175. self.unused_local_ips = unused_local_ips
  176. self.uncertain_local_ips = set()