Source code for encommon.parse.network
"""
Functions and routines associated with Enasis Network Common Library.
This file is part of Enasis Network software eco-system. Distribution
is permitted, for more information consult the project license file.
"""
from contextlib import suppress
from typing import Any
from typing import Optional
from netaddr import IPAddress
from netaddr import IPNetwork
[docs]
class Network:
"""
Convert the network into the various supported formats.
:param source: Network IPv4 or IPv6 network or address.
"""
__source: IPNetwork
def __init__(
self,
source: str,
) -> None:
"""
Initialize instance for class using provided parameters.
"""
network = IPNetwork(source)
self.__source = network
def __repr__(
self,
) -> str:
"""
Built-in method for representing the values for instance.
:returns: String representation for values from instance.
"""
return f"Network('{self.address_cidr}')"
def __hash__(
self,
) -> int:
"""
Built-in method used when performing hashing operations.
:returns: Integer hash value for the internal reference.
"""
return hash(self.__source)
def __str__(
self,
) -> str:
"""
Built-in method for representing the values for instance.
:returns: String representation for values from instance.
"""
return self.address_cidr
def __eq__(
self,
other: object,
) -> bool:
"""
Built-in method for comparing this instance with another.
:param other: Other value being compared with instance.
:returns: Boolean indicating outcome from the operation.
"""
source = self.__source
with suppress(Exception):
other = IPNetwork(str(other))
return source == other
return False
def __ne__(
self,
other: object,
) -> bool:
"""
Built-in method for comparing this instance with another.
:param other: Other value being compared with instance.
:returns: Boolean indicating outcome from the operation.
"""
return not self.__eq__(other)
@property
def source(
self,
) -> IPNetwork:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
return self.__source
@property
def version(
self,
) -> int:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
return self.__source.version
@property
def cidr(
self,
) -> int:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
source = self.__source
return source.prefixlen
@property
def address(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
source = self.__source
return str(source.ip)
@property
def address_cidr(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
address = self.address
return f'{address}/{self.cidr}'
@property
def address_host(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
address = self.address
prefix = (
128
if self.version == 6
else 32)
return f'{address}/{prefix}'
@property
def network(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
source = self.__source
return str(source.network)
@property
def network_cidr(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
network = self.network
return f'{network}/{self.cidr}'
@property
def broadcast(
self,
) -> Optional[str]:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
source = self.__source
address = source.broadcast
if address is None:
return None
return str(address)
@property
def padded(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
if self.version != 4:
raise ValueError('version')
address = self.address
octets = address.split('.')
pads = [
x.zfill(3)
for x in octets]
return '.'.join(pads)
@property
def reverse(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
if self.version != 4:
raise ValueError('version')
address = self.address
octets = address.split('.')
reverse = list(reversed(octets))
return '.'.join(reverse)
@property
def hwaddr(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
if self.version != 4:
raise ValueError('version')
padded = self.padded
nodots = (
padded
.replace('.', ''))
ranged = range(
0, len(nodots), 2)
pairs = [
nodots[x:x + 2]
for x in ranged]
return '-'.join(pairs)
@property
def netmask(
self,
) -> str:
"""
Return the value for the attribute from class instance.
:returns: Value for the attribute from class instance.
"""
source = self.__source
return str(source.netmask)
@property
def ispublic(
self,
) -> bool:
"""
Return the boolean indicating whether instance is state.
"""
return (
self.source.ip
.is_global())
@property
def isprivate(
self,
) -> bool:
"""
Return the boolean indicating whether instance is state.
"""
return not self.ispublic
@property
def islinklocal(
self,
) -> bool:
"""
Return the boolean indicating whether instance is state.
"""
return (
self.source
.is_link_local())
@property
def islocalhost(
self,
) -> bool:
"""
Return the boolean indicating whether instance is state.
"""
return (
self.source
.is_loopback())
[docs]
def insubnet_ip(
address: str,
networks: str | list[str] | tuple[str, ...],
) -> bool:
"""
Return the boolean indicating address is in the network.
:param address: Provided address to find in the network.
:param network: Networks which values can be within any.
:returns: Boolean indicating address is in the network.
"""
if isinstance(networks, str):
networks = [networks]
networks = list(networks)
if not isvalid_ip(address):
raise ValueError('address')
naddr = Network(address)
if (naddr.version == 4
and naddr.cidr == 32):
address = naddr.address
if (naddr.version == 6
and naddr.cidr == 128):
address = naddr.address
parsed = IPAddress(address)
return any(
parsed in IPNetwork(x)
for x in networks)
[docs]
def isvalid_ip(
value: Any, # noqa: ANN401
) -> bool:
"""
Return the boolean indicating whether the value is valid.
:param value: Value that will be validated as an address.
:returns: Boolean indicating whether the value is valid.
"""
value = str(value)
try:
Network(value)
return True
except Exception:
return False