def __calculate_mask(self) -> None: """ Calculates the mask from the instance var self.__mask If the mask is a literal mask (i.e. '255.255.255.0'), the try case is concerned. If instead, the user gave the mask length, we make sure to raise an AttributeError to switch to the except case to do proper testing. :raises: IncorrectMaskException: if the mask is wrongly formed (byte != 0 after byte < 255) or if the mask contains a byte that cannot be used in a mask. """ try: # The mask is given by its literal temp = self.__mask.split('.') if len(temp) == 1: # If the mask is given by its length # Use AttributeError raise to switch to the except case raise AttributeError() length = 0 for byte in range(4): concerned = int(temp[byte]) # We check that the byte is in the awaited bytes list if concerned in Utils.mask_allowed_bytes: # If mask contains a 0, we check that each next byte # contains only a 0, else we raise an IncorrectMaskException if concerned < 255: for i in range(1, 4 - byte): b = temp[byte + i] if b != '0': raise IncorrectMaskException( is_out_allowed=False, value=b, extra=byte + i) length += Utils.switch_length(concerned, index=True) else: raise IncorrectMaskException(is_out_allowed=True, value=concerned) # Stock the length self.__mask_length = length self.__mask = FourBytesLiteral().set_from_string_literal( ".".join(temp)) except AttributeError: # The mask is given by its length self.__mask_length = int(self.__mask) self.__mask = FourBytesLiteral().set_from_string_literal( Utils.mask_length_to_literal(self.__mask_length)) finally: self.__addresses = 2**(32 - self.__mask_length) - 2
def __build_subnets(self) -> None: start_ip = self.network_range['start'] for i in range(len(self.__subnets_sizes)): machines_bits = self.__submasks_machine_bits[i] mask_literal = FourBytesLiteral().set_eval(Utils.mask_length_to_literal(32 - machines_bits)) result = IPv4Network().init_from_fbl(start_ip, mask_literal) self.__subnets.append(result) start_ip = Utils.ip_after(result.network_range['end'])
def check_ip_availability(subnet_inst_, ip_): """ Checks if an IP is available This function is a suicider: it will die if any of the tests fail. It will either raise nettools.core.errors.IPOffNetworkRangeException or rth.core.errors.IPAlreadyAttributed Args: subnet_inst_: The subnetwork instance ip_: The IP that has to be checked """ # Checking that ip is effectively in range of the subnet if isinstance(ip_, str): ip_ = FourBytesLiteral().set_from_string_literal(ip_) mask = FourBytesLiteral().set_from_string_literal( Utils.mask_length_to_literal(subnet_inst_.mask_length)) inst = IPv4Network().init_from_fbl(ip_, mask) if inst.address_type != 1: # means the address is either a network or a broadcast address raise IPOffNetworkRangeException(str(ip)) # then we check that ip is not used by any of the current routers routers = subnet_inst_.routers for r in routers: if str(routers[r]) == str(ip_): raise IPAlreadyAttributed(name, ip_, self.uid_to_name('router', r), str(router_name))
def __display_subnets(self, advanced=False) -> None: if not self.__activated: return occupied, graph, t = self.__build_graph() literal_ip = Utils.to_literal(self.ip) literal_netr = Utils.netr_to_literal(self.__total_network_range) print(self.lang_dict['network']) if advanced is True: print(self.lang_dict['cidr_adv'].format(literal_ip, self.mask_length)) else: print(self.lang_dict['cidr'].format(literal_ip, self.mask_length)) print("{} - {}".format(literal_netr['start'], literal_netr['end'])) if advanced is True: print(self.lang_dict['addr_avail_advanced'].format(occupied, self.addresses)) else: print(self.lang_dict['addr_avail'].format(self.addresses)) print('') print(self.lang_dict['utils'].format(len(self.__subnets), t)) for i in range(len(self.__subnets)): literal_sub_netr = self.__subnets[i].displayable_network_range if advanced: print(self.lang_dict['sub_addr_advanced'].format(literal_sub_netr['start'], literal_sub_netr['end'], 2 ** self.__submasks_machine_bits[i] - 2, self.__subnets_sizes[i])) else: print(self.lang_dict['sub_addr'].format(literal_sub_netr['start'], literal_sub_netr['end'], 2 ** self.__submasks_machine_bits[i] - 2)) if advanced: print('') print(self.lang_dict['net_usage']) print(graph)
def display_type(self, display=False) -> None: if display is True: self._display() elif display is False: if self.address_type == 0: machine_type = self.lang_dict['addr_types']['net'] elif self.address_type == 1: machine_type = self.lang_dict['addr_types']['mac'] elif self.address_type == 2: machine_type = self.lang_dict['addr_types']['bct'] else: machine_type = None temp = Utils.netr_to_literal(self.network_range) temp['address_type'] = machine_type print(temp)
def network_raw_output(self): """ Returns a raw output of the local network """ final = {'subnets': {}, 'routers': {}} for sid in self.subnetworks: subnet = self.subnetworks[sid]['instance'] displayable_connected_routers = subnet.routers.copy() for i in displayable_connected_routers: displayable_connected_routers[i] = str( displayable_connected_routers[i]) final['subnets'][sid] = { 'id': subnet.uid, 'name': subnet.name, 'connected_routers': displayable_connected_routers, 'range': Utils.netr_to_literal(subnet.network_range), 'mask': subnet.mask_length } for rid in self.routers: router = self.routers[rid] displayable_connected_subnets = router.connected_networks.copy() for i in displayable_connected_subnets: displayable_connected_subnets[i] = str( displayable_connected_subnets[i]) final['routers'][rid] = { 'id': router.uid, 'name': router.name, 'connected_subnets': displayable_connected_subnets, 'internet': router.internet } return final
def displayable_network_range(self): return Utils.netr_to_literal(self.__network_range)
def display_range(self, display=False) -> None: if display is True: self._display() else: print(Utils.netr_to_literal(self.network_range))
def connect_router_to_networks(self, router_name, subnets_ips): """ Connects a router to a set of subnetworks Args: router_name: The name of the router subnets_ips: The list of subnetworks with the corresponding IP to assign the router to. Format is {SUBNET_NAME: IP, ...} """ def check_ip_availability(subnet_inst_, ip_): """ Checks if an IP is available This function is a suicider: it will die if any of the tests fail. It will either raise nettools.core.errors.IPOffNetworkRangeException or rth.core.errors.IPAlreadyAttributed Args: subnet_inst_: The subnetwork instance ip_: The IP that has to be checked """ # Checking that ip is effectively in range of the subnet if isinstance(ip_, str): ip_ = FourBytesLiteral().set_from_string_literal(ip_) mask = FourBytesLiteral().set_from_string_literal( Utils.mask_length_to_literal(subnet_inst_.mask_length)) inst = IPv4Network().init_from_fbl(ip_, mask) if inst.address_type != 1: # means the address is either a network or a broadcast address raise IPOffNetworkRangeException(str(ip)) # then we check that ip is not used by any of the current routers routers = subnet_inst_.routers for r in routers: if str(routers[r]) == str(ip_): raise IPAlreadyAttributed(name, ip_, self.uid_to_name('router', r), str(router_name)) router_uid = self.name_to_uid('router', router_name) for name in subnets_ips: subnet_uid = self.name_to_uid('subnet', name) subnet_inst = self.subnetworks[subnet_uid]['instance'] router_inst = self.routers[router_uid] subnet_ip = subnets_ips[name] # we want to attribute a "personalised" IP if subnet_ip: check_ip_availability(subnet_inst, subnet_ip) ip = subnet_ip # we will let the program set it for us else: ip = subnet_inst.network_range['end'] while True: ip = Utils.ip_before(ip) try: check_ip_availability(subnet_inst, ip) break except IPAlreadyAttributed: continue subnet_inst.connect(router_uid, ip) router_inst.connect(subnet_uid, ip) self.subnetworks[subnet_uid]['instance'] = subnet_inst self.routers[router_uid] = router_inst
def create_network(self, ip, mask_length, name=None): """ Creates a virtual subnetwork Args: ip: The given IP mask_length: The network mask length of the subnetwork name: The eventual name of the subnetwork """ uid = len(self.subnetworks) # Name correspondency if name: result = self.is_name_existing('subnet', name) if result: raise NameAlreadyExists(name) else: name = f"<Untitled Network#ID:{uid}>" current = self.Network(ip, mask_length, uid, name) current_netr = Utils.netr_to_literal(current.network_range) if self.ranges: for sid in self.subnetworks: subnet = self.subnetworks[sid]['instance'] subnetr = Utils.netr_to_literal(subnet.network_range) overlap = False if current.mask_length == subnet.mask_length: # Masks are equal if current_netr['start'] == subnetr['start']: overlap = True else: if current.mask_length < subnet.mask_length: # New network mask is bigger, check if the existing subnetwork is inside big = current_netr['start'].split('.') small = subnetr['start'] else: # New network is smaller that existing subnetwork, check if it is inside small = current_netr['start'] big = subnetr['start'].split('.') if current.mask_length <= 8: if int(big[0]) <= int(small.split('.')[0]): overlap = True elif 8 < current.mask_length <= 16: if small.startswith(f"{big[0]}") and int( big[1]) <= int(small.split('.')[1]): overlap = True elif 16 < current.mask_length <= 24: if small.startswith(f"{big[0]}.{big[1]}") and int( big[2]) <= int(small.split('.')[2]): overlap = True elif 24 < current.mask_length <= 32: if int(big[3]) <= int(small.split('.')[3]): overlap = True if overlap: raise OverlappingError(current_netr, subnetr) self.subnetworks[uid] = { 'instance': current, 'range': current.network_range } # adding to network ranges self.ranges.append(current.network_range) # also adding name if defined if name: self.subnets_names.append(name) return uid