Module: Chalk::IP

Defined in:
lib/chalk-ip.rb,
lib/chalk-ip/version.rb

Constant Summary collapse

VERSION =
'0.0.1'

Class Method Summary collapse

Class Method Details

.addr_to_cidr_bits(addr) ⇒ Object

Given IPAddr, return the CIDR netmask bits.

There doesn’t seem to be any native way to do this in Rubby.

Parameters:

  • addr (IPAddr)

Returns:

  • Fixnum



60
61
62
63
64
# File 'lib/chalk-ip.rb', line 60

def self.addr_to_cidr_bits(addr)
  mask = IPAddr.new(addr.instance_variable_get(:@mask_addr), addr.family)

  netmask_to_cidr_bits(mask)
end

.addr_to_s_cidr(addr) ⇒ Object

Given an IP address, return it as a string in CIDR notation.

I really can’t believe there’s no way to do this natively. Rubby.

Parameters:

  • addr (IPAddr, String)

Returns:

  • String



74
75
76
77
78
79
80
81
82
# File 'lib/chalk-ip.rb', line 74

def self.addr_to_s_cidr(addr)
  if addr.is_a?(IPAddr)
    addr_obj = addr
  else
    addr_obj = IPAddr.new(addr)
  end

  "#{addr_obj}/#{addr_to_cidr_bits(addr_obj)}"
end

.cidr_block_covering(addresses) ⇒ IPAddr

Given an enumerable of addresses, find the smallest CIDR block that will cover those addresses.

Parameters:

  • addresses (Enumerable<IPAddr>)

Returns:

  • (IPAddr)

    A network range covering the addresses.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/chalk-ip.rb', line 91

def self.cidr_block_covering(addresses)
  # start with the first address as our range
  net = addresses.find { true }
  if net.nil?
    raise ArgumentError.new('addresses cannot be empty')
  end

  addresses.each do |addr|
    # make sure we don't mix IPv4 and IPv6 addresses
    if net.family != addr.family
      raise ArgumentError.new('Cannot mix addresses of differing family')
    end

    # expand net until it includes addr
    until net.include?(addr)
      mask_bits = addr_to_cidr_bits(net)
      net = IPAddr.new("#{net.to_string}/#{mask_bits - 1}")
    end
  end

  net
end

.netmask_to_cidr_bits(addr) ⇒ Object

Given netmask, return the number of leading 1 bits (appropriate for use with CIDR notation).

I can’t believe this isn’t built in to the IPAddr class, but whatever.

Examples:


>> netmask_to_cidr_bits('255.255.0.0')
=> 16

>> mask = IPAddr.new('255.255.255.255/8')
=> #<IPAddr: IPv4:255.0.0.0/255.0.0.0>
>> netmask_to_cidr_bits(mask)
=> 8

>> netmask_to_cidr_bits('ffff:ffff:ffff:ffff::')
=> 64

>> netmask_to_cidr_bits('ffff::')
=> 16

Parameters:

  • addr (String, IPAddr)

Returns:

  • Fixnum



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/chalk-ip.rb', line 29

def self.netmask_to_cidr_bits(addr)
  case addr
  when IPAddr
    addr_obj = addr
  when String
    addr_obj = IPAddr.new(addr)
  else
    raise ArgumentError.new("Unexpected address: #{addr.inspect}")
  end

  if addr_obj.ipv4?
    total = 32
    xor = IPAddr::IN4MASK
  elsif addr_obj.ipv6?
    total = 128
    xor = IPAddr::IN6MASK
  else
    raise "#{addr_obj.inspect} is neither IPv4 nor IPv6??"
  end

  Integer(total - Math.log2((addr_obj.to_i ^ xor) + 1))
end