Skip to content

Instantly share code, notes, and snippets.

@magnetikonline magnetikonline/README.md
Last active Oct 12, 2019

Embed
What would you like to do?
Python function to determine if a given IPv4 CIDR "fits" into another.

CIDR fit

Python function to determine if a given IPv4 CIDR fits into another.

How cidr_fit(cidr_a,cidr_b) works:

  • For both CIDR's given:
    • Splits each CIDR in address and prefix size parts.
    • Converts the address part to a 32 bit binary string.
      • E.g. 192.168.0.1 becomes 11000000101010000000000000000001.
    • Cuts out everything after the prefix size.
      • E.g. 192.168.0.1/12 becomes 110000001010.
  • Now check if either:
    • Remaining binary string A starts with B
    • Remaining binary string B starts with A
  • Done.

Example

Using an example CIDR list of Google API ranges from _spf.google.com against a Google IP of 216.58.196.138:

$ ./cidrfit.py
('108.177.8.0/21    ', False)
('108.177.96.0/19   ', False)
('130.211.0.0/22    ', False)
('172.217.0.0/19    ', False)
('172.217.128.0/19  ', False)
('172.217.160.0/20  ', False)
('172.217.192.0/19  ', False)
('172.217.32.0/20   ', False)
('173.194.0.0/16    ', False)
('209.85.128.0/17   ', False)
('216.239.32.0/19   ', False)
('216.58.192.0/19   ', True)
('35.190.247.0/24   ', False)
('35.191.0.0/16     ', False)
('64.233.160.0/19   ', False)
('66.102.0.0/20     ', False)
('66.249.80.0/20    ', False)
('72.14.192.0/18    ', False)
('74.125.0.0/16     ', False)
#!/usr/bin/env python
def cidr_fit(cidr_a,cidr_b):
def split_cidr(cidr):
part_list = cidr.split('/')
if (len(part_list) == 1):
# if just an IP address, assume /32
part_list.append('32')
# return address and prefix size
return part_list[0].strip(),int(part_list[1])
def address_to_bits(address):
# convert each octet of IP address to binary
bit_list = [bin(int(part)) for part in address.split('.')]
# join binary parts together
return ''.join([part[2:].zfill(8) for part in bit_list])
def binary_network_prefix(cidr):
# return CIDR as bits, to the length of the prefix size only (drop the rest)
address,prefix_size = split_cidr(cidr)
return address_to_bits(address)[:prefix_size]
prefix_a = binary_network_prefix(cidr_a)
prefix_b = binary_network_prefix(cidr_b)
return (
prefix_a.startswith(prefix_b) or
prefix_b.startswith(prefix_a)
)
def main():
CIDR_TEST_LIST = [
'108.177.8.0/21',
'108.177.96.0/19',
'130.211.0.0/22',
'172.217.0.0/19',
'172.217.128.0/19',
'172.217.160.0/20',
'172.217.192.0/19',
'172.217.32.0/20',
'173.194.0.0/16',
'209.85.128.0/17',
'216.239.32.0/19',
'216.58.192.0/19',
'35.190.247.0/24',
'35.191.0.0/16',
'64.233.160.0/19',
'66.102.0.0/20',
'66.249.80.0/20',
'72.14.192.0/18',
'74.125.0.0/16'
]
for cidr_test in CIDR_TEST_LIST:
print((cidr_test.ljust(18,' '),cidr_fit(cidr_test,'216.58.196.138')))
if (__name__ == '__main__'):
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.