O módulo ipaddress no Python cria, valida e manipula endereços IPv4, IPv6, redes CIDR e interfaces. Ele permite verificar se um IP pertence a uma sub-rede, calcular broadcast, dividir blocos, resumir faixas, identificar endereços privados e converter representações textuais, inteiras e binárias.
A biblioteca não abre sockets, consulta DNS nem altera a configuração da máquina. Seu papel é trabalhar com valores e regras de endereçamento. Essa separação é útil em firewalls, listas de permissão, inventários, logs, APIs e validadores de configuração.
Crie um endereço automaticamente
ip_address() escolhe IPv4 ou IPv6 conforme a entrada:
from ipaddress import ip_address
ipv4 = ip_address("192.0.2.10")
ipv6 = ip_address("2001:db8::10")
print(ipv4.version)
print(ipv6.compressed)Uma entrada inválida gera ValueError. Quando você sabe qual versão espera e precisa de uma mensagem mais específica, use IPv4Address ou IPv6Address diretamente.
Valide entrada de usuário
import ipaddress
def validar_ip(texto: str):
try:
return ipaddress.ip_address(texto.strip())
except ValueError as erro:
raise ValueError("endereço IP inválido") from erroIPv4 com zeros à esquerda, como 010.0.0.1, é rejeitado para evitar ambiguidade com notação octal. Não tente “corrigir” automaticamente entradas suspeitas, pois isso pode transformar um valor rejeitado em outro endereço.
Endereço, rede e interface
Os três conceitos são diferentes:
ip_address("10.0.0.5")representa um endereço.ip_network("10.0.0.0/24")representa uma faixa.ip_interface("10.0.0.5/24")preserva o host e informa a rede associada.
from ipaddress import ip_interface
interface = ip_interface("10.0.0.5/24")
print(interface.ip)
print(interface.network)
print(interface.with_netmask)strict em redes
Por padrão, ip_network() exige que os bits de host estejam zerados:
from ipaddress import ip_network
rede = ip_network("192.168.1.0/24")
# Normaliza 192.168.1.42 para 192.168.1.0/24
normalizada = ip_network("192.168.1.42/24", strict=False)Use strict=False somente quando a normalização for desejada e documentada. Em regras de segurança, aceitar silenciosamente um endereço com bits de host pode esconder erro de configuração.
Verifique se um IP pertence à rede
from ipaddress import ip_address, ip_network
rede = ip_network("10.20.0.0/16")
cliente = ip_address("10.20.8.15")
if cliente in rede:
print("endereço permitido")Objetos IPv4 só podem ser comparados com redes IPv4, e o mesmo vale para IPv6. Misturar versões normalmente gera TypeError. Faça a validação antes de aplicar regras.
Propriedades importantes
from ipaddress import ip_address
ip = ip_address("127.0.0.1")
print(ip.is_loopback)
print(ip.is_private)
print(ip.is_global)
print(ip.is_multicast)
print(ip.is_link_local)
print(ip.reverse_pointer)reverse_pointer produz o nome usado em uma consulta PTR; ele não consulta o DNS. As classificações is_private e is_global acompanham registros especiais da IANA e podem mudar entre versões do Python. No Python 3.13 houve correções em várias faixas. Não copie listas antigas para substituir a biblioteca.
Privado não significa confiável
Um endereço privado, loopback ou link-local não deve ser usado sozinho como prova de identidade. Em aplicações web, cabeçalhos como X-Forwarded-For podem ser forjados quando o proxy não é controlado. Valide a cadeia de proxies e obtenha o endereço efetivo a partir de uma fonte confiável.
Também não trate is_global como garantia de segurança. Ele descreve alcance de endereçamento, não reputação, propriedade ou autorização.
Rede, broadcast e quantidade
from ipaddress import ip_network
rede = ip_network("192.0.2.0/29")
print(rede.network_address)
print(rede.broadcast_address)
print(rede.netmask)
print(rede.hostmask)
print(rede.num_addresses)
print(list(rede.hosts()))Em IPv4, hosts() normalmente exclui rede e broadcast. Blocos /31 incluem os dois endereços, conforme uso em links ponto a ponto. Um /32 possui um único host. Em IPv6, as regras são diferentes; não aplique suposições de broadcast IPv4.
Não materialize redes enormes
Iterar um IPv6 /64 significaria percorrer uma quantidade impraticável de endereços. Use propriedades, testes de pertencimento e operações de sub-rede, sem converter tudo para lista.
from ipaddress import ip_network
rede = ip_network("2001:db8::/64")
print(rede.num_addresses)
print(rede[0])
print(rede[-1])Divida uma rede
from ipaddress import ip_network
rede = ip_network("10.0.0.0/24")
for subrede in rede.subnets(new_prefix=26):
print(subrede)new_prefix precisa ser maior que o prefixo atual. Para obter um bloco maior que contém a rede, use supernet().
Compare redes
from ipaddress import ip_network
principal = ip_network("10.0.0.0/8")
filial = ip_network("10.20.0.0/16")
terceira = ip_network("10.20.128.0/17")
print(filial.subnet_of(principal))
print(principal.supernet_of(terceira))
print(filial.overlaps(terceira))Essas operações ajudam a detectar regras redundantes, conflitos de rotas e sobreposição de faixas em inventários.
Remova uma faixa de outra
from ipaddress import ip_network
bloco = ip_network("192.0.2.0/28")
reservado = ip_network("192.0.2.4/30")
for restante in bloco.address_exclude(reservado):
print(restante)A rede removida deve estar completamente contida no bloco original. O resultado é um iterador de redes CIDR que cobre os endereços restantes.
Resuma e colapse redes
import ipaddress
inicio = ipaddress.ip_address("192.0.2.0")
fim = ipaddress.ip_address("192.0.2.130")
print(list(ipaddress.summarize_address_range(inicio, fim)))
redes = [
ipaddress.ip_network("10.0.0.0/25"),
ipaddress.ip_network("10.0.0.128/25"),
]
print(list(ipaddress.collapse_addresses(redes)))collapse_addresses() junta blocos adjacentes ou redundantes. Não misture IPv4 e IPv6 no mesmo conjunto.
Conversão para inteiro e bytes
from ipaddress import ip_address
ip = ip_address("192.0.2.1")
print(int(ip))
print(ip.packed)
print(str(ip))packed devolve quatro bytes para IPv4 e dezesseis para IPv6, em ordem de rede. Para construir cabeçalhos binários, combine com struct no Python. Defina sempre versão e comprimento do campo.
IPv6 compactado, expandido e escopo
from ipaddress import IPv6Address
ip = IPv6Address("2001:db8::1")
print(ip.compressed)
print(ip.exploded)
local = IPv6Address("fe80::1234%eth0")
print(local.scope_id)Endereços link-local podem incluir um zone ID. Dois endereços iguais com escopos diferentes não são considerados iguais. Ao converter para inteiro, o escopo não é preservado; não use essa conversão quando a interface fizer parte da identidade.
IPv4 mapeado em IPv6
ipv4_mapped identifica endereços como ::ffff:192.0.2.1. No Python recente, propriedades como is_private e is_global seguem o IPv4 subjacente. Normalize com cuidado para evitar que uma política trate representações equivalentes de maneira diferente.
Listas de permissão
from ipaddress import ip_address, ip_network
PERMITIDAS = tuple(map(ip_network, [
"192.0.2.0/24",
"2001:db8:abcd::/48",
]))
def permitido(texto: str) -> bool:
endereco = ip_address(texto)
return any(
endereco.version == rede.version and endereco in rede
for rede in PERMITIDAS
)Carregue redes validadas durante a inicialização, não a cada requisição. O guia de configparser no Python mostra como ler configurações, mas segredos e regras críticas devem ter validação adicional e revisão.
Evite SSRF com mais de uma camada
ipaddress ajuda a bloquear loopback, link-local e faixas privadas, mas não resolve sozinho ataques SSRF. Um hostname pode mudar entre resolução e conexão, retornar vários IPs ou redirecionar para outro destino. Resolva, valide todos os resultados, conecte ao endereço validado e revalide redirecionamentos. Para decompor URLs corretamente, combine com o módulo urllib.parse, sem confiar em concatenação de strings.
Ordenação e hashing
Endereços e redes são imutáveis e hashable, podendo ser chaves de dicionário e elementos de conjuntos. Endereços da mesma versão são ordenáveis. Para ordenar uma mistura de endereços e redes, use get_mixed_type_key() conscientemente.
Erros e observabilidade
Não exponha mensagens técnicas completas ao usuário. Registre o valor de forma sanitizada, a regra aplicada e a versão IP. Para investigar fluxos de validação, use trace no Python. Em pipelines concorrentes de grandes listas, distribua tarefas com queue no Python, mas mantenha as redes pré-compiladas.
Testes recomendados
Inclua IPv4 e IPv6 válidos, zeros à esquerda, prefixos inválidos, bits de host com modo estrito, /31, /32, /127, /128, IPv4 mapeado, zone IDs, redes sobrepostas e listas muito grandes. Teste ainda entradas com espaços, Unicode confusável e strings maiores que o esperado.
Boas práticas
- Converta strings em objetos uma única vez.
- Use modo estrito em regras críticas.
- Não materialize redes enormes.
- Não trate endereço privado como identidade.
- Valide IPv4 e IPv6 explicitamente.
- Normalize representações antes de comparar.
- Use limites para listas e intervalos.
- Combine validação IP com DNS, proxy e política de aplicação.
Conclusão
O ipaddress no Python oferece uma base sólida para validar endereços, calcular redes e implementar políticas consistentes em IPv4 e IPv6. Os objetos imutáveis evitam muitas manipulações frágeis de strings e tornam operações CIDR claras.
Consulte a documentação oficial do ipaddress e os registros especiais da IANA. Classificações de alcance ajudam na política, mas autorização exige contexto adicional.







