Generar todas las direcciones IP de una red en Python
Explora varios métodos para generar y enumerar las direcciones IP de una red con ipaddress, con optimización de memoria y ejemplos prácticos de uso.
InSkillCoach
Generar todas las direcciones IP de una red en Python
Generar o enumerar todas las direcciones IP de una red es una tarea habitual en administración de sistemas, reconocimiento de red y pruebas de aplicaciones. El módulo ipaddress de Python proporciona herramientas eficaces para ello. La clave está en entender la diferencia entre subnets() para las subredes, hosts() para las direcciones utilizables y la red completa, así como en utilizar generadores para evitar problemas de memoria en redes grandes.
1. Enumerar las direcciones utilizables con hosts()
El método hosts() devuelve un generador con todas las direcciones IP utilizables de una red, excluyendo la dirección de red y la dirección de broadcast.
import ipaddress
reseau = ipaddress.ip_network("192.168.1.0/24")
# hosts() retourne un générateur (pas une liste)
print(type(reseau.hosts())) # <class 'generator'>
# Itérer sur tous les hôtes
for ip in reseau.hosts():
print(ip)
# Affiche : 192.168.1.1, 192.168.1.2, ..., 192.168.1.254
# (254 adresses pour un /24)
Convertir en lista (¡cuidado con la memoria!)
import ipaddress
reseau = ipaddress.ip_network("192.168.1.0/24")
# Convertir le générateur en liste
liste_ips = list(reseau.hosts())
print(f"Nombre d'adresses : {len(liste_ips)}") # 254
# Accès direct à un élément
print(liste_ips[0]) # 192.168.1.1
print(liste_ips[10]) # 192.168.1.11
# ⚠️ WARNING : Ne pas faire cela sur un grand réseau !
# reseau_enorme = ipaddress.ip_network("10.0.0.0/8") # 16 millions d'IPs
# liste_enorme = list(reseau_enorme.hosts()) # Consomme plusieurs Go de RAM
2. Enumerar la red completa mediante iteración
Para incluir la dirección de red y la dirección de broadcast, itera directamente sobre la red.
import ipaddress
reseau = ipaddress.ip_network("192.168.1.0/24")
# Itérer sur toutes les adresses (réseau + hôtes + broadcast)
for ip in reseau:
print(ip)
# Affiche : 192.168.1.0, 192.168.1.1, ..., 192.168.1.255
# (256 adresses pour un /24)
# Nombre total d'adresses
print(f"Nombre total : {reseau.num_addresses}") # 256
3. Diferencia: hosts() frente a la red completa
import ipaddress
reseau = ipaddress.ip_network("10.0.0.0/30")
# hosts() : exclut l'adresse réseau et le broadcast
print("hosts():")
for ip in reseau.hosts():
print(f" {ip}")
# Affiche : 10.0.0.1, 10.0.0.2
# (2 adresses utilisables)
# Itération complète
print("Réseau complet:")
for ip in reseau:
print(f" {ip}")
# Affiche : 10.0.0.0, 10.0.0.1, 10.0.0.2, 10.0.0.3
# (4 adresses totales : réseau 0, hôtes 1-2, broadcast 3)
4. Optimización de memoria con generadores
En las redes grandes, utiliza generadores e itertools.islice para limitar el número de direcciones procesadas.
import ipaddress
import itertools
reseau_enorme = ipaddress.ip_network("10.0.0.0/8") # 16 millions d'IPs
# ✗ NE PAS FAIRE : cela consomme 100+ GB de RAM
# toutes_les_ips = list(reseau_enorme.hosts())
# ✓ FAIRE : utiliser un générateur et islice
print("Afficher les 10 premières adresses :")
for ip in itertools.islice(reseau_enorme.hosts(), 10):
print(ip)
# Affiche : 10.0.0.1, 10.0.0.2, ..., 10.0.0.10
# Traiter les adresses par lots
print("\nTraiter par lots de 100 :")
for lot in iter(lambda: list(itertools.islice(reseau_enorme.hosts(), 100)), []):
print(f"Lot de {len(lot)} adresses : {lot[0]} à {lot[-1]}")
# Traiter chaque lot (scanner, ping, etc.)
5. Dividir una red en subredes
El método subnets() divide una red en subredes más pequeñas.
import ipaddress
# Réseau initial
reseau = ipaddress.ip_network("192.168.0.0/22")
# Diviser en /24 (4 sous-réseaux)
print("Sous-réseaux /24 :")
for subnet in reseau.subnets(new_prefix=24):
print(f" {subnet}")
# Affiche :
# 192.168.0.0/24
# 192.168.1.0/24
# 192.168.2.0/24
# 192.168.3.0/24
# Diviser en /25 (8 sous-réseaux)
print("\nSous-réseaux /25 :")
for subnet in reseau.subnets(new_prefix=25):
print(f" {subnet}")
6. Contar las direcciones
import ipaddress
reseau = ipaddress.ip_network("172.16.0.0/12")
# Nombre total
print(f"Total : {reseau.num_addresses}") # 1048576
# Nombre d'hôtes utilisables (excluant réseau et broadcast)
print(f"Hôtes utilisables : {len(list(reseau.hosts()))}") # 1048574
# Adresses réservées
print(f"Réservées : 2 (réseau + broadcast)")
7. Exportar a un archivo
Para procesar millones de IP, escribe en un archivo en lugar de cargarlas en memoria.
import ipaddress
reseau = ipaddress.ip_network("10.0.0.0/16")
# Exporter en fichier texte
with open("ips.txt", "w") as f:
for ip in reseau.hosts():
f.write(f"{ip}\n")
# Vérifier le fichier
with open("ips.txt", "r") as f:
nb_lignes = sum(1 for _ in f)
print(f"Fichier contient {nb_lignes} adresses")
# Fichier contient 65534 adresses
8. Ejemplo: escáner de red sencillo
Escanea las direcciones activas de una red (ten en cuenta que esto requiere los permisos adecuados).
import ipaddress
import socket
from concurrent.futures import ThreadPoolExecutor, as_completed
def ping_ip(ip, timeout=1):
"""Vérifier si une IP répond."""
try:
socket.create_connection((str(ip), 22), timeout=timeout)
return True
except (socket.timeout, socket.error):
return False
def scanner_reseau(reseau_cidr, num_workers=10):
"""Scanner un réseau et lister les IPs actives."""
reseau = ipaddress.ip_network(reseau_cidr, strict=False)
actives = []
with ThreadPoolExecutor(max_workers=num_workers) as executor:
futures = {
executor.submit(ping_ip, ip): ip
for ip in reseau.hosts()
}
for future in as_completed(futures):
ip = futures[future]
if future.result():
actives.append(ip)
print(f"✓ {ip} actif")
return actives
# Scanner le réseau 192.168.1.0/24
# ips_actives = scanner_reseau("192.168.1.0/24")
# print(f"\nTotal actifs : {len(ips_actives)}")
# Note : remplacer socket.create_connection par un vrai ping
# pour une reconnaissance plus réaliste (ICMP)
9. Caso de uso: listar las direcciones por rango
import ipaddress
def generer_adresses_par_plages(plages):
"""
Génère des adresses IP à partir de multiples plages CIDR.
Args:
plages (list): Liste de strings CIDR (ex: ["192.168.1.0/24", "10.0.0.0/16"])
Yields:
ipaddress.IPv4Address : adresse IP
"""
for plage in plages:
reseau = ipaddress.ip_network(plage, strict=False)
for ip in reseau.hosts():
yield ip
# Utilisation
plages_internes = [
"192.168.0.0/16",
"10.0.0.0/8",
"172.16.0.0/12",
]
print("Afficher les 20 premières adresses internes :")
for i, ip in enumerate(generer_adresses_par_plages(plages_internes)):
if i >= 20:
break
print(ip)
10. Buenas prácticas
- Utiliza generadores: no cargues millones de IP en memoria de golpe.
hosts()frente a la iteración directa: usahosts()para excluir la dirección de red y el broadcast (caso habitual).- Atención a los /30 y a los prefijos más pequeños: un
/32solo tiene una dirección, un/31tiene dos yhosts()devuelve cero. - Prueba primero en redes pequeñas: antes de escanear redes /8 o /16.
- Respeta la ley: escanea únicamente las redes que controles.
Conclusión
Generar o enumerar las direcciones IP de una red en Python es sencillo con ipaddress, pero hay que ser consciente del rendimiento en las redes grandes. Los generadores, subnets() e islice son tus mejores aliados para procesar eficazmente bloques CIDR sin agotar la memoria. Estas técnicas son indispensables para la administración de sistemas, el reconocimiento de red y las pruebas de infraestructura.
Acerca de InSkillCoach
Experto en formación y tecnologías
Coach especializado en tecnologías avanzadas e IA, impulsado por GNeurone Inc.
Certificaciones:
- AWS Certified Solutions Architect – Professional
- Certificaciones de Google Cloud
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión