2009-12-01 15 views
7

He estado usando la gema dirección IP y no parece tener la capacidad de convertir de una máscara de red de la formamáscara de red a CIDR en rubí

255.255.255.0 

en la forma CIDR

/24 

¿Alguien tiene alguna idea de cómo convertir rápidamente la primera a la última?

+0

Una solución es probablemente usar la gema ipadmin lugar que se parece mucho más completo. Todavía estoy interesado en ver qué solución hay para esto desde la perspectiva del código. –

Respuesta

11

Aquí es la manera rápida y sucia

require 'ipaddr' 
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1") 

Debe haber un funcionamiento correcto para eso, no pude encontrar que, por lo que sólo cuente "1"

Si vas a se utiliza la función en una serie de lugares y no les importa monkeypatching, esto podría ayudar:

IPAddr.class_eval 
    def to_cidr 
    "/" + self.to_i.to_s(2).count("1") 
    end 
end 

Entonces usted consigue

IPAddr.new('255.255.255.0').to_cidr 
# => "/24" 
+0

No estoy seguro de que haya algo más apropiado que usar el recuento ("1"). Tal vez algo como esto? '32 - (2 ** 32 - 1 - IPAddr.new (" 255.255.255.0 "). To_i) .to_s (2).length' –

+0

En C, probablemente cambie a la derecha y pruebe con & 1 hasta su alcance 1, por ejemplo, 'bits = 32; unsigned int ipaddr = 0xFFFFFF00; while (ipaddr & 1 == 0) {ipaddr = ipaddr> > 1; bits -;} 'para el caso anterior, solo necesito cambiar a la derecha 8 veces, creo. – YOU

9

Así como un FYI, y para mantener la información de fácil acceso para aquellos que están buscando ...

Aquí está una manera fácil de convertir de CIDR a netmask formato:

def cidr_to_netmask(cidr) 
    IPAddr.new('255.255.255.255').mask(cidr).to_s 
end 

Por ejemplo :

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" 
2

Si no necesita utilizar la gema dirección IP, se puede hacer esto con la joya netaddr

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" 
4

Aquí es un enfoque más matemático, evitando a toda costa cuerdas:

def cidr_mask 
    Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1)) 
end 

con "máscara" ser una cadena como 255.255.255.0. Puede modificarlo y cambiar el primer argumento para simplemente "máscara" si "máscara" ya es una representación entera de una dirección IP.

Así por ejemplo, si la máscara era "255.255.255.0", IPAddr.new (máscara, Socket :: AF_INET) .to_i se convertiría en 0xffffff00, que luego se XOR con 0xffffffff, lo que equivale a 255.

Agregamos 1 a eso para que sea un rango completo de 256 hosts, luego buscamos la base de registro 2 de 256, que es igual a 8 (los bits usados ​​para la dirección de host), luego restamos 8 de 32, que es igual a 24 (el bits utilizados para la dirección de red).

Emitimos en enteros porque Math.log2 devuelve un flotante.

4

rápida y sucia conversión:

"255.255.255.0".split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").split(".")

=> I dividió máscara en una matriz

.map { |e| e.to_i.to_s(2).rjust(8, "0") }

=> Para cada elemento en Array:

.to_i

=> Convertir en número entero

.to_s(2)

=> Convertir entero en binario

.rjust(8, "0")

=> Añadir el relleno

=> Mapa devolver una matriz con el mismo cardinalidad

.join

=> Convertir matriz en una cadena completa

.count("1")

=> Count "1" caracteres => Dar CIDR mask

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" 
1
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" 

El código logra el enmascaramiento accediendo privada variable de instancia * @ mask_addr) de la instancia IPAddr (dirección, pasada a serialize_ipaddr). Este no es el camino recomendado (como las variables de instancia no son parte de la API pública clases pero aquí es mejor que analizar la cadena de #inspect en mi opinión

lo tanto, el proceso es el siguiente:.

  1. obtener la instancia variable de @mask_addr que representa la máscara de red
  2. Obtener su representación binaria por ejemplo 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. contar el 1-s en el número de base-2 para obtener la máscara CIDR (24)
  4. componen una cadena formada por la dirección de la máscara &

EDIT: explicación añadida a la aplicación conforme a lo solicitado por NathanOliver

+0

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-coded-based-answers) realmente ayuda a mejorar la calidad de su enviar. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – NathanOliver

Cuestiones relacionadas