Skip to content

Instantly share code, notes, and snippets.

@tnibert
Created February 25, 2021 08:33
Show Gist options
  • Save tnibert/f7e13547d4702d43065b2f99ed0d1626 to your computer and use it in GitHub Desktop.
Save tnibert/f7e13547d4702d43065b2f99ed0d1626 to your computer and use it in GitHub Desktop.
Check if an address is in a given subnet
#! /usr/bin/env python3
split_fields = lambda addr: [int(f) for f in addr.split(".")]
def check_subnet(prefix_addr: str, prefix_length: int, to_check: str):
"""
Determine if the IPv4 address to_check is within the given subnet
:param prefix_addr: address prefix as shown in CIDR notation
:param prefix_length: the number of bits in the network section
of the IP (subnet mask, as per CIDR notation)
:param to_check: the IP address to check if within the given subnet
:return: True if to_check is in the subnet specified by prefix_addr and prefix_length, else False
"""
# split apart the bytes making up the IPv4 address
pref_fields = split_fields(prefix_addr)
check_addr_fields = split_fields(to_check)
# assert valid IPs - each field limited to 8 bits
for field in pref_fields + check_addr_fields:
assert field < 256
# identify the first varying field and the number of bits that are the same
bits_to_check = prefix_length % 8
field_to_check = int(prefix_length / 8)
# confirm fully matching bytes do in fact match
if pref_fields[:field_to_check] != check_addr_fields[:field_to_check]:
return False
# check that the network bits in the first varying field match
shift = 8 - bits_to_check
return (pref_fields[field_to_check] >> shift) == (check_addr_fields[field_to_check] >> shift)
if __name__ == '__main__':
# is 10.0.65.13 in subnet 10.0.64.0/18?
assert check_subnet("10.0.64.0", 18, "10.0.65.13")
assert check_subnet("192.168.1.0", 24, "192.168.1.112")
assert not check_subnet("192.168.1.0", 24, "192.168.2.2")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment