ipaddress - Indirizzi Internet

Scopo: Classi per lavorare con indirizzi di Protocollo Internet (IP)

Il modulo ipaddress include classi per lavorare con indirizzi di rete IPv4 e IPv6. Le classi supportano validazione, la ricerca di host e indirizzi su una rete e altre comuni operazioni.

Indirizzi

L'oggetto più basico rappresenta l'indirizzo di rete stesso. Si passi una stringa, intero, o sequenza di byte a ip_address() per costruire un indirizzo. Il valore di ritorno sarà una istanza di IPv4Address o IPv6Address, a seconda del tipo di indirizzo usato.

# ipaddress_addresses.py

import binascii
import ipaddress


ADDRESSES = [
    '10.9.0.6',
    'fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa',
]

for ip in ADDRESSES:
    addr = ipaddress.ip_address(ip)
    print('{!r}'.format(addr))
    print('             versione IP:', addr.version)
    print('               è privato:', addr.is_private)
    print('  formato pacchettizzato:', binascii.hexlify(addr.packed))
    print('                  intero:', int(addr))
    print()

Entrambe le classi forniscono varie rappresentazioni dell'indirizzo per scopi diversi, così come basiche asserzioni tipo se l'indirizzo è riservato per comunicazioni multicast oppure se si tratta di una rete privata.

$ python3 ipaddress_addresses.py

IPv4Address('10.9.0.6')
             versione IP: 4
               è privato: True
  formato pacchettizzato: b'0a090006'
                  intero: 168361990

IPv6Address('fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa')
             versione IP: 6
               è privato: True
  formato pacchettizzato: b'fdfd87b5b4755e3eb1bce121a8eb14aa'
                  intero: 337611086560236126439725644408160982186

Reti

Una rete viene definita come un intervallo di indirizzi, generalmente espressi con un indirizzo base e una maschera che indica quali porzioni dell'indirizzo rappresentano la rete e quali porzioni rimangono per rappresentare gli indirizzi su quella rete. La maschera può essere espressa esplicitamente, oppure usando come prefisso un valore di lunghezza, come nell'esempio di seguito.

# ipaddress_networks.py

import ipaddress

NETWORKS = [
    '10.9.0.0/24',
    'fdfd:87b5:b475:5e3e::/64',
]

for n in NETWORKS:
    net = ipaddress.ip_network(n)
    print('{!r}'.format(net))
    print('          è privato:', net.is_private)
    print('          broadcast:', net.broadcast_address)
    print('          compresso:', net.compressed)
    print('   con maschera net:', net.with_netmask)
    print('  con maschera host:', net.with_hostmask)
    print('   numero indirizzi:', net.num_addresses)
    print()

Come per gli indirizzi, ci sono due classi rete per le reti IPv4 e IPv6. Ogni classe fornisce proprietà o metodi per accedere valori associati alla rete tipo l'indirizzo broadcast e gli indirizzi sulla rete disponibili per l'uso dagli host.

$ python3 ipaddress_networks.py

IPv4Network('10.9.0.0/24')
          è privato: True
          broadcast: 10.9.0.255
          compresso: 10.9.0.0/24
   con maschera net: 10.9.0.0/255.255.255.0
  con maschera host: 10.9.0.0/0.0.0.255
   numero indirizzi: 256

IPv6Network('fdfd:87b5:b475:5e3e::/64')
          è privato: True
          broadcast: fdfd:87b5:b475:5e3e:ffff:ffff:ffff:ffff
          compresso: fdfd:87b5:b475:5e3e::/64
   con maschera net: fdfd:87b5:b475:5e3e::/ffff:ffff:ffff:ffff::
  con maschera host: fdfd:87b5:b475:5e3e::/::ffff:ffff:ffff:ffff
   numero indirizzi: 18446744073709551616

Una istanza di rete è iterabile, e mantiene gli indirizzi sulla rete.

# ipaddress_network_iterate.py

import ipaddress

NETWORKS = [
    '10.9.0.0/24',
    'fdfd:87b5:b475:5e3e::/64',
]

for n in NETWORKS:
    net = ipaddress.ip_network(n)
    print('{!r}'.format(net))
    for i, ip in zip(range(3), net):
        print(ip)
    print()

Questo esempio stampa solo alcuni indirizzi, visto che una rete IPv6 può contenere molti più indirizzi di quanti ne possa contenere il risultato.

$ python3 ipaddress_network_iterate.py

IPv4Network('10.9.0.0/24')
10.9.0.0
10.9.0.1
10.9.0.2

IPv6Network('fdfd:87b5:b475:5e3e::/64')
fdfd:87b5:b475:5e3e::
fdfd:87b5:b475:5e3e::1
fdfd:87b5:b475:5e3e::2

L'iterazione sulla rete estrae gli indirizzi, ma non tutti sono validi per gli host. Ad esempio sono inclusi sia l'indirizzo base di una rete che quello di broadcast. Per trovare gli indirizzi che possono essere usati da normali host sulla rete, si usi il metodo hosts(), che produce un generatore.

# ipaddress_network_iterate_hosts.py

import ipaddress

NETWORKS = [
    '10.9.0.0/24',
    'fdfd:87b5:b475:5e3e::/64',
]

for n in NETWORKS:
    net = ipaddress.ip_network(n)
    print('{!r}'.format(net))
    for i, ip in zip(range(3), net.hosts()):
        print(ip)
    print()

Confrontando il risultato di questo esempio con quello precedente si nota che gli indirizzi host non includono i primi valori prodotti quando si itera sull'intera rete.

$ python3 ipaddress_network_iterate_hosts.py

IPv4Network('10.9.0.0/24')
10.9.0.1
10.9.0.2
10.9.0.3

IPv6Network('fdfd:87b5:b475:5e3e::/64')
fdfd:87b5:b475:5e3e::1
fdfd:87b5:b475:5e3e::2
fdfd:87b5:b475:5e3e::3

Oltre al protocollo di iterazione, viene supportato l'operatore in per determinare su un indirizzo faccia parte di una rete.

# ipaddress_network_membership.py

import ipaddress


NETWORKS = [
    ipaddress.ip_network('10.9.0.0/24'),
    ipaddress.ip_network('fdfd:87b5:b475:5e3e::/64'),
]

ADDRESSES = [
    ipaddress.ip_address('10.9.0.6'),
    ipaddress.ip_address('10.7.0.31'),
    ipaddress.ip_address(
        'fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa'
    ),
    ipaddress.ip_address('fe80::3840:c439:b25e:63b0'),
]


for ip in ADDRESSES:
    for net in NETWORKS:
        if ip in net:
            print('{}\nè su {}'.format(ip, net))
            break
    else:
        print('{}\nnon è un su una rete conosciuta'.format(ip))
    print()

L'implementazione di in usa la maschera di rete per verificare l'indirizzo, quindi è molto più efficiente rispetto all'espansione della lista completa degli indirizzi sulla rete.

$ python3 ipaddress_network_membership.py

10.9.0.6
è su 10.9.0.0/24

10.7.0.31
non è un su una rete conosciuta

fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa
è su fdfd:87b5:b475:5e3e::/64

fe80::3840:c439:b25e:63b0
non è un su una rete conosciuta

Interfacce

Una interfaccia di rete rappresenta un indirizzo specifico su di una rete e può essere rappresentato da un indirizzo host e da un prefisso di rete o maschera di rete.

# ipaddress_interfaces.py

import ipaddress


ADDRESSES = [
    '10.9.0.6/24',
    'fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa/64',
]


for ip in ADDRESSES:
    iface = ipaddress.ip_interface(ip)
    print('{!r}'.format(iface))
    print('rete:\n  ', iface.network)
    print('ip:\n  ', iface.ip)
    print('IP con prefisso di lunghezza:\n  ', iface.with_prefixlen)
    print('maschera di rete:\n  ', iface.with_netmask)
    print('maschera host:\n  ', iface.with_hostmask)
    print()

L'oggetto interfaccia ha proprietà per accedere all'intera rete e agli indirizzi separatamente, così come ha diversi modi per esprimere l'interfaccia e la maschera di rete.

$ python3 ipaddress_interfaces.py

IPv4Interface('10.9.0.6/24')
rete:
   10.9.0.0/24
ip:
   10.9.0.6
IP con prefisso di lunghezza:
   10.9.0.6/24
maschera di rete:
   10.9.0.6/255.255.255.0
maschera host:
   10.9.0.6/0.0.0.255

IPv6Interface('fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa/64')
rete:
   fdfd:87b5:b475:5e3e::/64
ip:
   fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa
IP con prefisso di lunghezza:
   fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa/64
maschera di rete:
   fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa/ffff:ffff:ffff:ffff::
maschera host:
   fdfd:87b5:b475:5e3e:b1bc:e121:a8eb:14aa/::ffff:ffff:ffff:ffff

Vedere anche:

ipaddresses
La documentazione della libreria standard per questo modulo.
PEP 3144
Libreria per la manipolazione di inidirizzi IP per la libreria standard Python
An introduction to the ipaddress module
Introduzione al modulo ipaddress
Wikipedia: Indirizzi IP
Introduzione agli indirizzi IP e alle reti.
Computer Networks (5th Edition)
Di Andrew S. Tanenbaum e David J. Wetherall. Pubblicato da Pearson, 2010. ISBN-10: 0132126958
Indice articolo: