Lavorare con indirizzi IP in Ruby

Lavorare con indirizzi IP (sia v4 che v6) in Ruby è molto semplice poiché dalla versione 1.8.0 è stata inclusa nella libreria standard la classe IPAddr che mette a disposizione un set di metodi per le operazioni più comuni. Possiamo creare un’istanza di questa classe specificando l’indirizzo in vari formati (in questo caso mi limiterò all’utilizzo di IPv4):

require'ipaddr' # 1- indirizzo in notazione decimale puntata IPAddr.new('192.168.1.1') # 2- Indirizzo espresso come numero IPAddr.new(3232235777, Socket::AF_INET) # 3- indirizzo + netmask in notazione decimale puntata IPAddr.new('192.168.1.1/255.255.255.255') # 4- indirizzo in notazione decimale puntata + CIDR IPAddr.new('192.168.1.1/32')

In tutti questi casi otteniamo quattro istanze di IPAddr uguali usando diversi formati per esprimere l’indirizzo IP. Nel primo caso abbiamo specificato l’indirizzo IP rappresentato nella comune notazione decimale puntata, nel secondo invece abbiamo utilizzato la forma interna di un indirizzo ovvero un numero (potete dare un’occhiata a questo vecchio articolo per ottenere maggiori informazioni e trovare qualche spunto nell’ambito dell’ottimizzazione di un database in cui memorizzare indirizzi IP) e infine nel terzo e quarto caso abbiamo accompagnato la notazione decimale puntata a due formati di espressione delle sottoreti differenti (netmask e CIDR) che limitano il range di indirizzamento allo stesso IP specificato (in pratica possiamo pensare a “192.168.1.1″ come forma ridotta per esprimere “192.168.1.1/255.255.255.255″ oppure “192.168.1.1/32″). Creiamo ora qualche istanza di IPAddr:

ip_a = IPAddr.new('192.168.1.1') #<IPAddr: IPv4:192.168.1.1/255.255.255.255> ip_b = IPAddr.new('192.168.1.2') #<IPAddr: IPv4:192.168.1.2/255.255.255.255> ip_c = IPAddr.new('192.168.1.1/32') #<IPAddr: IPv4:192.168.1.1/255.255.255.255> ip_a == ip_b # => false ip_a == ip_c # => true ip_b == ip_d # => false

Per le esigenze dettate da una lenta transizione da IPv4 a IPv6, quest’ultima versione supporta una facile trasformazione dei vecchi indirizzamenti in nuovi attraverso due tipologie differenti di formato: IPv4-mapped address e IPv4-compatible address. E’ quindi possibile tradurre un’istanza di IPAddr che rappresenta un indirizzo IPv4 in una che rappresenta un IPv6 valido e viceversa

address = IPAddr.new('192.168.1.1') #<IPAddr: IPv4:192.168.1.1/255.255.255.255> address.ipv4? # => true address.ipv6? # => false ipv6_mapped = address.ipv4_mapped # => ::ffff:192.168.1.1 ipv6_compat = address.ipv4_compat # => ::192.168.1.1 ipv6_mapped.ipv6? # => true ipv6_compat.ipv6? # => true ipv4 = ipv6_mapped.native # => 192.168.1.1

La possibilità di specificare una netmask per la creazione di un’istanza di IPAddr non è casuale perchè permette di rappresentare non soltanto un indirizzo IP singolo ma un intero range di indirizzi (ovvero una sottorete), inoltre è possibile applicare una maschera a un’istanza di IPAddr già esistente attraverso il metodo mask:

IPAddr.new('192.168.0.0').mask('255.255.254.0') #<IPAddr: IPv4:192.168.0.0/255.255.254.0> IPAddr.new('192.168.0.0').mask(23) #<IPAddr: IPv4:192.168.0.0/255.255.254.0> IPAddr.new('192.168.0.0/255.255.254.0') #<IPAddr: IPv4:192.168.0.0/255.255.254.0> IPAddr.new('192.168.0.0/23') #<IPAddr: IPv4:192.168.0.0/255.255.254.0>

Otteniamo quattro istanze che rappresentano una sottorete di 512 indirizzi che va da 192.168.0.0 a 192.168.1.255. Su un range di indirizzi possiamo effettuare alcune operazioni utili:

network = IPAddr.new('192.168.0.0/23') #<IPAddr: IPv4:192.168.0.0/255.255.254.0> # verifica se un indirizzo appartiene a una determinata sottorete network.include?(IPAddr.new('192.168.0.23')) # => true network.include?(IPAddr.new('192.168.1.1')) # => true network.include?(IPAddr.new('192.168.10.1')) # => false network.include?(IPAddr.new('172.16.100.2')) # => false # supporto per operazioni bitwise sugli indirizzi # bitwise AND permette di ottenere l'indirizzo di rete da un ip e una netmask IPAddr.new('192.168.1.1') & IPAddr.new('255.255.254.0') #<IPAddr: IPv4:192.168.0.0/255.255.254.0> # l'operazione bitwise OR permette di alzare i singoli bit di un indirizzo, # può essere utile per iterare tra gli host di una sottorete: network | 1 # 192.168.0.1 (#<IPAddr: IPv4:192.168.0.1/255.255.254.0>) network | 10 # 192.168.0.10 (#<IPAddr: IPv4:192.168.0.10/255.255.254.0>) network | 255 # 192.168.0.255 (#<IPAddr: IPv4:192.168.0.255/255.255.254.0>)

La classe IPAddr, oltre al normale utilizzo nelle classi e nei moduli che la sfruttano, può quindi tornare molto utile in ambito di script per l’amministrazione di rete.


Puoi scrivere un commento oppure inviare un trackback dal tuo sito.

3 commenti a “Lavorare con indirizzi IP in Ruby”

  1. bell’articoletto! aggiunto link dal wiki, spero non ti dispiaccia :)

  2. Non mi dispiace per niente, anzi…
    Grazie :)

  3. Esistono equivalenti di INET_ATON e INET_NTOA in Ruby?

    Prima di tutto, inet_aton e inet_ntoa sono due funzioni classiche delle librerie di rete (si possono trovare implementate con lo stesso nome in svariate librerie per diversi linguaggi) e permettono rispettivamente la conversione di un indirizzo IP da r…

Lascia un commento

Puoi utilizzare i seguenti tag XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>