Class: Philiprehberger::IpAddr::Range

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/philiprehberger/ip_addr.rb

Overview

CIDR range wrapper

Instance Method Summary collapse

Constructor Details

#initialize(cidr) ⇒ Range

Returns a new instance of Range.

Parameters:

  • cidr (String)

    CIDR notation string



139
140
141
142
143
144
# File 'lib/philiprehberger/ip_addr.rb', line 139

def initialize(cidr)
  @cidr = cidr.to_s.strip
  @network = ::IPAddr.new(@cidr)
rescue ::IPAddr::InvalidAddressError => e
  raise Error, "Invalid CIDR range: #{e.message}"
end

Instance Method Details

#broadcastAddress

Returns broadcast address (last address in the block).

Returns:

  • (Address)

    broadcast address (last address in the block)



161
162
163
# File 'lib/philiprehberger/ip_addr.rb', line 161

def broadcast
  Address.new(@network.to_range.last.to_s)
end

#each {|Address| ... } ⇒ Enumerator

Iterate over all addresses in the range

Yields:

  • (Address)

    each address in the range

Returns:

  • (Enumerator)

    if no block given



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/philiprehberger/ip_addr.rb', line 200

def each(&block)
  return enum_for(:each) unless block

  start_int = @network.to_range.first.to_i
  end_int = @network.to_range.last.to_i

  (start_int..end_int).each do |int|
    addr = @network.ipv4? ? int_to_v4(int) : int_to_v6(int)
    block.call(Address.new(addr))
  end
end

#include?(ip) ⇒ Boolean

Returns true if the range includes the given IP.

Parameters:

  • ip (Address, String)

    IP address to check

Returns:

  • (Boolean)

    true if the range includes the given IP



190
191
192
193
194
195
# File 'lib/philiprehberger/ip_addr.rb', line 190

def include?(ip)
  addr = ip.is_a?(Address) ? ::IPAddr.new(ip.to_s) : ::IPAddr.new(ip.to_s)
  @network.include?(addr)
rescue ::IPAddr::InvalidAddressError
  false
end

#ipv4?Boolean

Returns true if this is an IPv4 range.

Returns:

  • (Boolean)

    true if this is an IPv4 range



218
219
220
# File 'lib/philiprehberger/ip_addr.rb', line 218

def ipv4?
  @network.ipv4?
end

#ipv6?Boolean

Returns true if this is an IPv6 range.

Returns:

  • (Boolean)

    true if this is an IPv6 range



223
224
225
# File 'lib/philiprehberger/ip_addr.rb', line 223

def ipv6?
  @network.ipv6?
end

#netmaskString

Returns subnet mask.

Returns:

  • (String)

    subnet mask



171
172
173
174
175
176
177
178
# File 'lib/philiprehberger/ip_addr.rb', line 171

def netmask
  if @network.ipv4?
    mask_int = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF
    [24, 16, 8, 0].map { |shift| (mask_int >> shift) & 0xFF }.join('.')
  else
    "/#{prefix}"
  end
end

#networkAddress

Returns network address (first address in the block).

Returns:

  • (Address)

    network address (first address in the block)



156
157
158
# File 'lib/philiprehberger/ip_addr.rb', line 156

def network
  Address.new(@network.to_range.first.to_s)
end

#overlap?(other) ⇒ Boolean

Returns true if the two ranges share any addresses.

Parameters:

  • other (Range)

    another CIDR range

Returns:

  • (Boolean)

    true if the two ranges share any addresses

Raises:



182
183
184
185
186
# File 'lib/philiprehberger/ip_addr.rb', line 182

def overlap?(other)
  raise Error, 'Argument must be a Range' unless other.is_a?(Range)

  @network.include?(other.network.to_s) || other.include?(network.to_s)
end

#prefixInteger

Returns CIDR prefix length.

Returns:

  • (Integer)

    CIDR prefix length



166
167
168
# File 'lib/philiprehberger/ip_addr.rb', line 166

def prefix
  @network.prefix
end

#sizeInteger

Returns number of addresses in the range.

Returns:

  • (Integer)

    number of addresses in the range



147
148
149
150
151
152
153
# File 'lib/philiprehberger/ip_addr.rb', line 147

def size
  if @network.ipv4?
    2**(32 - prefix)
  else
    2**(128 - prefix)
  end
end

#subnets(prefix:) {|Range| ... } ⇒ Enumerator<Range>

Split the range into equal-size child subnets at the given prefix length

Parameters:

  • prefix (Integer)

    the child subnet prefix length

Yields:

  • (Range)

    each child subnet

Returns:

  • (Enumerator<Range>)

    if no block given

Raises:

  • (ArgumentError)

    if prefix is not larger than the current prefix or exceeds the address family max



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/philiprehberger/ip_addr.rb', line 232

def subnets(prefix:)
  max_prefix = ipv6? ? 128 : 32
  unless prefix.is_a?(Integer) && prefix > @network.prefix && prefix <= max_prefix
    raise ArgumentError,
          "prefix must be an Integer greater than #{@network.prefix} and <= #{max_prefix}, got #{prefix.inspect}"
  end

  return enum_for(:subnets, prefix: prefix) unless block_given?

  step = 2**(max_prefix - prefix)
  start_int = @network.to_range.first.to_i
  end_int = @network.to_range.last.to_i
  int = start_int
  while int <= end_int
    addr = ipv4? ? int_to_v4(int) : int_to_v6(int)
    yield Range.new("#{addr}/#{prefix}")
    int += step
  end
end

#to_aArray<Address>

Returns all addresses in the range.

Returns:

  • (Array<Address>)

    all addresses in the range



213
214
215
# File 'lib/philiprehberger/ip_addr.rb', line 213

def to_a
  each.to_a
end

#to_sString

Returns string representation.

Returns:

  • (String)

    string representation



253
254
255
# File 'lib/philiprehberger/ip_addr.rb', line 253

def to_s
  @cidr
end