Domanda
Sto usando la gemma dell'indirizzo IP e non sembra avere la possibilità di convertire da una maschera di rete del modulo
255.255.255.0
nel modulo CIDR
/24
Qualcuno ha idee su come convertire rapidamente il primo nel secondo?
Soluzione
Ecco il modo rapido e sporco
require 'ipaddr'
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1")
Dovrebbe esserci una funzione adeguata per questo, non sono riuscito a trovarlo, quindi conto solo " 1 "
Se utilizzerai la funzione in un certo numero di posti e non ti dispiace il monkeypatching, questo potrebbe aiutare:
IPAddr.class_eval
def to_cidr
"/" + self.to_i.to_s(2).count("1")
end
end
Quindi ottieni
IPAddr.new('255.255.255.0').to_cidr
# => "/24"
Altri suggerimenti
Proprio come una FYI e per mantenere le informazioni facilmente accessibili per coloro che stanno cercando ...
Ecco un modo semplice per convertire da CIDR in formato maschera di rete:
def cidr_to_netmask(cidr)
IPAddr.new('255.255.255.255').mask(cidr).to_s
end
Ad esempio:
cidr_to_netmask(24) #=> "255.255.255.0"
cidr_to_netmask(32) #=> "255.255.255.255"
cidr_to_netmask(16) #=> "255.255.0.0"
cidr_to_netmask(22) #=> "255.255.252.0"
Ecco un approccio più matematico, evitando le stringhe a tutti i costi:
def cidr_mask
Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1))
end
con " maschera " essendo una stringa come 255.255.255.0. Puoi modificarlo e cambiare il primo argomento in solo " mask " se "maschera" è già una rappresentazione intera di un indirizzo IP.
Quindi, ad esempio, se la maschera fosse " 255.255.255.0 " ;, IPAddr.new (maschera, socket :: AF_INET) .to_i diventerebbe 0xffffff00, che viene quindi xor'd con 0xffffffff, che equivale a 255.
Aggiungiamo 1 a quello per renderlo un intervallo completo di 256 host, quindi troviamo la base di registro 2 di 256, che è uguale a 8 (i bit utilizzati per l'indirizzo host), quindi sottraggiamo quell'8 da 32, che equivale a 24 (i bit utilizzati per l'indirizzo di rete).
Quindi eseguiamo il cast su intero perché Math.log2 restituisce un float.
Conversione rapida e sporca:
" 255.255.255.0 " .split (". "). map {| e | e.to_i.to_s (2) .rjust (8, " 0 ")} .join.count (" 1 "). split (". ")
= > Ho diviso la maschera in un array
.map {| e | e.to_i.to_s (2) .rjust (8, " 0 ")}
= > Per ogni elemento nell'array:
.to_i
= > Converti in intero
.to_s (2)
= > Converti intero in binario
.rjust (8, " 0 ")
= > Aggiungi imbottitura
= > La mappa restituisce un array con la stessa cardinalità
.join
= > Converti array in una stringa completa
.count (" 1 ")
= > Conta " 1 " caratteri = > Dai maschera CIDR
def mask_2_ciddr mask
"/" + mask.split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").to_s
end
mask_2_ciddr "255.255.255.0"
=> "/24"
mask_2_ciddr "255.255.255.128"
=> "/25"
Se non è necessario utilizzare la gemma dell'indirizzo IP, è possibile farlo con netaddr gemma
require 'netaddr'
def to_cidr_mask(dotted_mask)
NetAddr::CIDR.create('0.0.0.0/'+dotted_mask).netmask
end
to_cidr_mask("255.224.0.0") # => "/11"
require 'ipaddr'
def serialize_ipaddr(address)
mask = address.instance_variable_get(:@mask_addr).to_s(2).count('1')
"#{address}/#{mask}"
end
serialize_ipaddr(IPAddr.new('192.168.0.1/24')) # => "192.168.0.0/24"
Il codice ottiene il mascheramento accedendo alla variabile di istanza privata * @ mask_addr) dell'istanza di IPAddr (indirizzo, passato in serialize_ipaddr). Questo non è un metodo raccomandato (poiché le variabili di istanza non fanno parte dell'API pubblica delle classi ma qui è meglio che analizzare la stringa da #inspect a mio avviso.
Quindi il processo è il seguente:
- Ottieni la variabile di istanza @mask_addr che rappresenta la maschera di rete
- Ottieni la sua rappresentazione binaria, ad es.
255.255.255.0 - > 4294967040 - > 11111111111111111111111100000000
- Contare gli 1-s nel numero base-2 per ottenere la maschera CIDR (24)
- Crea una stringa composta dall'indirizzo & amp; mascherare
EDIT: aggiunta spiegazione all'implementazione come richiesto da NathanOliver
Ecco un modo per farlo senza la gemma IPAddr
(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')