Frage
Ich habe die IP-Adresse gem benutzen und es scheint nicht die Möglichkeit zu haben, von einer Netzmaske der Form zu konvertieren
255.255.255.0
in die CIDR Form
/24
Hat jemand eine Idee hat, wie man schnell die ersteren zum letzteren umwandeln?
Lösung
Hier ist die schnelle und schmutzige Art und Weise
require 'ipaddr'
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1")
Es sollte eine einwandfreie Funktion für das sein, konnte ich nicht feststellen, dass, so dass ich nur „1“ zähle
Wenn Sie vorhaben, die Funktion in einer Reihe von Orten zu verwenden und nicht monkeypatching nichts, das helfen könnte:
IPAddr.class_eval
def to_cidr
"/" + self.to_i.to_s(2).count("1")
end
end
Sie erhalten dann
IPAddr.new('255.255.255.0').to_cidr
# => "/24"
Andere Tipps
So wie ein FYI, und die Informationen zu halten, leicht zugänglich für diejenigen, die suchen ...
Hier ist eine einfache Möglichkeit, von CIDR-Format zu konvertieren Netmask:
def cidr_to_netmask(cidr)
IPAddr.new('255.255.255.255').mask(cidr).to_s
end
Zum Beispiel:
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"
Hier ist ein mathematischer Ansatz, Streicher unter allen Umständen vermieden werden:
def cidr_mask
Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1))
end
mit „Maske“ ist eine Zeichenkette wie 255.255.255.0. Sie können es ändern, und das erste Argument ändern, um nur „Maske“, wenn „Maske“ ist schon eine ganze Zahl Darstellung einer IP-Adresse.
So zum Beispiel, wenn Maske "255.255.255.0" ist, IPAddr.new (Maske, Socket :: AF_INET) .to_i würde 0xffffff00 werden, die dann mit 0xffffffff XOR-verknüpft wird, die 255 gleich
Wir fügen 1, dass es ein umfassendes Angebot von 256 Hosts zu machen, dann die Log-Basis finden 2 von 256, die 8 (für die Host-Adresse verwendet, um die Bits) gleich, dann subtrahieren, dass 8 von 32, die 24 gleich (die Bits für die Netzwerkadresse verwendet wird).
Wir werfen dann integer, weil Math.log2 einen Schwimmer zurück.
Schnell und schmutzig Umwandlung:
"255.255.255.0".split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").split(".")
=> I gespalten Maske in einem Array
.map { |e| e.to_i.to_s(2).rjust(8, "0") }
=> Für jedes Element in Array:
.to_i
=> Konvertieren in integer
.to_s(2)
=> Konvertieren integer in binären
.rjust(8, "0")
=> Add padding
=> Karte ein Array mit der gleichen Mächtigkeit zurückkehren
.join
=> Konvertieren Array in eine vollständige Zeichenfolge
.count("1")
=> "1" Zeichen Count => Geben Sie CIDR Maske
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"
Wenn Sie nicht brauchen, um IP-Adresse gem zu verwenden, können Sie dies mit der netaddr gem
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"
Der Code löst die Maskierung von privaten Instanzvariablen Zugriff auf * @ mask_addr) von IPAddr Instanz (Adresse, in serialize_ipaddr bestanden). Dies wird nicht empfohlen Art und Weise (wie die Instanzvariablen nicht Teil der Klassen öffentlichen API sind aber hier ist es besser als das Parsen der Zeichenfolge #inspect in meiner Meinung nach.
So wird das Verfahren wie folgt:
- Holen Sie sich das Instanzvariable @mask_addr , die netmask steht
- Get seine binäre Darstellung z.B.
255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
- Zählen Sie die 1-s in der Basis-2 Nummer CIDR-Maske zu erhalten (24)
- Erstellen Sie eine Zeichenkette, die aus der Adresse und Maske bis
EDIT: Hinzugefügt Erklärung für die Umsetzung, wie durch NathanOliver angefordert
Hier ist ein Weg, um es ohne das IPAddr Juwel zu tun
(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')