Вопрос

Я использовал драгоценный камень ip-адреса, и, похоже, у него нет возможности конвертировать из сетевой маски вида

255.255.255.0 

в форму CIDR

/24

У кого-нибудь есть идеи, как быстро преобразовать первое во второе?

Это было полезно?

Решение

Вот быстрый и грязный способ

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

Для этого должна быть соответствующая функция, я не смог ее найти, поэтому я просто считаю "1".

Если вы собираетесь использовать функцию в нескольких местах и не возражаете против monkeypatching, это может помочь:

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

Тогда вы получите

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

Другие советы

Просто для справки, чтобы информация была легко доступна для тех, кто ищет ...

Вот простой способ преобразования из CIDR в формат маски сети:

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

Например:

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"

Вот более математический подход, позволяющий избежать строк любой ценой:

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

с " маской " будучи строкой как 255.255.255.0. Вы можете изменить его и изменить первый аргумент на «quot; mask» " если " маска " уже является целочисленным представлением IP-адреса.

Так, например, если маска была " 255.255.255.0 " ;, IPAddr.new (mask, Socket :: AF_INET) .to_i стал бы 0xffffff00, который затем xor'd с 0xffffffff, что равно 255.

Мы добавляем 1 к этому, чтобы сделать его полным диапазоном из 256 хостов, затем находим лог-базу 2 из 256, что равно 8 (биты, используемые для адреса хоста), затем вычитаем это 8 из 32, что равно 24 (биты, используемые для сетевого адреса).

Затем мы приводим к целому числу, потому что Math.log2 возвращает число с плавающей точкой.

Быстрое и грязное преобразование:

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

=> Я разделяю маску на Массив

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

=> Для каждого элемента в массиве:

.to_i

=> Преобразовать в целое число

.to_s(2)

=> Преобразовать целое число в двоичное

.rjust(8, "0")

=> Добавить отступы

=> Map возвращает массив с такой же мощностью

.join

=> Преобразовать массив в полную строку

.count("1")

=> Количество символов "1" => Присвоить маску 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"

Если вам не нужно использовать гем ip-адреса, вы можете сделать это с помощью 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" 
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"

Код выполняет маскирование путем доступа к закрытой переменной экземпляра * @ mask_addr) экземпляра IPAddr (адрес, передаваемый в serialize_ipaddr). Это не рекомендуется (так как переменные экземпляра не являются частью открытого API классов, но здесь, на мой взгляд, это лучше, чем анализ строки из #inspect .

Итак, процесс выглядит следующим образом:

<Ол>
  • Получите переменную экземпляра @mask_addr , которая представляет маску сети
  • Получить его двоичное представление, например 255.255.255.0 - > 4294967040 - > 11111111111111111111111100000000
  • Подсчитайте 1-е число в числе base-2, чтобы получить маску CIDR (24)
  • Составьте строку, состоящую из адреса & amp; маска
  • РЕДАКТИРОВАТЬ: Добавлено пояснение к реализации, запрошенное NathanOliver

    Вот способ сделать это без драгоценного камня IPAddr

    (('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top