0%
Extract Subnet Addresses with Python

Extract Subnet Addresses with Python

Learn how to extract and analyze all the IP addresses in a subnet with Python. Optimized techniques for network monitoring and security auditing.

I

InSkillCoach

· min

Extract Subnet Addresses with Python

Extracting and analyzing the IP addresses in a subnet are essential tasks for network administrators, security specialists, and developers of monitoring tools. In this guide, we will explore how to use Python to efficiently extract all the addresses in a subnet, filter them by various criteria, and analyze them for a range of practical applications.

Why extract subnet addresses?

Extracting the IP addresses of a subnet is useful for:

  • Network inventory: Catalog all available addresses
  • Security auditing: Check which addresses are active or in use
  • Capacity planning: Assess subnet utilization
  • Network monitoring: Systematically monitor all addresses
  • Device configuration: Prepare configuration scripts for network devices

The ipaddress module to the rescue

Python provides a powerful module called ipaddress that greatly simplifies working with IP addresses and subnets. Let’s import it to get started:

import ipaddress

Extracting all addresses in a subnet

Basic technique

The simplest way to extract all the addresses in a subnet is to iterate over the network object:

def extract_all_addresses(cidr):
    """Extrait toutes les adresses IP d'un sous-réseau donné en notation CIDR."""
    network = ipaddress.ip_network(cidr)
    return list(network.hosts())

# Exemple pour un petit sous-réseau
subnet = "192.168.1.0/29"
addresses = extract_all_addresses(subnet)
print(f"Le sous-réseau {subnet} contient {len(addresses)} adresses utilisables:")
for addr in addresses:
    print(f"  - {addr}")

Output:

Le sous-réseau 192.168.1.0/29 contient 6 adresses utilisables:
  - 192.168.1.1
  - 192.168.1.2
  - 192.168.1.3
  - 192.168.1.4
  - 192.168.1.5
  - 192.168.1.6

Optimization for large subnets

For large subnets, it’s better to avoid storing all the addresses in memory at once. Let’s use generators:

def address_generator(cidr):
    """Générateur qui produit les adresses IP d'un sous-réseau sans les charger toutes en mémoire."""
    network = ipaddress.ip_network(cidr)
    for host in network.hosts():
        yield host

# Utilisation pour un sous-réseau plus grand
subnet = "10.0.0.0/24"  # 254 adresses utilisables
for i, addr in enumerate(address_generator(subnet)):
    if i < 5:  # Afficher seulement les 5 premières
        print(f"Adresse {i+1}: {addr}")
    elif i == 5:
        print("...")

Extracting subsets of addresses

Addresses at the beginning and end of the subnet

def get_subnet_boundaries(cidr, count=5):
    """Retourne les premières et dernières adresses d'un sous-réseau."""
    network = ipaddress.ip_network(cidr)
    hosts = list(network.hosts())
    
    if len(hosts) <= count * 2:
        return hosts
        
    return hosts[:count] + hosts[-count:]

# Exemple
subnet = "172.16.0.0/20"
boundaries = get_subnet_boundaries(subnet)
print(f"Premières adresses de {subnet}:")
for addr in boundaries[:5]:
    print(f"  - {addr}")
print(f"Dernières adresses de {subnet}:")
for addr in boundaries[-5:]:
    print(f"  - {addr}")

Extracting addresses by range

def extract_address_range(cidr, start_idx, end_idx):
    """Extrait une plage spécifique d'adresses d'un sous-réseau."""
    network = ipaddress.ip_network(cidr)
    hosts = list(network.hosts())
    
    if start_idx >= len(hosts) or end_idx > len(hosts):
        raise ValueError("Indices hors limites")
        
    return hosts[start_idx:end_idx]

# Exemple: obtenir les adresses 10 à 20 d'un sous-réseau
subnet = "192.168.2.0/24"
middle_range = extract_address_range(subnet, 10, 20)
print(f"Adresses 10 à 20 de {subnet}:")
for addr in middle_range:
    print(f"  - {addr}")

Analyzing and filtering addresses

Filtering by address pattern

def filter_by_pattern(cidr, pattern):
    """Filtre les adresses d'un sous-réseau selon un motif."""
    network = ipaddress.ip_network(cidr)
    pattern_str = str(pattern)
    
    result = []
    for addr in network.hosts():
        if pattern_str in str(addr):
            result.append(addr)
    
    return result

# Exemple: trouver toutes les adresses contenant "100"
subnet = "192.168.0.0/22"
matching_addrs = filter_by_pattern(subnet, "100")
print(f"Adresses contenant '100' dans {subnet}:")
for addr in matching_addrs:
    print(f"  - {addr}")

Identifying even and odd addresses

def categorize_addresses(cidr):
    """Catégorise les adresses en paires et impaires."""
    network = ipaddress.ip_network(cidr)
    even = []
    odd = []
    
    for host in network.hosts():
        if int(host) % 2 == 0:
            even.append(host)
        else:
            odd.append(host)
    
    return {
        'even': even,
        'odd': odd
    }

# Exemple
subnet = "192.168.1.16/28"
categories = categorize_addresses(subnet)
print(f"Adresses paires de {subnet}: {len(categories['even'])}")
print(f"Adresses impaires de {subnet}: {len(categories['odd'])}")

Practical applications

Scanning a subnet for active hosts

import subprocess
import concurrent.futures
import platform

def ping(ip):
    """Vérifie si une adresse IP répond au ping."""
    param = "-n" if platform.system().lower() == "windows" else "-c"
    command = ["ping", param, "1", str(ip)]
    return subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0

def scan_subnet(cidr, max_workers=10):
    """Scanne un sous-réseau pour trouver les hôtes actifs."""
    network = ipaddress.ip_network(cidr)
    active_hosts = []
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        # Créer un dictionnaire de futures
        future_to_ip = {executor.submit(ping, ip): ip for ip in network.hosts()}
        
        for future in concurrent.futures.as_completed(future_to_ip):
            ip = future_to_ip[future]
            try:
                if future.result():
                    active_hosts.append(ip)
                    print(f"Hôte actif trouvé: {ip}")
            except Exception as exc:
                print(f"{ip} a généré une exception: {exc}")
    
    return active_hosts

# Exemple d'utilisation (attention: peut prendre du temps selon la taille du sous-réseau)
# active_hosts = scan_subnet("192.168.1.0/24")
# print(f"Total des hôtes actifs: {len(active_hosts)}")

Generating configuration files for network devices

def generate_dhcp_config(cidr, domain="example.com"):
    """Génère une configuration DHCP pour un sous-réseau."""
    network = ipaddress.ip_network(cidr)
    
    config = [
        f"subnet {network.network_address} netmask {network.netmask} {{",
        f"  option domain-name \"{domain}\";",
        f"  option domain-name-servers 8.8.8.8, 8.8.4.4;",
        f"  option routers {next(network.hosts())};",
        f"  option broadcast-address {network.broadcast_address};",
        f"  default-lease-time 600;",
        f"  max-lease-time 7200;",
        "}",
        "",
        "# Réservations statiques"
    ]
    
    # Ajouter quelques réservations d'exemple
    for i, host in enumerate(list(network.hosts())[:5]):
        config.append(f"host device{i+1} {{")
        config.append(f"  hardware ethernet 00:11:22:33:44:{i+1:02x};")
        config.append(f"  fixed-address {host};")
        config.append("}")
    
    return "\n".join(config)

# Exemple
subnet = "192.168.5.0/24"
dhcp_config = generate_dhcp_config(subnet)
print("Configuration DHCP générée:")
print(dhcp_config)

Handling IPv6

The ipaddress module works just as well with IPv6 as with IPv4:

def compare_ipv4_ipv6_extraction(ipv4_cidr, ipv6_cidr, count=5):
    """Compare l'extraction d'adresses IPv4 et IPv6."""
    ipv4_net = ipaddress.ip_network(ipv4_cidr)
    ipv6_net = ipaddress.ip_network(ipv6_cidr)
    
    ipv4_hosts = list(ipv4_net.hosts())[:count]
    ipv6_hosts = list(ipv6_net.hosts())[:count]
    
    print(f"Premiers {count} hôtes IPv4 dans {ipv4_cidr}:")
    for host in ipv4_hosts:
        print(f"  - {host}")
    
    print(f"\nPremiers {count} hôtes IPv6 dans {ipv6_cidr}:")
    for host in ipv6_hosts:
        print(f"  - {host}")
    
    print(f"\nTaille totale IPv4: {ipv4_net.num_addresses} adresses")
    print(f"Taille totale IPv6: {ipv6_net.num_addresses} adresses")

# Exemple
compare_ipv4_ipv6_extraction("192.168.1.0/24", "2001:db8::/120")

Performance optimization

For very large subnets (such as /16 or larger in IPv4, or most IPv6 subnets), full enumeration can be inefficient or impossible. Here are a few optimized approaches:

def sample_large_subnet(cidr, sample_size=1000):
    """Échantillonne un grand sous-réseau de manière statistique."""
    network = ipaddress.ip_network(cidr)
    total_addresses = network.num_addresses
    
    # Si le réseau a des adresses de broadcast/réseau, les exclure du calcul
    if network.version == 4:
        host_addresses = total_addresses - 2
    else:  # IPv6 n'a pas ces restrictions
        host_addresses = total_addresses
    
    if host_addresses <= sample_size:
        return list(network.hosts())
    
    # Calculer des points d'échantillonnage statistiques
    step = host_addresses // sample_size
    
    result = []
    current = int(network.network_address) + (1 if network.version == 4 else 0)
    
    for _ in range(sample_size):
        addr = ipaddress.ip_address(current)
        if addr in network:
            result.append(addr)
        current += step
    
    return result

# Exemple avec un grand sous-réseau
large_subnet = "10.0.0.0/16"  # 65,534 adresses utilisables
samples = sample_large_subnet(large_subnet, 10)
print(f"Échantillon de 10 adresses du sous-réseau {large_subnet}:")
for addr in samples:
    print(f"  - {addr}")

Key takeaways

  • The ipaddress module is essential for working efficiently with IP addresses in Python
  • For small subnets, full enumeration is simple and efficient
  • For large subnets, favor generators and sampling
  • Extraction techniques can be adapted for both IPv4 and IPv6
  • Practical applications include network scanning, device configuration, and address inventory

Conclusion

Extracting IP addresses from a subnet is a fundamental skill for any network administrator or developer working with network applications. With its ipaddress module, Python provides powerful tools to automate these tasks and integrate them into larger network management, monitoring, or security systems.

By mastering these techniques, you can build robust solutions for managing your network infrastructure, whether you’re dealing with small local networks or large enterprise deployments.

InSkillCoach

About InSkillCoach

Training and technology expert

Coach specializing in advanced technologies and AI, backed by GNeurone Inc.

Certifications:

  • AWS Certified Solutions Architect – Professional
  • Google Cloud certifications
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.6k
262

Comments

Comments are powered by GitHub Discussions

Sign in with GitHub to join the discussion

Link copied!