dotted_decimal_quad_to_binary in module belowis_dotted_quad_multicast in module belowcidr_to_dotted_quad and dotted_quad_to_cidr in module below| # Hosts requested | Block Need | Range |
|---|---|---|
| 260 | /23 | 1.0.0.0 ... 1.0.1.255 |
| 128 | /24 | 1.0.2.0 ... 1.0.2.255 |
| 41 | /26 | 1.0.3.0 ... 1.0.3.63 |
| 20 | /27 | 1.0.3.64 ... 1.0.3.95 |
| 15 | /27 | 1.0.3.96 ... 1.0.3.127 |
| 9 | /28 | 1.0.3.128 ... 1.0.3.143 |
We did it! And we have 112 addresses left to give out.
Here is another way to see how the networks are handed out from a /22:
x x.x x x x x x x x ← Our /22 0 x.x x x x x x x x ← Allocate the /23 1 0.x x x x x x x x ← Allocate a /24 1 1.0 0 x x x x x x ← Allocate a /26 1 1.0 1 0 x x x x x ← Allocate a /27 1 1.0 1 1 x x x x x ← and another /27 1 1.1 0 0 0 x x x x ← Allocate the /28
cidr_to_address_and_mask_in_binary in module belowbinary_to_colon_hex in module belowIt’s easiest to combine all the functions in a single module since they share some code:
import sys
import re
# Yes, these are global, but it’s a nice way to ensure they are only computed once
OCTET = r'(?:\d|[1-9]\d|1\d\d|2(?:[0-4]\d|5[0-5]))'
DOTTED_QUAD = f'{OCTET}\\.{OCTET}\\.{OCTET}\\.{OCTET}'
IPv4_PATTERN = re.compile(DOTTED_QUAD)
IPv4_CIDR_PATTERN = re.compile(f'{DOTTED_QUAD}/(?:\\d|[1-2]\\d|3[0-2])')
IPv6_BINARY_PATTERN = re.compile(r'[01]{128}')
def validate_ipv4(address):
if re.fullmatch(IPv4_PATTERN, address) is None:
raise ValueError('Illegal IPv4 Address')
def validate_ipv4_cidr(address):
if re.fullmatch(IPv4_CIDR_PATTERN, address) is None:
raise ValueError('Illegal IPv4 CIDR')
def validate_ipv6_binary(bit_string):
if re.fullmatch(IPv6_BINARY_PATTERN, bit_string) is None:
raise ValueError('Illegal IPv6 Binary')
def dotted_decimal_quad_to_binary(quad):
validate_ipv4(quad)
return ''.join(f'{int(octet):08b}' for octet in quad.split('.'))
def is_dotted_quad_multicast(quad):
validate_ipv4(quad)
return dotted_decimal_quad_to_binary(quad).startswith('1110')
def cidr_to_dotted_quad(cidr):
'''I guess just drop the slash part after validation'''
validate_ipv4_cidr(cidr)
return cidr[0:cidr.index('/')]
def dotted_quad_to_cidr(quad, length):
'''I guess just add the slash after validation'''
validate_ipv4(quad)
if not isinstance(length, int) or length < 0 or length > 32:
raise ValueError('Invalid CIDR length')
return f'{quad}/{length}'
def cidr_to_address_and_mask_in_binary(cidr):
validate_ipv4_cidr(cidr)
address, length = cidr.split('/')
mask = '1' * int(length) + '0' * (32 - int(length))
return address, mask
def binary_to_colon_hex(b):
validate_ipv6_binary(b)
return ':'.join(f'{int(b[i:i+16], 2):x}' for i in range(0, 128, 16))
While you were not required to turn in unit tests, the little functions that were required in this assigment were tricky that you would be insane not to have provided unit tests. Here are the tests I used, just for fun:
import pytest
import iputils
def test_dotted_decimal_quad_to_binary():
good = [
('12.3.8.9', '00001100000000110000100000001001'),
('255.255.255.255', '11111111111111111111111111111111'),
('100.32.240.96', '01100100001000001111000001100000')]
bad = ['', 'dog', '100.256.0.0', '10.0', '1..100', '3.-5.2.2']
for ip, binary in good:
assert iputils.dotted_decimal_quad_to_binary(ip) == binary
for ip in bad:
with pytest.raises(ValueError):
iputils.dotted_decimal_quad_to_binary(ip)
def test_is_dotted_quad_multicast():
multicast = ['224.0.0.0', '239.255.255.255', '230.1.8.129']
not_multicast = ['223.0.0.0', '240.0.1.2', '255.255.255.255']
bad = ['', 'dog', '100.256.0.0', '10.0', '1..100', '3.-5.2.2']
for ip in multicast:
assert iputils.is_dotted_quad_multicast(ip)
for ip in not_multicast:
assert not iputils.is_dotted_quad_multicast(ip)
for ip in bad:
with pytest.raises(ValueError):
iputils.is_dotted_quad_multicast(ip)
def test_cidr_to_dotted_quad():
good = [
('12.3.8.9/20', '12.3.8.9'),
('5.222.11.3/25', '5.222.11.3'),
('100.32.240.96/8', '100.32.240.96')]
bad = [
'', 'dog', '100.256.0.0', '10.0', '1..100', '3.-5.2.2',
'1.1.1.1/dog', '1.1.1.1/33']
for cidr, ip in good:
assert iputils.cidr_to_dotted_quad(cidr) == ip
for cidr in bad:
with pytest.raises(ValueError):
iputils.dotted_decimal_quad_to_binary(cidr)
def test_dotted_quad_to_cidr():
good = [
('12.3.8.9/20', 20, '12.3.8.9'),
('5.222.11.3/25', 25, '5.222.11.3'),
('100.32.240.96/32', 32, '100.32.240.96')]
bad = [
('100.256.0.0', 8),
('1.1.1.1', 33),
('2.3.4.5', 'dog')]
for cidr, length, quad in good:
assert iputils.dotted_quad_to_cidr(quad, length) == cidr
for quad, length in bad:
with pytest.raises(ValueError):
iputils.dotted_quad_to_cidr(quad, length)
def test_cidr_to_address_and_mask_in_binary():
good = [
('12.3.8.9/20', '12.3.8.9', '11111111111111111111000000000000'),
('5.222.11.3/25', '5.222.11.3', '11111111111111111111111110000000'),
('5.222.11.3/1', '5.222.11.3', '10000000000000000000000000000000'),
('5.222.11.3/32', '5.222.11.3', '11111111111111111111111111111111'),
('100.32.240.96/0', '100.32.240.96', '00000000000000000000000000000000')]
bad = [
'', 'dog', '100.256.0.0', '10.0', '1..100', '3.-5.2.2',
'1.1.1.1/dog', '1.1.1.1/33']
for cidr, ip, mask in good:
assert iputils.cidr_to_address_and_mask_in_binary(cidr) == (ip, mask)
for cidr in bad:
with pytest.raises(ValueError):
iputils.cidr_to_address_and_mask_in_binary(cidr)
def test_binary_to_colon_hex():
good = [
('0000000000000011' * 8, '3:3:3:3:3:3:3:3'),
('1010' * 32, 'aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa'),
('11010010' * 15 + '11000011', 'd2d2:d2d2:d2d2:d2d2:d2d2:d2d2:d2d2:d2c3'),
('0' * 128, '0:0:0:0:0:0:0:0')]
bad = ['', '10101', '1'*127+'2']
for binary, address in good:
assert iputils.binary_to_colon_hex(binary) == address
for binary in bad:
with pytest.raises(ValueError):
iputils.binary_to_colon_hex(binary)
Will be on GitHub.