Verificar se um Endereço IP Pertence a uma Rede em Python
Aprenda a verificar se um endereço IP pertence a uma rede usando o módulo ipaddress. Exemplos práticos para firewalls, listas de permissão e filtragem de rede.
InSkillCoach
Verificar se um Endereço IP Pertence a uma Rede em Python
Uma tarefa comum em administração de redes e em segurança de aplicações é determinar se um determinado endereço IP pertence a uma rede específica. O módulo ipaddress do Python oferece ferramentas elegantes e robustas para essa verificação. Seja para implementar uma lista de permissão, um firewall de aplicação ou uma validação de acesso, este guia mostrará como dominar essa funcionalidade.
1. O Módulo ipaddress
O módulo ipaddress está incluído na stdlib do Python desde a versão 3.3. Ele fornece classes para representar e manipular endereços IP e redes.
import ipaddress
# Créer une adresse IP
ip = ipaddress.ip_address("192.168.1.100")
print(ip) # 192.168.1.100
print(type(ip)) # <class 'ipaddress.IPv4Address'>
# Créer un réseau
reseau = ipaddress.ip_network("192.168.1.0/24")
print(reseau) # 192.168.1.0/24
print(type(reseau)) # <class 'ipaddress.IPv4Network'>
2. Verificar a Pertinência com o operador in
O operador in testa se um endereço IP pertence a uma rede.
import ipaddress
reseau = ipaddress.ip_network("192.168.1.0/24")
# Tester si des adresses appartiennent au réseau
print("192.168.1.50" in reseau) # True
print("192.168.2.50" in reseau) # False
print("10.0.0.1" in reseau) # False
# Note : l'adresse réseau et l'adresse broadcast font partie du réseau
print("192.168.1.0" in reseau) # True (adresse réseau)
print("192.168.1.255" in reseau) # True (adresse broadcast)
Função reutilizável
import ipaddress
def is_ip_in_network(ip_string, network_string):
"""
Vérifie si une adresse IP appartient à un réseau.
Args:
ip_string (str): Adresse IP à vérifier (ex: "192.168.1.50")
network_string (str): Réseau CIDR (ex: "192.168.1.0/24")
Returns:
bool: True si l'IP est dans le réseau, False sinon
"""
try:
ip = ipaddress.ip_address(ip_string)
reseau = ipaddress.ip_network(network_string)
return ip in reseau
except ValueError as e:
print(f"Erreur : {e}")
return False
# Tests
print(is_ip_in_network("192.168.1.100", "192.168.1.0/24")) # True
print(is_ip_in_network("192.168.2.100", "192.168.1.0/24")) # False
print(is_ip_in_network("10.0.0.5", "10.0.0.0/8")) # True
3. Tratamento de Erros
A entrada do usuário pode ser inválida. É preciso capturar as exceções.
import ipaddress
def verifier_ip_securisee(ip_string, network_string):
"""Vérification robuste avec gestion d'erreur."""
try:
ip = ipaddress.ip_address(ip_string)
reseau = ipaddress.ip_network(network_string, strict=False)
return ip in reseau
except ValueError as e:
print(f"Entrée invalide : {e}")
return False
# Tests d'erreur
print(verifier_ip_securisee("999.999.999.999", "192.168.1.0/24")) # ValueError
print(verifier_ip_securisee("192.168.1.a", "192.168.1.0/24")) # ValueError
print(verifier_ip_securisee("192.168.1.100", "192.168.1.0/999")) # ValueError
print(verifier_ip_securisee("192.168.1.100", "invalid")) # ValueError
# Résultat : tous affichent un message d'erreur et retournent False
Parâmetro strict=False
Por padrão, ip_network exige que a rede esteja exatamente no limite do bloco CIDR. Com strict=False, o endereço de rede é recalculado automaticamente.
import ipaddress
# Strict (par défaut)
try:
# 192.168.1.100 n'est pas l'adresse réseau de /24
reseau = ipaddress.ip_network("192.168.1.100/24")
except ValueError as e:
print(f"Erreur (strict=True) : {e}")
# Erreur (strict=True) : 192.168.1.100/24 does not have the correct netmask
# Non-strict
reseau = ipaddress.ip_network("192.168.1.100/24", strict=False)
print(reseau) # 192.168.1.0/24 (corrigé automatiquement)
4. Comparação de Redes
O módulo oferece funções para comparar redes.
import ipaddress
reseau_grand = ipaddress.ip_network("10.0.0.0/8")
reseau_petit = ipaddress.ip_network("10.1.0.0/16")
# Vérifier si un réseau est contenu dans un autre
print(reseau_petit.subnet_of(reseau_grand)) # True
print(reseau_grand.supernet_of(reseau_petit)) # True
# Vérifier l'égalité
reseau_copy = ipaddress.ip_network("10.0.0.0/8")
print(reseau_grand == reseau_copy) # True
5. IPv6
O módulo também lida com IPv6. A sintaxe é idêntica.
import ipaddress
# IPv6
reseau_ipv6 = ipaddress.ip_network("2001:db8::/32")
print(reseau_ipv6) # 2001:db8::/32
# Tester l'appartenance
print("2001:db8::1" in reseau_ipv6) # True
print("2001:db9::1" in reseau_ipv6) # False
# Adresse link-local (spéciale)
ip_link_local = ipaddress.ip_address("fe80::1")
print(ip_link_local.is_link_local) # True
6. Casos de Uso Práticos
Lista de permissão para uma API
import ipaddress
from flask import Flask, request, abort
app = Flask(__name__)
# IPs autorisées (interne + partenaires)
ALLOWED_NETWORKS = [
ipaddress.ip_network("192.168.0.0/16"), # Réseau interne
ipaddress.ip_network("10.0.0.0/8"), # Réseau principal
ipaddress.ip_network("203.0.113.0/24"), # Partenaire A
]
def is_ip_authorized(ip_string):
"""Vérifie si une IP est autorisée."""
try:
ip = ipaddress.ip_address(ip_string)
return any(ip in network for network in ALLOWED_NETWORKS)
except ValueError:
return False
@app.before_request
def check_ip():
"""Middleware : bloquer les IPs non autorisées."""
client_ip = request.remote_addr
if not is_ip_authorized(client_ip):
abort(403) # Accès refusé
@app.route("/api/data")
def get_data():
return {"data": "Secret"}
# Résultat : seules les IPs dans ALLOWED_NETWORKS accèdent à l'API
Filtragem em um firewall de aplicação
import ipaddress
class SimpleFirewall:
def __init__(self):
self.blocked_networks = [
ipaddress.ip_network("203.0.113.0/24"), # Pays bloqué
ipaddress.ip_network("198.51.100.0/24"), # Spam connu
]
def is_blocked(self, ip_string):
"""Vérifie si une IP est bloquée."""
try:
ip = ipaddress.ip_address(ip_string)
return any(ip in network for network in self.blocked_networks)
except ValueError:
return False
def log_connection(self, ip_string, allowed):
status = "ALLOWED" if allowed else "BLOCKED"
print(f"{ip_string} : {status}")
firewall = SimpleFirewall()
test_ips = [
"192.168.1.1", # OK
"203.0.113.50", # Bloquée
"198.51.100.100", # Bloquée
]
for ip in test_ips:
allowed = not firewall.is_blocked(ip)
firewall.log_connection(ip, allowed)
7. Boas Práticas
- Capture
ValueError: a entrada de rede pode sempre ser inválida. - Use
strict=Falsequando você aceita entrada do usuário e quer ser tolerante. - Crie os objetos de rede uma única vez e reutilize-os (o custo em memória é baixo).
- Teste os casos extremos: endereço de rede, endereço de broadcast, endereços especiais (localhost, link-local etc.).
- Registre em log as rejeições para fins de auditoria e segurança.
Conclusão
O módulo ipaddress simplifica enormemente a verificação de pertinência de um IP a uma rede. Com o operador in, o parâmetro strict=False e um tratamento de erros robusto, você dispõe de todas as ferramentas necessárias para implementar listas de permissão, filtros de rede e políticas de acesso. Seja para proteger uma API, gerenciar um firewall de aplicação ou filtrar tráfego, essa habilidade é essencial para qualquer desenvolvedor Python que trabalhe com redes.
Sobre InSkillCoach
Especialista em treinamento e tecnologias
Coach especializado em tecnologias avançadas e IA, apoiado pela GNeurone Inc.
Certificações:
- AWS Certified Solutions Architect – Professional
- Certificações Google Cloud
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Comentários
Os comentários são alimentados pelo GitHub Discussions
Conecte-se com o GitHub para participar da discussão