USD ($)
$
United States Dollar
India Rupee

Use Python's ipaddress module for subnetting

Lesson 23/27 | Study Time: 120 Min
Use Python's ipaddress module for subnetting

Task 1: Creating IP Address Objects

Task 2: Subnet Calculations and Validations

Task 3: Checking if IP is in a Specific Subnet

Task 4: Network Summarization

Task 5: Creating an IP Address Management Tool

Task 1: Creating IP Address Objects

Let's work with the ipaddress module. This module helps with IP address calculations. First, import it. Create a file ip_objects.py.

# Creating IP address objects
print("WORKING WITH IP ADDRESS OBJECTS")
print("=" * 70)
import ipaddress

Now let's create an IP address object for Router1's IP:

# Create an IPv4 address object
router1_ip = ipaddress.IPv4Address("192.168.1.1")
print(f"Router1 IP: {router1_ip}")
print(f"Type: {type(router1_ip)}")

ipaddress.IPv4Address("192.168.1.1") creates an IP address object. This is not just a string - it's a special object that understands IP addresses.

Now let's create IP objects for all our lab devices:

# Create IP objects for all lab devices
lab_ips = [
ipaddress.IPv4Address("192.168.1.1"), # Router1
ipaddress.IPv4Address("192.168.1.2"), # Router2
ipaddress.IPv4Address("192.168.1.3"), # Switch1
ipaddress.IPv4Address("192.168.1.4"), # Switch2
ipaddress.IPv4Address("192.168.1.5") # Ubuntu Server
]
print("\nLab IP Address Objects:")
for ip in lab_ips:
print(f" {ip}")

Now let's do some operations with IP objects:

print("\n" + "=" * 70)
print("IP ADDRESS OPERATIONS")
print("=" * 70)
# Get the next IP address
print("Getting next IP address:")
router1_ip = ipaddress.IPv4Address("192.168.1.1")
next_ip = router1_ip + 1
print(f"Router1 IP: {router1_ip}")
print(f"Next IP: {next_ip}")
print()
# Compare IP addresses
print("Comparing IP addresses:")
ip1 = ipaddress.IPv4Address("192.168.1.1")
ip2 = ipaddress.IPv4Address("192.168.1.2")
print(f"IP1: {ip1}")
print(f"IP2: {ip2}")
print(f"IP1 < IP2: {ip1 < ip2}")
print(f"IP1 == IP2: {ip1 == ip2}")
IP objects can do math. router1_ip + 1 gives 192.168.1.2.

Now let's create network objects:

print("\n" + "=" * 70)
print("NETWORK OBJECTS")
print("=" * 70)
# Create a network object for our lab subnet
lab_network = ipaddress.IPv4Network("192.168.1.0/24")
print(f"Lab network: {lab_network}")
print(f"Network address: {lab_network.network_address}")
print(f"Broadcast address: {lab_network.broadcast_address}")
print(f"Netmask: {lab_network.netmask}")
print(f"Number of addresses: {lab_network.num_addresses}")

ipaddress.IPv4Network("192.168.1.0/24") creates a network object. This represents the entire subnet.

Task 2: Subnet Calculations and Validations

Let's do subnet calculations. Create a file subnet_calc.py.

# Subnet calculations and validations
print("SUBNET CALCULATIONS")
print("=" * 70)
import ipaddress

First, let's validate if an IP is in our lab subnet:

# Our lab network
lab_net = ipaddress.IPv4Network("192.168.1.0/24")
# Test IPs
test_ips = [
"192.168.1.1", # Router1 - should be in subnet
"192.168.1.10", # Should be in subnet
"192.168.2.1", # Different subnet
"10.0.0.1" # Different network
]
print(f"Lab network: {lab_net}")
print("\nChecking if IPs are in lab subnet:")
print("-" * 40)
for ip_str in test_ips:
ip = ipaddress.IPv4Address(ip_str)
in_subnet = ip in lab_net
if in_subnet:
print(f"✓ {ip} is in {lab_net}")
else:
print(f"✗ {ip} is NOT in {lab_net}")

The in operator checks if an IP is in a network. ip in lab_net returns True or False.

Now let's calculate subnets:

print("\n" + "=" * 70)
print("SUBNET CALCULATIONS")
print("=" * 70)
# Create a larger network
large_network = ipaddress.IPv4Network("10.0.0.0/16")
print(f"Large network: {large_network}")
print(f"Total IPs: {large_network.num_addresses}")
print()
# Divide into smaller subnets
subnets = list(large_network.subnets(prefixlen_diff=2))
print(f"Dividing /16 into /18 subnets:")
print(f"Number of subnets created: {len(subnets)}")
print()
for i, subnet in enumerate(subnets[:4], 1): # Show first 4
print(f"Subnet {i}: {subnet}")
print(f" Usable hosts: {subnet.num_addresses - 2}")

subnets(prefixlen_diff=2) divides the network. prefixlen_diff=2 means increase prefix length by 2 (from /16 to /18).

Now let's calculate for our lab:

print("\n" + "=" * 70)
print("LAB SUBNET CALCULATIONS")
print("=" * 70)
# Our lab is /24, let's see what it contains
lab_subnet = ipaddress.IPv4Network("192.168.1.0/24")
print(f"Lab subnet: {lab_subnet}")
print(f"Network IP: {lab_subnet.network_address}")
print(f"Broadcast IP: {lab_subnet.broadcast_address}")
print(f"Usable IPs: {lab_subnet.num_addresses - 2}")
print(f"First usable: {lab_subnet.network_address + 1}")
print(f"Last usable: {lab_subnet.broadcast_address - 1}")

Now let's check each lab device's IP:

print("\nLab device IP analysis:")
print("-" * 40)
lab_devices = {
"Router1": "192.168.1.1",
"Router2": "192.168.1.2",
"Switch1": "192.168.1.3",
"Switch2": "192.168.1.4",
"Ubuntu_Server": "192.168.1.5"
}
for device, ip_str in lab_devices.items():
ip = ipaddress.IPv4Address(ip_str)
if ip in lab_subnet:
print(f"✓ {device:15} {ip:15} - Valid lab IP")
else:
print(f"✗ {device:15} {ip:15} - NOT in lab subnet")

Task 3: Checking if IP is in a Specific Subnet

Let's create a function to check IPs against subnets. Create ip_checking.py.

# Checking if IP is in specific subnet
print("IP SUBNET MEMBERSHIP CHECKING")
print("=" * 70)
import ipaddress

First, let's define our network segments:

# Define our network segments
networks = {
"management": ipaddress.IPv4Network("192.168.1.0/24"),
"users": ipaddress.IPv4Network("10.10.10.0/24"),
"servers": ipaddress.IPv4Network("10.10.20.0/24"),
"voice": ipaddress.IPv4Network("10.10.30.0/24")
}
print("Network segments:")
for name, net in networks.items():
print(f" {name:12} {net}")

Now let's check where an IP belongs:

def find_ip_network(ip_str):
"""Find which network an IP belongs to"""
try:
ip = ipaddress.IPv4Address(ip_str)
except ValueError:
return None, "Invalid IP address"
for network_name, network in networks.items():
if ip in network:
return network_name, network
return None, "IP not in any defined network"
print("\n" + "=" * 70)
print("FINDING IP NETWORKS")
print("=" * 70)
# Test IPs
test_ips = [
"192.168.1.1", # Router1 - management
"192.168.1.5", # Ubuntu Server - management
"10.10.10.100", # User PC
"10.10.20.50", # Server
"192.168.2.1" # Unknown network
]
print("Checking IP network membership:")
print("-" * 40)
for ip_str in test_ips:
network_name, result = find_ip_network(ip_str)
if network_name:
print(f"✓ {ip_str:15} → {network_name:12} network")
else:
print(f"✗ {ip_str:15} → {result}")

This function checks an IP against all defined networks.

Now let's check all our lab IPs:

print("\n" + "=" * 70)
print("CHECKING ALL LAB IPs")
print("=" * 70)
lab_ips = {
"Router1": "192.168.1.1",
"Router2": "192.168.1.2",
"Switch1": "192.168.1.3",
"Switch2": "192.168.1.4",
"Ubuntu_Server": "192.168.1.5"
}
print("Lab device network analysis:")
print("-" * 40)
for device, ip_str in lab_ips.items():
network_name, _ = find_ip_network(ip_str)
if network_name == "management":
print(f"✓ {device:15} {ip_str:15} - Management network")
else:
print(f"✗ {device:15} {ip_str:15} - Wrong network ({network_name})")

Now let's check if an IP is valid for a specific network:

print("\n" + "=" * 70)
print("VALIDATING IP FOR SPECIFIC NETWORK")
print("=" * 70)
def validate_ip_for_network(ip_str, network_name):
"""Check if IP is valid for a specific network"""
if network_name not in networks:
return False, f"Network '{network_name}' not defined"
network = networks[network_name]
try:
ip = ipaddress.IPv4Address(ip_str)
except ValueError:
return False, "Invalid IP address"
if ip in network:
# Check if it's not network or broadcast address
if ip == network.network_address:
return False, "Cannot use network address"
elif ip == network.broadcast_address:
return False, "Cannot use broadcast address"
else:
return True, "Valid IP for network"
else:
return False, f"IP not in {network_name} network"
# Test validation
test_cases = [
("192.168.1.1", "management", True),
("192.168.1.0", "management", False), # Network address
("192.168.1.255", "management", False), # Broadcast address
("10.10.10.100", "users", True),
("192.168.1.100", "users", False) # Wrong network
]
print("IP validation tests:")
print("-" * 40)
for ip_str, network_name, should_pass in test_cases:
is_valid, message = validate_ip_for_network(ip_str, network_name)
status = "✓" if is_valid == should_pass else "✗"
print(f"{status} {ip_str:15} for {network_name:12}: {message}")

Task 4: Network Summarization

Let's work with network summarization. Create network_summary.py.

python

# Network summarization

print("NETWORK SUMMARIZATION")

print("=" * 70)


import ipaddress


First, let's create some networks:


python

# Create some networks

networks = [

    ipaddress.IPv4Network("192.168.1.0/24"),

    ipaddress.IPv4Network("192.168.2.0/24"),

    ipaddress.IPv4Network("192.168.3.0/24"),

    ipaddress.IPv4Network("192.168.4.0/24")

]


print("Original networks:")

for net in networks:

    print(f"  {net}")


Now let's summarize them:


python

print("\n" + "=" * 70)

print("SUMMARIZING NETWORKS")

print("=" * 70)


# Summarize the networks

try:

    summarized = ipaddress.collapse_addresses(networks)

    summarized_list = list(summarized)

    

    print(f"Original networks: {len(networks)}")

    print(f"Summarized to: {len(summarized_list)} network(s)")

    print()

    

    for net in summarized_list:

        print(f"  {net}")

        

except Exception as e:

    print(f"Error summarizing: {e}")

collapse_addresses() tries to combine networks into larger summaries.


Now let's work with our lab topology networks:


python

print("\n" + "=" * 70)

print("LAB NETWORK ANALYSIS")

print("=" * 70)


# Simulated networks in our lab

lab_networks = [

    ipaddress.IPv4Network("192.168.1.0/24"),  # Management

    ipaddress.IPv4Network("10.10.10.0/24"),   # Users

    ipaddress.IPv4Network("10.10.20.0/24"),   # Servers

    ipaddress.IPv4Network("10.10.30.0/24")    # Voice

]


print("Lab networks:")

for net in lab_networks:

    print(f"  {net}")

    print(f"    Usable hosts: {net.num_addresses - 2}")


These networks can't be summarized (they're in different ranges). Let's create networks that can be summarized:


python

print("\n" + "=" * 70)

print("SUMMARIZABLE NETWORKS")

print("=" * 70)


# Networks that can be summarized

summary_networks = [

    ipaddress.IPv4Network("10.10.10.0/24"),

    ipaddress.IPv4Network("10.10.11.0/24"),

    ipaddress.IPv4Network("10.10.12.0/24"),

    ipaddress.IPv4Network("10.10.13.0/24")

]


print("Networks to summarize:")

for net in summary_networks:

    print(f"  {net}")


# Summarize

summarized = list(ipaddress.collapse_addresses(summary_networks))


print(f"\nSummarized to: {len(summarized)} network(s)")

for net in summarized:

    print(f"  {net}")

    print(f"    Covers: {2**(net.prefixlen - 24)} /24 networks")


Now let's check if networks overlap:


python

print("\n" + "=" * 70)

print("CHECKING NETWORK OVERLAPS")

print("=" * 70)


def check_overlap(net1_str, net2_str):

    """Check if two networks overlap"""

    

    net1 = ipaddress.IPv4Network(net1_str)

    net2 = ipaddress.IPv4Network(net2_str)

    

    overlap = net1.overlaps(net2)

    

    print(f"Network 1: {net1}")

    print(f"Network 2: {net2}")

    

    if overlap:

        print("  ✗ Networks OVERLAP")

    else:

        print("  ✓ Networks do NOT overlap")

    

    print()

    return overlap


# Test network overlaps

test_pairs = [

    ("192.168.1.0/24", "192.168.2.0/24"),  # No overlap

    ("192.168.1.0/24", "192.168.1.128/25"), # Overlap (second is subnet of first)

    ("10.0.0.0/8", "10.1.0.0/16"),         # Overlap (second is subnet of first)

    ("172.16.0.0/16", "172.17.0.0/16")     # No overlap

]


print("Checking network overlaps:")

print("-" * 40)


for net1_str, net2_str in test_pairs:

    check_overlap(net1_str, net2_str)

overlaps() checks if networks overlap.


Task 5: Creating an IP Address Management Tool


Let's create a simple IPAM tool. Create ipam_tool.py.


python

# IP Address Management Tool

print("SIMPLE IP ADDRESS MANAGEMENT TOOL")

print("=" * 70)


import ipaddress


First, let's create a subnet and track used IPs:


python

# Create a subnet for management

mgmt_subnet = ipaddress.IPv4Network("192.168.1.0/24")


print(f"Management subnet: {mgmt_subnet}")

print(f"Total IPs: {mgmt_subnet.num_addresses}")

print(f"Usable IPs: {mgmt_subnet.num_addresses - 2}")

print()


# Track used IPs

used_ips = set()


# Add our lab devices

lab_devices = {

    "Router1": "192.168.1.1",

    "Router2": "192.168.1.2",

    "Switch1": "192.168.1.3",

    "Switch2": "192.168.1.4",

    "Ubuntu_Server": "192.168.1.5"

}


print("Lab device IPs:")

print("-" * 40)


for device, ip_str in lab_devices.items():

    ip = ipaddress.IPv4Address(ip_str)

    

    if ip in mgmt_subnet:

        used_ips.add(ip)

        print(f"✓ {device:15} {ip:15} - Added to used IPs")

    else:

        print(f"✗ {device:15} {ip:15} - Not in management subnet")


print(f"\nUsed IPs: {len(used_ips)}")


Now let's find available IPs:


python

print("\n" + "=" * 70)

print("FINDING AVAILABLE IPS")

print("=" * 70)


def find_available_ips(subnet, used_ips, count=5):

    """Find available IPs in subnet"""

    

    available = []

    

    # Start from first usable IP

    current_ip = subnet.network_address + 1

    

    while len(available) < count and current_ip < subnet.broadcast_address:

        if current_ip not in used_ips:

            available.append(current_ip)

        current_ip += 1

    

    return available


print("Finding available IPs in management subnet...")

available = find_available_ips(mgmt_subnet, used_ips, count=10)


print(f"\nFirst 10 available IPs:")

for i, ip in enumerate(available, 1):

    print(f"{i:2}. {ip}")


This function finds unused IPs in the subnet.


Now let's check if an IP is available:


python

print("\n" + "=" * 70)

print("CHECKING IP AVAILABILITY")

print("=" * 70)


def check_ip_availability(ip_str, subnet, used_ips):

    """Check if an IP is available"""

    

    try:

        ip = ipaddress.IPv4Address(ip_str)

    except ValueError:

        return False, "Invalid IP address"

    

    # Check if in subnet

    if ip not in subnet:

        return False, f"IP not in {subnet}"

    

    # Check if network or broadcast address

    if ip == subnet.network_address:

        return False, "Network address (not usable)"

    if ip == subnet.broadcast_address:

        return False, "Broadcast address (not usable)"

    

    # Check if already used

    if ip in used_ips:

        return False, "IP already in use"

    

    return True, "IP is available"


# Test IP availability

test_ips = [

    "192.168.1.1",    # Router1 - used

    "192.168.1.6",    # Should be available

    "192.168.1.0",    # Network address

    "192.168.1.255",  # Broadcast address

    "192.168.2.1"     # Wrong subnet

]


print("Checking IP availability:")

print("-" * 40)


for ip_str in test_ips:

    available, message = check_ip_availability(ip_str, mgmt_subnet, used_ips)

    

    status = "✓" if available else "✗"

    print(f"{status} {ip_str:15} - {message}")


Now let's allocate an IP:


python

print("\n" + "=" * 70)

print("ALLOCATING AN IP ADDRESS")

print("=" * 70)


def allocate_ip(device_name, ip_str, subnet, used_ips):

    """Allocate an IP address to a device"""

    

    # Check availability

    available, message = check_ip_availability(ip_str, subnet, used_ips)

    

    if not available:

        return False, message

    

    # Allocate the IP

    ip = ipaddress.IPv4Address(ip_str)

    used_ips.add(ip)

    

    return True, f"Allocated {ip} to {device_name}"


# Try to allocate some IPs

allocation_tests = [

    ("New_Router", "192.168.1.6"),

    ("New_Switch", "192.168.1.1"),  # Already used

    ("Test_Device", "192.168.1.100")

]


print("Allocating IPs to devices:")

print("-" * 40)


for device, ip_str in allocation_tests:

    success, message = allocate_ip(device, ip_str, mgmt_subnet, used_ips)

    

    status = "✓" if success else "✗"

    print(f"{status} {device:15} {ip_str:15} - {message}")


print(f"\nTotal used IPs: {len(used_ips)}")


Now let's create a simple IPAM class:


python

print("\n" + "=" * 70)

print("SIMPLE IPAM CLASS")

print("=" * 70)


class SimpleIPAM:

    """Simple IP Address Management"""

    

    def __init__(self, subnet_str):

        self.subnet = ipaddress.IPv4Network(subnet_str)

        self.used_ips = set()

        self.allocations = {}  # device_name -> ip

    

    def allocate(self, device_name, ip_str=None):

        """Allocate an IP to a device"""

        

        # If no IP specified, find one

        if ip_str is None:

            ip = self.find_next_available()

            if ip is None:

                return False, "No available IPs"

        else:

            # Check specified IP

            ip = ipaddress.IPv4Address(ip_str)

            

            if ip not in self.subnet:

                return False, f"IP not in {self.subnet}"

            

            if ip == self.subnet.network_address:

                return False, "Cannot use network address"

            

            if ip == self.subnet.broadcast_address:

                return False, "Cannot use broadcast address"

            

            if ip in self.used_ips:

                return False, "IP already allocated"

        

        # Allocate

        self.used_ips.add(ip)

        self.allocations[device_name] = ip

        

        return True, f"Allocated {ip} to {device_name}"

    

    def find_next_available(self):

        """Find next available IP"""

        

        current_ip = self.subnet.network_address + 1

        

        while current_ip < self.subnet.broadcast_address:

            if current_ip not in self.used_ips:

                return current_ip

            current_ip += 1

        

        return None

    

    def show_allocations(self):

        """Show all allocations"""

        

        print(f"\nSubnet: {self.subnet}")

        print(f"Total IPs: {self.subnet.num_addresses}")

        print(f"Used IPs: {len(self.used_ips)}")

        print(f"Available: {self.subnet.num_addresses - 2 - len(self.used_ips)}")

        print()

        

        print("Device allocations:")

        print("-" * 40)

        

        for device, ip in self.allocations.items():

            print(f"{device:20} {ip}")


# Test the IPAM class

print("Testing SimpleIPAM class...")


# Create IPAM for management subnet

ipam = SimpleIPAM("192.168.1.0/24")


# Allocate IPs to lab devices

devices_to_allocate = [

    ("Router1", "192.168.1.1"),

    ("Router2", "192.168.1.2"),

    ("Switch1", "192.168.1.3"),

    ("Switch2", "192.168.1.4"),

    ("Ubuntu_Server", "192.168.1.5")

]


print("\nAllocating IPs to lab devices:")

print("-" * 40)


for device, ip in devices_to_allocate:

    success, message = ipam.allocate(device, ip)

    print(f"{'✓' if success else '✗'} {message}")


# Allocate a new device with auto IP

print("\nAllocating new device with auto IP:")

success, message = ipam.allocate("New_Switch")

print(f"{'✓' if success else '✗'} {message}")


# Show all allocations

ipam.show_allocations()


This SimpleIPAM class manages IP allocations in a subnet.


Each script focuses on one aspect of IP address management. The functions are small and do one thing. You can combine these to build more complex IP management tools.


Key points:


1.Use ipaddress module for IP calculations

2.Validate IPs before using them

3.Track used IPs to avoid conflicts

4.Check network boundaries

5.Create reusable functions for common tasks