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.