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



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

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)



177
178
179
# File 'lib/philiprehberger/ip_addr.rb', line 177

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



216
217
218
219
220
221
222
223
224
225
226
# File 'lib/philiprehberger/ip_addr.rb', line 216

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



206
207
208
209
210
211
# File 'lib/philiprehberger/ip_addr.rb', line 206

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



234
235
236
# File 'lib/philiprehberger/ip_addr.rb', line 234

def ipv4?
  @network.ipv4?
end

#ipv6?Boolean

Returns true if this is an IPv6 range.

Returns:

  • (Boolean)

    true if this is an IPv6 range



239
240
241
# File 'lib/philiprehberger/ip_addr.rb', line 239

def ipv6?
  @network.ipv6?
end

#netmaskString

Returns subnet mask.

Returns:

  • (String)

    subnet mask



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

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)



172
173
174
# File 'lib/philiprehberger/ip_addr.rb', line 172

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:



198
199
200
201
202
# File 'lib/philiprehberger/ip_addr.rb', line 198

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



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

def prefix
  @network.prefix
end

#sizeInteger

Returns number of addresses in the range.

Returns:

  • (Integer)

    number of addresses in the range



163
164
165
166
167
168
169
# File 'lib/philiprehberger/ip_addr.rb', line 163

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



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/philiprehberger/ip_addr.rb', line 248

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



229
230
231
# File 'lib/philiprehberger/ip_addr.rb', line 229

def to_a
  each.to_a
end

#to_sString

Returns string representation.

Returns:

  • (String)

    string representation



269
270
271
# File 'lib/philiprehberger/ip_addr.rb', line 269

def to_s
  @cidr
end