PcapAddressOperations.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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_priv_address_range(self):
  27. """
  28. Returns a tuple with the start and end of the observed private IP range.
  29. """
  30. # better way to handle error?
  31. if not self.pcap_contains_priv_ips():
  32. print("Error: .pcap does not contain any private ips.")
  33. return -1, -1
  34. return str(self.min_priv_ip), str(self.max_priv_ip)
  35. def get_count_rem_priv_ips(self):
  36. """
  37. Returns the number of private IPs in the pcap file that have not aldready been returned by get_existing_priv_ips.
  38. """
  39. return len(self.remaining_priv_ips)
  40. def get_existing_priv_ips(self, count: int=1):
  41. """
  42. Returns the given number of private IPs that are existent in the pcap file.
  43. :param count: the number of IPs to return
  44. :return: the chosen private IPs
  45. """
  46. # reasonable to include this?
  47. if not self.pcap_contains_priv_ips():
  48. print("Warning: .pcap does not contain any private ips.")
  49. return []
  50. if count > len(self.priv_ips):
  51. print("Warning: There are no {} priv IPs in the .pcap file. Returning all existing priv IPs.".format(count))
  52. total = min(len(self.priv_ips), count)
  53. retr_priv_ips = []
  54. priv_ips = self.remaining_priv_ips
  55. for _ in range(0, total):
  56. random_priv_ip = choice(tuple(priv_ips))
  57. retr_priv_ips.append(str(random_priv_ip))
  58. priv_ips.remove(random_priv_ip)
  59. return retr_priv_ips
  60. # also use IPs below minimum observed IP?
  61. # offset for later, start at x after minimum? e.g. start at 192.168.0.100
  62. # exclude the last IP of an IP segment because its broadcast?
  63. def get_new_priv_ips(self, count: int=1):
  64. """
  65. Returns in the pcap not existent private IPs that match the used segment. IPs can be returned
  66. that are either between the minimum and maximum observed IP and are therefore considered certain
  67. or that are above the observed maximum address, are more likely to not belong to the network using the
  68. private IP segment and are therefore considered uncertain.
  69. :param count: the number of IPs to return
  70. :return: the newly created private IP addresses
  71. """
  72. if not self.pcap_contains_priv_ips():
  73. print("Error: .pcap does not contain any private ips.")
  74. return []
  75. unused_priv_ips = self.unused_priv_ips
  76. uncertain_priv_ips = self.uncertain_priv_ips
  77. # warning reasonable?
  78. if count > len(unused_priv_ips):
  79. print("Warning: there are no {0} unused certain priv IPs in the .pcap file.\n \
  80. Returning {1} certain and {2} uncertain priv IPs.".format(count, len(unused_priv_ips), count-len(unused_priv_ips)))
  81. count_certain = min(count, len(unused_priv_ips))
  82. retr_priv_ips = []
  83. for _ in range(0, count_certain):
  84. random_priv_ip = choice(tuple(unused_priv_ips))
  85. retr_priv_ips.append(str(random_priv_ip))
  86. unused_priv_ips.remove(random_priv_ip)
  87. # retrieve uncertain priv ips
  88. if count_certain < count:
  89. count_uncertain = count - count_certain
  90. # check if new uncertain IPs have to be created
  91. if len(uncertain_priv_ips) < count_uncertain:
  92. ipspace_multiplier = self.UNCERTAIN_IPSPACE_MULTIPLIER
  93. max_new_ip = self.max_uncertain_priv_ip.to_int() + ipspace_multiplier * count_uncertain
  94. # adjust IP space multiplier and prevent broadcast address of private segment from being chosen as new IP
  95. while max_new_ip >= self.priv_ip_segment.last_address().to_int():
  96. max_new_ip -= 1
  97. count_new_ips = max_new_ip - self.max_uncertain_priv_ip.to_int()
  98. if count_new_ips < count_uncertain:
  99. print("Error: Cannot generate enough new private IPs because they would exceed the maximum private segment IP. Returning {}.".format(count_new_ips))
  100. # create ipspace_multiplier * count_uncertain new uncertain IP addresses
  101. last_gen_ip = None
  102. for i in range(1, count_new_ips + 1):
  103. ip = IPAddress.from_int(self.max_uncertain_priv_ip.to_int() + i)
  104. # exclude the broadcast address
  105. if ip.to_int() >= self.priv_ip_segment.last_address().to_int():
  106. break
  107. uncertain_priv_ips.add(ip)
  108. last_gen_ip = ip
  109. self.max_uncertain_priv_ip = last_gen_ip
  110. # choose the uncertain IPs to return
  111. total_uncertain = min(count_uncertain, len(uncertain_priv_ips))
  112. for _ in range(0, total_uncertain):
  113. random_priv_ip = choice(tuple(uncertain_priv_ips))
  114. retr_priv_ips.append(str(random_priv_ip))
  115. uncertain_priv_ips.remove(random_priv_ip)
  116. return retr_priv_ips
  117. def _init_ipaddress_ops(self):
  118. """
  119. Load and process data needed to perform functions on the IP addresses contained in the statistics
  120. """
  121. all_ips = self.statistics.process_db_query("all(ipAddress)", print_results=False)
  122. # find the private IP segment in use
  123. priv_ip_segment = None
  124. self.contains_priv_ips = False
  125. first_priv_ip = None
  126. first_priv_ip_idx = -1
  127. # for that iterate over all IPs until the first private IP is found
  128. for i, ip in enumerate(all_ips):
  129. if not is_ipv4(ip):
  130. continue
  131. ip = IPAddress.parse(ip)
  132. if ip.is_private():
  133. priv_ip_segment = ip.get_private_segment()
  134. first_priv_ip_idx = i
  135. first_priv_ip = ip
  136. self.contains_priv_ips = True
  137. break
  138. if not self.contains_priv_ips:
  139. #print("The Pcap File does not contain any private IPs")
  140. return
  141. # get minimum and maximum seen private IP. The addresses in-bewteen are considered
  142. # as certain to be part of the network the pcap traffic is from
  143. min_priv_ip, max_priv_ip = first_priv_ip, first_priv_ip
  144. priv_ips = {first_priv_ip}
  145. for ip in all_ips[first_priv_ip_idx+1:]:
  146. if not is_ipv4(ip):
  147. continue
  148. ip = IPAddress.parse(ip)
  149. if ip in priv_ip_segment:
  150. priv_ips.add(ip)
  151. if ip > max_priv_ip:
  152. max_priv_ip = ip
  153. elif ip < min_priv_ip:
  154. min_priv_ip = ip
  155. # save the certain unused priv IPs of the network
  156. unused_priv_ips = set()
  157. for i in range (min_priv_ip.to_int() + 1, max_priv_ip.to_int()):
  158. ip = IPAddress.from_int(i)
  159. if not ip in priv_ips:
  160. unused_priv_ips.add(ip)
  161. # save the gathered information for efficient later use
  162. self.min_priv_ip, self.max_priv_ip = min_priv_ip, max_priv_ip
  163. self.max_uncertain_priv_ip = max_priv_ip
  164. self.priv_ips = frozenset(priv_ips)
  165. self.remaining_priv_ips = priv_ips
  166. self.unused_priv_ips = unused_priv_ips
  167. self.generated_uncertain_ips = set()
  168. self.uncertain_priv_ips = set()
  169. self.priv_ip_segment = priv_ip_segment