|
@@ -31,226 +31,192 @@ class PcapAddressOperations():
|
|
|
"""
|
|
|
return self.contains_priv_ips
|
|
|
|
|
|
- def get_priv_address_range(self):
|
|
|
+ def get_local_address_range(self):
|
|
|
"""
|
|
|
- Returns a tuple with the start and end of the observed private IP range.
|
|
|
+ Returns a tuple with the start and end of the observed local IP range.
|
|
|
"""
|
|
|
- # better way to handle error?
|
|
|
- if not self.pcap_contains_priv_ips():
|
|
|
- print("Error: .pcap does not contain any private ips.")
|
|
|
- return -1, -1
|
|
|
- return str(self.min_priv_ip), str(self.max_priv_ip)
|
|
|
+ return str(self.min_local_ip), str(self.max_local_ip)
|
|
|
|
|
|
- def get_count_rem_priv_ips(self):
|
|
|
+ def get_count_rem_local_ips(self):
|
|
|
"""
|
|
|
- Returns the number of private IPs in the pcap file that have not aldready been returned by get_existing_priv_ips.
|
|
|
+ Returns the number of local IPs in the pcap file that have not aldready been returned by get_existing_local_ips.
|
|
|
"""
|
|
|
- return len(self.remaining_priv_ips)
|
|
|
+ return len(self.remaining_local_ips)
|
|
|
|
|
|
- def get_existing_priv_ips(self, count: int=1):
|
|
|
+ def get_existing_local_ips(self, count: int=1):
|
|
|
"""
|
|
|
- Returns the given number of private IPs that are existent in the pcap file.
|
|
|
+ Returns the given number of local IPs that are existent in the pcap file.
|
|
|
|
|
|
- :param count: the number of IPs to return
|
|
|
- :return: the chosen private IPs
|
|
|
+ :param count: the number of local IPs to return
|
|
|
+ :return: the chosen local IPs
|
|
|
"""
|
|
|
|
|
|
- # reasonable to include this?
|
|
|
- if not self.pcap_contains_priv_ips():
|
|
|
- print("Warning: .pcap does not contain any private ips.")
|
|
|
- return []
|
|
|
+ if count > len(self.remaining_local_ips):
|
|
|
+ print("Warning: There are no more {} local IPs in the .pcap file. Returning all remaining local IPs.".format(count))
|
|
|
|
|
|
- if count > len(self.remaining_priv_ips):
|
|
|
- print("Warning: There are no more {} private IPs in the .pcap file. Returning all remaining private IPs.".format(count))
|
|
|
+ total = min(len(self.remaining_local_ips), count)
|
|
|
|
|
|
- total = min(len(self.remaining_priv_ips), count)
|
|
|
-
|
|
|
- retr_priv_ips = []
|
|
|
- priv_ips = self.remaining_priv_ips
|
|
|
+ retr_local_ips = []
|
|
|
+ local_ips = self.remaining_local_ips
|
|
|
for _ in range(0, total):
|
|
|
- random_priv_ip = choice(tuple(priv_ips))
|
|
|
- retr_priv_ips.append(str(random_priv_ip))
|
|
|
- priv_ips.remove(random_priv_ip)
|
|
|
+ random_local_ip = choice(sorted(local_ips))
|
|
|
+ retr_local_ips.append(str(random_local_ip))
|
|
|
+ local_ips.remove(random_local_ip)
|
|
|
|
|
|
# if count == 1:
|
|
|
- # return retr_priv_ips[0]
|
|
|
+ # return retr_local_ips[0]
|
|
|
|
|
|
- return retr_priv_ips
|
|
|
+ return retr_local_ips
|
|
|
|
|
|
# also use IPs below minimum observed IP?
|
|
|
# offset for later, start at x after minimum? e.g. start at 192.168.0.100
|
|
|
# exclude the last IP of an IP segment because its broadcast?
|
|
|
- def get_new_priv_ips(self, count: int=1):
|
|
|
+ def get_new_local_ips(self, count: int=1):
|
|
|
"""
|
|
|
- Returns in the pcap not existent private IPs that match the used segment. IPs can be returned
|
|
|
+ Returns in the pcap not existent local IPs that are in proximity of the observed local IPs. IPs can be returned
|
|
|
that are either between the minimum and maximum observed IP and are therefore considered certain
|
|
|
- or that are above the observed maximum address, are more likely to not belong to the network using the
|
|
|
- private IP segment and are therefore considered uncertain.
|
|
|
+ or that are above the observed maximum address, are more likely to not belong to the local network
|
|
|
+ and are therefore considered uncertain.
|
|
|
|
|
|
- :param count: the number of IPs to return
|
|
|
- :return: the newly created private IP addresses
|
|
|
+ :param count: the number of new local IPs to return
|
|
|
+ :return: the newly created local IP addresses
|
|
|
"""
|
|
|
|
|
|
- if not self.pcap_contains_priv_ips():
|
|
|
- print("Error: .pcap does not contain any private ips.")
|
|
|
- return []
|
|
|
-
|
|
|
- unused_priv_ips = self.unused_priv_ips
|
|
|
- uncertain_priv_ips = self.uncertain_priv_ips
|
|
|
+ unused_local_ips = self.unused_local_ips
|
|
|
+ uncertain_local_ips = self.uncertain_local_ips
|
|
|
|
|
|
# warning reasonable?
|
|
|
- if count > len(unused_priv_ips):
|
|
|
- print("Warning: there are no {0} unused certain priv IPs in the .pcap file.\n \
|
|
|
- Returning {1} certain and {2} uncertain priv IPs.".format(count, len(unused_priv_ips), count-len(unused_priv_ips)))
|
|
|
+ if count > len(unused_local_ips):
|
|
|
+ print("Warning: there are no {0} unused certain local IPs in the .pcap file.\n \
|
|
|
+ Returning {1} certain and {2} uncertain local IPs.".format(count, len(unused_local_ips), count-len(unused_local_ips)))
|
|
|
|
|
|
- count_certain = min(count, len(unused_priv_ips))
|
|
|
+ count_certain = min(count, len(unused_local_ips))
|
|
|
|
|
|
- retr_priv_ips = []
|
|
|
+ retr_local_ips = []
|
|
|
for _ in range(0, count_certain):
|
|
|
- random_priv_ip = choice(tuple(unused_priv_ips))
|
|
|
- retr_priv_ips.append(str(random_priv_ip))
|
|
|
- unused_priv_ips.remove(random_priv_ip)
|
|
|
+ random_local_ip = choice(sorted(unused_local_ips))
|
|
|
+ retr_local_ips.append(str(random_local_ip))
|
|
|
+ unused_local_ips.remove(random_local_ip)
|
|
|
|
|
|
- # retrieve uncertain priv ips
|
|
|
+ # retrieve uncertain local ips
|
|
|
if count_certain < count:
|
|
|
count_uncertain = count - count_certain
|
|
|
|
|
|
# check if new uncertain IPs have to be created
|
|
|
- if len(uncertain_priv_ips) < count_uncertain:
|
|
|
+ if len(uncertain_local_ips) < count_uncertain:
|
|
|
ipspace_multiplier = self.UNCERTAIN_IPSPACE_MULTIPLIER
|
|
|
|
|
|
- max_new_ip = self.max_uncertain_priv_ip.to_int() + ipspace_multiplier * count_uncertain
|
|
|
- # adjust IP space multiplier and prevent broadcast address of private segment from being chosen as new IP
|
|
|
- while max_new_ip >= self.priv_ip_segment.last_address().to_int():
|
|
|
- max_new_ip -= 1
|
|
|
-
|
|
|
- count_new_ips = max_new_ip - self.max_uncertain_priv_ip.to_int()
|
|
|
- if count_new_ips < count_uncertain:
|
|
|
- print("Error: Cannot generate enough new private IPs because they would exceed the maximum private segment IP. Returning {}.".format(count_new_ips))
|
|
|
+ max_new_ip = self.max_uncertain_local_ip.to_int() + ipspace_multiplier * count_uncertain
|
|
|
|
|
|
- # create ipspace_multiplier * count_uncertain new uncertain IP addresses
|
|
|
+ count_new_ips = max_new_ip - self.max_uncertain_local_ip.to_int()
|
|
|
+
|
|
|
+ # create ipspace_multiplier * count_uncertain new uncertain local IP addresses
|
|
|
last_gen_ip = None
|
|
|
for i in range(1, count_new_ips + 1):
|
|
|
- ip = IPAddress.from_int(self.max_uncertain_priv_ip.to_int() + i)
|
|
|
- # exclude the broadcast address
|
|
|
- if ip.to_int() >= self.priv_ip_segment.last_address().to_int():
|
|
|
- break
|
|
|
- uncertain_priv_ips.add(ip)
|
|
|
+ ip = IPAddress.from_int(self.max_uncertain_local_ip.to_int() + i)
|
|
|
+ # exclude the definite broadcast address
|
|
|
+ if self.priv_ip_segment:
|
|
|
+ if ip.to_int() >= self.priv_ip_segment.last_address().to_int():
|
|
|
+ break
|
|
|
+ uncertain_local_ips.add(ip)
|
|
|
last_gen_ip = ip
|
|
|
- self.max_uncertain_priv_ip = last_gen_ip
|
|
|
+ self.max_uncertain_local_ip = last_gen_ip
|
|
|
|
|
|
# choose the uncertain IPs to return
|
|
|
- total_uncertain = min(count_uncertain, len(uncertain_priv_ips))
|
|
|
+ total_uncertain = min(count_uncertain, len(uncertain_local_ips))
|
|
|
for _ in range(0, total_uncertain):
|
|
|
- random_priv_ip = choice(tuple(uncertain_priv_ips))
|
|
|
- retr_priv_ips.append(str(random_priv_ip))
|
|
|
- uncertain_priv_ips.remove(random_priv_ip)
|
|
|
+ random_local_ip = choice(sorted(uncertain_local_ips))
|
|
|
+ retr_local_ips.append(str(random_local_ip))
|
|
|
+ uncertain_local_ips.remove(random_local_ip)
|
|
|
|
|
|
# if count == 1:
|
|
|
- # return retr_priv_ips[0]
|
|
|
+ # return retr_local_ips[0]
|
|
|
|
|
|
- return retr_priv_ips
|
|
|
+ return retr_local_ips
|
|
|
|
|
|
def get_existing_external_ips(self, count: int=1):
|
|
|
"""
|
|
|
- Returns the given number of private IPs that are existent in the pcap file.
|
|
|
+ Returns the given number of external IPs that are existent in the pcap file.
|
|
|
|
|
|
- :param count: the number of IPs to return
|
|
|
- :return: the chosen private IPs
|
|
|
+ :param count: the number of external IPs to return
|
|
|
+ :return: the chosen external IPs
|
|
|
"""
|
|
|
|
|
|
# reasonable to include this?
|
|
|
- if not (len(self.public_ips) > 0):
|
|
|
- print("Warning: .pcap does not contain any public ips.")
|
|
|
+ if not (len(self.external_ips) > 0):
|
|
|
+ print("Warning: .pcap does not contain any external ips.")
|
|
|
return []
|
|
|
|
|
|
- if count > len(self.remaining_public_ips):
|
|
|
- print("Warning: There are no {} public IPs in the .pcap file. Returning all existing public IPs.".format(count))
|
|
|
+ if count > len(self.remaining_external_ips):
|
|
|
+ print("Warning: There are no more %d external IPs in the .pcap file.\n" % count +
|
|
|
+ "Returning all %d existing external IPs." % len(self.remaining_external_ips))
|
|
|
|
|
|
- total = min(len(self.remaining_public_ips), count)
|
|
|
+ total = min(len(self.remaining_external_ips), count)
|
|
|
|
|
|
- retr_public_ips = []
|
|
|
- public_ips = self.remaining_public_ips
|
|
|
+ retr_external_ips = []
|
|
|
+ external_ips = self.remaining_external_ips
|
|
|
|
|
|
for _ in range(0, total):
|
|
|
- random_public_ip = choice(tuple(public_ips))
|
|
|
- retr_public_ips.append(str(random_public_ip))
|
|
|
- public_ips.remove(random_public_ip)
|
|
|
+ random_external_ip = choice(sorted(external_ips))
|
|
|
+ retr_external_ips.append(str(random_external_ip))
|
|
|
+ external_ips.remove(random_external_ip)
|
|
|
|
|
|
# if count == 1:
|
|
|
- # return retr_public_ips[0]
|
|
|
+ # return retr_external_ips[0]
|
|
|
|
|
|
- return retr_public_ips
|
|
|
+ return retr_external_ips
|
|
|
|
|
|
def _init_ipaddress_ops(self):
|
|
|
"""
|
|
|
Load and process data needed to perform functions on the IP addresses contained in the statistics
|
|
|
"""
|
|
|
|
|
|
- all_ips = self.statistics.process_db_query("all(ipAddress)", print_results=False)
|
|
|
-
|
|
|
- # Prepare private address operations and on the side save all external IPs
|
|
|
- # find the private IP segment in use
|
|
|
- public_ips = set()
|
|
|
- priv_ip_segment = None
|
|
|
+ # retrieve local and external IPs
|
|
|
+ all_ips_str = set(self.statistics.process_db_query("all(ipAddress)", print_results=False))
|
|
|
+ external_ips_str = set(self.statistics.process_db_query("ipAddress(macAddress=%s)" % self.get_probable_router_mac(), print_results=False))
|
|
|
+ local_ips_str = all_ips_str - external_ips_str
|
|
|
+ external_ips = set()
|
|
|
+ local_ips = set()
|
|
|
self.contains_priv_ips = False
|
|
|
- first_priv_ip = None
|
|
|
- first_priv_ip_idx = -1
|
|
|
-
|
|
|
- # for that iterate over all IPs until the first private IP is found
|
|
|
- for i, ip in enumerate(all_ips):
|
|
|
- if not is_ipv4(ip):
|
|
|
- continue
|
|
|
- ip = IPAddress.parse(ip)
|
|
|
-
|
|
|
- if ip.is_private():
|
|
|
- priv_ip_segment = ip.get_private_segment()
|
|
|
- first_priv_ip_idx = i
|
|
|
- first_priv_ip = ip
|
|
|
- self.contains_priv_ips = True
|
|
|
- break
|
|
|
- # new function in IPv4 to shorten this?
|
|
|
- elif (not ip.is_localhost()) and (not ip.is_localhost()) and (not ip.is_multicast()) and (not ip.is_reserved()) and (not ip.is_zero_conf()):
|
|
|
- public_ips.add(ip)
|
|
|
-
|
|
|
- if not self.contains_priv_ips:
|
|
|
- #print("The Pcap File does not contain any private IPs")
|
|
|
- return
|
|
|
-
|
|
|
- # get minimum and maximum seen private IP. The addresses in-bewteen are considered
|
|
|
- # as certain to be part of the network the pcap traffic is from
|
|
|
- min_priv_ip, max_priv_ip = first_priv_ip, first_priv_ip
|
|
|
- priv_ips = {first_priv_ip}
|
|
|
- for ip in all_ips[first_priv_ip_idx+1:]:
|
|
|
- if not is_ipv4(ip):
|
|
|
- continue
|
|
|
- ip = IPAddress.parse(ip)
|
|
|
-
|
|
|
- if ip in priv_ip_segment:
|
|
|
- priv_ips.add(ip)
|
|
|
- if ip > max_priv_ip:
|
|
|
- max_priv_ip = ip
|
|
|
- elif ip < min_priv_ip:
|
|
|
- min_priv_ip = ip
|
|
|
- # new function in IPv4 to shorten this?
|
|
|
- elif (not ip.is_private()) and (not ip.is_localhost()) and (not ip.is_localhost()) and (not ip.is_multicast()) and (not ip.is_reserved()) and (not ip.is_zero_conf()):
|
|
|
- public_ips.add(ip)
|
|
|
-
|
|
|
- # save the certain unused priv IPs of the network
|
|
|
- unused_priv_ips = set()
|
|
|
- for i in range (min_priv_ip.to_int() + 1, max_priv_ip.to_int()):
|
|
|
+ self.priv_ip_segment = None
|
|
|
+
|
|
|
+ # convert local IP strings to IPv4.IPAddress representation
|
|
|
+ for ip in local_ips_str:
|
|
|
+ if is_ipv4(ip):
|
|
|
+ ip = IPAddress.parse(ip)
|
|
|
+ if ip.is_private() and not self.contains_priv_ips:
|
|
|
+ self.contains_priv_ips = True
|
|
|
+ self.priv_ip_segment = ip.get_private_segment()
|
|
|
+ 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()):
|
|
|
+ local_ips.add(ip)
|
|
|
+
|
|
|
+ # convert external IP strings to IPv4.IPAddress representation
|
|
|
+ for ip in external_ips_str:
|
|
|
+ if is_ipv4(ip):
|
|
|
+ ip = IPAddress.parse(ip)
|
|
|
+ # if router MAC can definitely be mapped to local/private IP, add it to local_ips
|
|
|
+ if ip.is_private():
|
|
|
+ local_ips.add(ip)
|
|
|
+ # new function in IPv4 to shorten this?
|
|
|
+ # exclude local broadcast address
|
|
|
+ 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()):
|
|
|
+ external_ips.add(ip)
|
|
|
+
|
|
|
+ min_local_ip, max_local_ip = min(local_ips), max(local_ips)
|
|
|
+
|
|
|
+ # save the certain unused local IPs of the network
|
|
|
+ unused_local_ips = set()
|
|
|
+ for i in range(min_local_ip.to_int() + 1, max_local_ip.to_int()):
|
|
|
ip = IPAddress.from_int(i)
|
|
|
- if not ip in priv_ips:
|
|
|
- unused_priv_ips.add(ip)
|
|
|
+ if not ip in local_ips:
|
|
|
+ unused_local_ips.add(ip)
|
|
|
|
|
|
# save the gathered information for efficient later use
|
|
|
- self.public_ips = frozenset(public_ips)
|
|
|
- self.remaining_public_ips = public_ips
|
|
|
- self.min_priv_ip, self.max_priv_ip = min_priv_ip, max_priv_ip
|
|
|
- self.max_uncertain_priv_ip = max_priv_ip
|
|
|
- self.priv_ips = frozenset(priv_ips)
|
|
|
- self.remaining_priv_ips = priv_ips
|
|
|
- self.unused_priv_ips = unused_priv_ips
|
|
|
- self.generated_uncertain_ips = set()
|
|
|
- self.uncertain_priv_ips = set()
|
|
|
- self.priv_ip_segment = priv_ip_segment
|
|
|
+ self.external_ips = frozenset(external_ips)
|
|
|
+ self.remaining_external_ips = external_ips
|
|
|
+ self.min_local_ip, self.max_local_ip = min_local_ip, max_local_ip
|
|
|
+ self.max_uncertain_local_ip = max_local_ip
|
|
|
+ self.local_ips = frozenset(local_ips)
|
|
|
+ self.remaining_local_ips = local_ips
|
|
|
+ self.unused_local_ips = unused_local_ips
|
|
|
+ self.uncertain_local_ips = set()
|