CIDR-Man is a high-performance ipaddress subnetting library designed to replace the built-in ipaddress library.
Project description
CIDR-Man
Built due to frustrations with python's built-in ipaddress
library's performance, code complexity, and accuracy.
CIDR-Man is an accurate high-performance IP address subnetting library.
While the interface of this new library is a little different from that of the built-in library, we think you'll find it to be more "pythonic", and quite intuitive.
NOTE: While writing tests for this library we discovered that a number of the is_<address type>
flags from the python built-in library were returning incorrect results. CIDR-Man is accurate as per the RFCs at the time of writing, thus our responses may differ.
Key performance metrics (vs Built-in ipaddress
)
__init__
: 7.822xsupernet
: 2.186xsubnet_of
: 8.516xsubnets
: 3.966xcompressed
: 1.303x
CIDRs explained
CIDR (or Classless Inter-Domain Routing) is a way of representing and handling IP addresses and networks. Introduced in 1993 to replace the previous IP address class architecture, CIDRs offer more flexibility in addressing hierarchy in network designs. A block of IP addresses in CIDR notation would be represented as the first IP in the block followed by the number of bits in the bitmask separated by a forward slash.
For example, the CIDR 192.0.2.0/24 represents an IP address block spanning 192.0.2.0 to 192.0.2.255. Expanding this out we get the following:
Network: 192.0.2.0
Network (as binary): 11000000000000000000001000000000
Netmask: 255.255.255.0
Netmask (as binary): 11111111111111111111111100000000
Broadcast IP: 192.0.2.255
Broadcast IP (as binary): 11000000000000000000001011111111
First usable IP (normally the Gateway): 192.0.2.1
First usable IP (as binary): 11000000000000000000001000000001
Last usable IP: 192.0.2.255
Last usable IP (as binary): 11000000000000000000001011111110
Using this representation a single IP address is simply one with a full bitmask, thus 192.0.2.1/32 is the same as 192.0.2.1.
This means that our network subnetting library only needs a single class CIDR
.
Utilising a single type CIDR
to represent both network objects and individual addresses results in considerably more concise code.
Usage
Initialisation
Initialising a new CIDR object is easy and supports all common input types (presentation format, integer format, network/big-endian byte format, and built-in IP & Network types).
from cidr_man import CIDR, Version
## Create from string (presentation format)
network = CIDR("192.0.2.0/24")
ip = CIDR("192.0.2.1")
network_v6 = CIDR("2001:db8::/56")
machine_alloc_v6 = CIDR("2001:db8::/64")
ip_v6 = CIDR("2001:db8::1")
## Create from built-in
network = CIDR(IPv4Network("192.0.2.0/24"))
ip = CIDR(IPv4Address("192.0.2.1"))
network_v6 = CIDR(IPv6Network("2001:db8::/56"))
machine_alloc_v6 = CIDR(IPv6Network("2001:db8::/64"))
ip_v6 = CIDR(IPv6Address("2001:db8::1"))
## Create from integer
network = CIDR(3221225984, version=Version.v4, prefix_len=24)
ip = CIDR(3221225985, version=Version.v4)
network_v6 = CIDR(42540766411282592856903984951653826560, version=Version.v6, prefix_len=56)
ip_v6 = CIDR(42540766411282592856903984951653826561, version=Version.v6)
## Create from byte
network = CIDR(b'\xc0\x00\x02\x01', prefix_len=24)
ip = CIDR(b'\xc0\x00\x02\x01')
network_v6 = CIDR(b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', prefix_len=56)
ip_v6 = CIDR(b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01')
Get subnets
Retrieving the direct subnets of a network is easy.
To get the pair
network = CIDR("192.0.2.0/24")
subnets = network.subnets # (CIDR("192.0.2.0/25"), CIDR("192.0.2.128/25"))
To get only the "left" (low-bit subnet)
left = network.left # CIDR("192.0.2.0/25")
To get only the "right" (high-bit subnet)
right = network.right # CIDR("192.0.2.128/25")
These can be chained for quick traversal
left_of_left = network.left.left # CIDR("192.0.2.0/26")
right_of_left = network.left.right # CIDR(192.0.2.64/26")
Get supernets
Retrieving the direct supernet of a network is easy.
network = CIDR("192.0.2.0/25")
supernet = network.supernet() # CIDR("192.0.2.0/24")
Contains
Checking if an address or network is the subnet of another is made simpler, with subnet in supernet
syntax fully supported.
network_1 = CIDR("192.0.2.0/24")
network_2 = CIDR("192.0.2.0/26")
result = network_2 in network_1
# or
result = network_1.contains(network_2)
Alternatively if you prefer the built-in library's style we've included subnet_of
for compatibility.
network_2.subnet_of(network_1)
As well as additional support for subnet < supernet
,subnet <= supernet
,subnet > supernet
, subnet >= supernet
, and subnet == supernet
*NOTE: These are perhaps counter-intuitive as this in the inverse of the size of the address space, but as this is how python's library defines the operations we're maintaining compatibility
subnet < supernet # Returns True if subnet has less specific prefix than supernet
subnet <= supernet # Returns True if subnet has a less than or equal prefix than supernet
subnet > supernet # Returns True if subnet has a less specific prefix than supernet
subnet >= supernet # Returns True if subnet has a greater than or equal prefix supernet
subnet == supernet # Returns True if subnet is exactly equal to supernet
Packed (Byte format)
ip_b = ip.packed # b'\xc0\x00\x02\x01'
ipv6_b = ip.packed # b' \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
Compressed (String / Presentation format)
CIDRs that have a prefix_len
equal to the maximum for their IP version (that is 32 for IPv4, and 128 for IPv6) will be presented in IP presentation format.
Therefore, both CIDR("192.0.2.1")
and CIDR("192.0.2.1/32")
produce the presentation format "192.0.2.1"
.
# IPv4
ip_s = ip.compressed # "192.0.2.1"
### or
ip_s = str(ip) # "192.0.2.1"
## CIDRs who's prefix is not the max_prefix are presented in CIDR presentation format
network_s = network.compressed # "192.0.2.0/24"
### or
network_s = str(ip) # "192.0.2.0/24"
# IPv6
ipv6_s = ip.compressed # "2001:db8::1"
### or
ipv6_s = str(ip) # "2001:db8::1"
network_v6_s = network.compressed # "2001:db8::/56"
## or
network_v6_s = str(ip) # "2001:db8::/56"
Important addresses
network_address
, broadcast_address
, netmask
, inverse_netmask
, first_address
, and last_address
each provide the relevant addresses as new CIDR objects.
# IPv4
net_address = network.network_address # 192.0.2.0
first_address = network.first_address # 192.0.2.1
last_address = network.last_address # 192.0.2.254
broadcast_address = network.network_address # 192.0.2.255
netmask = network.netmask # 255.255.255.0
inverse_netmask = network.inverse_netmask # 0.0.0.255
# IPv6
net_address_v6 = network_v6.network_address # 2001:db8::
first_address_v6 = network_v6.first_address # 2001:db8::1
last_address_v6 = network_v6.last_address # 2001:db8:0:ff:ffff:ffff:ffff:fffe
broadcast_address_v6 = network_v6.network_address # 2001:db8:0:ff:ffff:ffff:ffff:ffff
netmask_v6 = network_v6.netmask # ffff:ffff:ffff:ff00::
inverse_netmask_v6 = network_v6.inverse_netmask # ::ff:ffff:ffff:ffff:ffff
is_ flags
NOTE: While writing tests for this library we discovered that a number of the is_<address type>
flags from the python built-in library were returning incorrect results. CIDR-Man is accurate as per the RFCs at the time of writing, thus our responses may differ.
is_multicast = network.is_multicast # True if the address is reserved for multicast use by RFCs.
is_global = network.is_global # True if the address is allocated for public networks.
is_private = network.is_private # True if the address is allocated for private networks.
is_reserved = network.is_reserved # True if the address is otherwise IETF reserved.
is_loopback = network.is_loopback # True if this is a loopback address.
is_link_local = network.is_link_local # True if the address is reserved for link-local usage.
Installation (from pip):
pip install cidr_man
Installation (from source):
git clone https://gitlab.com/geoip.network/cidr_man
poetry install
Theme song
CIDR-Man, CIDR-Man, Does what ever a CIDR can...
Thwip! Thwip! """""""""""""""""""""""""""""""""""""""""""""""""
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file CIDR-Man-1.5.3.tar.gz
.
File metadata
- Download URL: CIDR-Man-1.5.3.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.15 CPython/3.9.12 Linux/5.4.109+
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 07a0f10415366014c092dc0f2b44fc5e9424798155b403da36078ba2c1d3acc6 |
|
MD5 | 769615c848bf535e65942a6ff777d06b |
|
BLAKE2b-256 | 0f433ec29b242ac6d522ddb334169c4cb4cc897e56af8d5c850ed12a482d27bb |
File details
Details for the file CIDR_Man-1.5.3-py3-none-any.whl
.
File metadata
- Download URL: CIDR_Man-1.5.3-py3-none-any.whl
- Upload date:
- Size: 7.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.15 CPython/3.9.12 Linux/5.4.109+
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3e790cbe58c0be8fbebc073039a8bb99721c9c5df2389c5217e860346cc5cdae |
|
MD5 | 9c6587d0dbfdd280493e829d3e3250f3 |
|
BLAKE2b-256 | 25368d8834d2134cc195a827fd8822d9a712b5942bb7bb0a701210606e6aae88 |