Сетевая маска для CIDR в рубине - PullRequest
10 голосов
/ 01 декабря 2009

Я использовал гем ip-address, и он, похоже, не способен конвертировать из маски сети вида

255.255.255.0 

в форму CIDR

/24

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

Ответы [ 7 ]

13 голосов
/ 01 декабря 2009

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

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

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

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

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"
10 голосов
/ 07 июня 2011

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

Вот простой способ преобразования из 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"
5 голосов
/ 26 октября 2012

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

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

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

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

.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"
5 голосов
/ 30 мая 2012

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

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

с маской, представляющей собой строку типа 255.255.255.0. Вы можете изменить его и изменить первый аргумент на «маску», если «маска» уже является целочисленным представлением 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 возвращает число с плавающей запятой.

2 голосов
/ 25 октября 2011

Если вам не нужно использовать гем ip-адреса, вы можете сделать это с помощью 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" 
1 голос
/ 20 октября 2015
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 , на мой взгляд.

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

  1. Получить переменную экземпляра @ mask_addr , которая представляет маску сети
  2. Получить его двоичное представление, например 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. Подсчитайте 1-е число в base-2, чтобы получить маску CIDR (24)
  4. Составьте строку, состоящую из адреса и маски

РЕДАКТИРОВАТЬ: Добавлено пояснение к реализации в соответствии с просьбой NathanOliver

0 голосов
/ 02 ноября 2018

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

(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
...