Pregunta

He estado usando la gema de la dirección IP y no parece tener la capacidad de convertir desde una máscara de red del formulario

255.255.255.0 

en el formulario CIDR

/24

¿Alguien tiene una idea de cómo convertir rápidamente la primera a la segunda?

¿Fue útil?

Solución

Aquí está la manera rápida y sucia

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

Debería haber una función adecuada para eso, no pude encontrar eso, así que solo cuento " 1 "

Si va a utilizar la función en varios lugares y no le importa el parche de mono, esto podría ayudar:

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

Entonces obtienes

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

Otros consejos

Al igual que para su información, y para mantener la información fácilmente accesible para aquellos que están buscando ...

Aquí hay una manera simple de convertir de CIDR a formato de máscara de red:

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"

Aquí hay un enfoque más matemático, evitando cadenas a toda costa:

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

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

Entonces, por ejemplo, si la máscara fuera " 255.255.255.0 " ;, IPAddr.new (mask, Socket :: AF_INET) .to_i se convertiría en 0xffffff00, que luego se modifica con 0xffffffff, que es igual a 255.

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

Luego lo convertimos a entero porque Math.log2 devuelve un flotante.

Conversión rápida y sucia:

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

= > Partí la máscara en una matriz

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

= > Para cada elemento en la matriz:

.to_i

= > Convierte en entero

.to_s(2)

= > Convertir entero en binario

.rjust (8, " 0 ")

= > Añadir relleno

= > El mapa devuelve una matriz con la misma cardinalidad

.join

= > Convertir matriz en una cadena completa

.count("1")

= > Contar " 1 " caracteres = > Dar máscara 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"

Si no necesita usar la gema de la dirección IP, puede hacerlo con el netaddr gema

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"

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

Entonces el proceso es el siguiente:

  1. Obtenga la variable de instancia @mask_addr que representa netmask
  2. Obtenga su representación binaria, p. 255.255.255.0 - > 4294967040 - > 11111111111111111111111100000000
  3. Cuente los 1-s en el número base-2 para obtener la máscara CIDR (24)
  4. Crea una cadena que consiste en la dirección & amp; máscara

EDITAR: Se agregó una explicación a la implementación según lo solicitado por NathanOliver

Aquí hay una manera de hacerlo sin la gema IPAddr

(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top