ipaddress no Python: redes IPv4 e IPv6

Publicado em: 18/08/2026
Tempo de leitura: 6 minutos
A person typing on a laptop with a Python programming book visible, capturing technology and learning.

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 erro

IPv4 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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    A vibrant collection of blue sewing threads arranged with hands on a white background.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    queue no Python: coordene threads

    Aprenda queue no Python para coordenar threads com FIFO, prioridade, backpressure, task_done, join, retries e shutdown seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    A male software engineer working on code in a modern office setting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    struct no Python: trabalhe com binário

    Aprenda struct no Python para empacotar dados binários, controlar endianness, usar buffers e validar protocolos e arquivos externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile no Python: crie TAR seguro

    Aprenda tarfile no Python para criar TAR comprimido, inspecionar membros e extrair com filtros, limites e proteção contra path traversal.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Row of colorful office binders neatly arranged on a shelf, ideal for organization concepts.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    gzip no Python: comprima arquivos .gz

    Aprenda gzip no Python para ler e gravar .gz, criar saídas reproduzíveis, trabalhar com streams e limitar a expansão de

    Ler mais

    Tempo de leitura: 4 minutos
    17/08/2026
    Color-coded office binders organized neatly in a storage shelf, featuring labels and a striking red binder.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    lzma no Python: comprima arquivos XZ

    Aprenda lzma no Python para criar arquivos XZ, usar streams, checks, filtros e limites de memória ao descompactar dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Exquisite python skin handbag with intricate snake emblem and elegant design.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    bz2 no Python: comprima com bzip2

    Aprenda bz2 no Python para comprimir arquivos e bytes, processar fluxos em blocos e limitar a expansão de dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    16/08/2026