Pergunta

Eu estive usando o gem ip-address e não parecem ter a capacidade de converter a partir de uma máscara de rede da forma

255.255.255.0 

no formulário CIDR

/24

Alguém tem uma idéia de como converter rapidamente a primeira para a segunda?

Foi útil?

Solução

Aqui é a maneira rápida e suja

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

Deve haver a função apropriada para isso, eu não poderia encontrar isso, então eu apenas contar "1"

Se você está indo estar usando a função em um número de lugares e não se importa monkeypatching, isso poderia ajudar:

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

Então você começa

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

Outras dicas

Assim como um FYI, e para manter a informação facilmente acessível para aqueles que estão à procura ...

Aqui está uma maneira simples para converter CIDR para o formato de máscara de rede:

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

Por exemplo:

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"

Aqui está uma fórmula matemática, evitando cordas em todos os custos:

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

com "máscara" ser uma string como 255.255.255.0. Você pode modificá-lo e alterar o primeiro argumento para apenas "máscara" se "máscara" já é uma representação inteira de um endereço IP.

Assim, por exemplo, se a máscara era "255.255.255.0", IPAddr.new (máscara, soquete :: AF_INET) .to_i se tornaria 0xffffff00, que é então XOR com 0xffffffff, o que equivale a 255.

Nós adicionamos 1 a isso para torná-lo uma gama completa de 256 hosts, em seguida, encontrar a base de log 2 de 256, o que equivale a 8 (os bits usados ??para o endereço de host), em seguida, subtrair que 8 de 32, o que equivale a 24 (os bits utilizado para o endereço de rede).

Em seguida, convertido para inteiro, porque Math.log2 retorna um float.

conversão rápida e suja:

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

=> I máscara dividida em um Array

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

=> Para cada elemento na matriz:

.to_i

=> converter em número inteiro

.to_s(2)

=> Convert inteiro em binário

.rjust(8, "0")

=> adicionar preenchimento

=> Mapa retornar um array com a mesma cardinalidade

.join

=> Convert matriz em uma seqüência completa

.count("1")

=> Contagem "1" caracteres => máscara Dar 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 você não precisa usar gem endereço IP, você pode fazer isso com a 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"

O código atinge o mascaramento acessando variável de instância privada * @ mask_addr) da instância IPAddr (endereço, passou para serialize_ipaddr). Isso não é recomendado maneira (como as variáveis ??de instância não são parte das classes API pública, mas aqui é melhor do que analisar a seqüência de #inspect na minha opinião.

Assim, o processo é o seguinte:

  1. Obter a variável de instância @mask_addr que representa a máscara de rede
  2. Obter sua representação binária por exemplo 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. Contar o 1-S no número base-2 para obter máscara CIDR (24)
  4. Faça um string que consiste o endereço e máscara

EDIT: Adicionado explicação para a implementação, conforme solicitado pela NathanOliver

Aqui está uma maneira de fazê-lo sem a gema IPAddr

(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top