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



130
131
132
133
134
135
# File 'lib/philiprehberger/ip_addr.rb', line 130

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)



152
153
154
# File 'lib/philiprehberger/ip_addr.rb', line 152

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



191
192
193
194
195
196
197
198
199
200
201
# File 'lib/philiprehberger/ip_addr.rb', line 191

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



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

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



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

def ipv4?
  @network.ipv4?
end

#ipv6?Boolean

Returns true if this is an IPv6 range.

Returns:

  • (Boolean)

    true if this is an IPv6 range



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

def ipv6?
  @network.ipv6?
end

#netmaskString

Returns subnet mask.

Returns:

  • (String)

    subnet mask



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

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)



147
148
149
# File 'lib/philiprehberger/ip_addr.rb', line 147

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:



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

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



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

def prefix
  @network.prefix
end

#sizeInteger

Returns number of addresses in the range.

Returns:

  • (Integer)

    number of addresses in the range



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

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



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/philiprehberger/ip_addr.rb', line 223

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



204
205
206
# File 'lib/philiprehberger/ip_addr.rb', line 204

def to_a
  each.to_a
end

#to_sString

Returns string representation.

Returns:

  • (String)

    string representation



244
245
246
# File 'lib/philiprehberger/ip_addr.rb', line 244

def to_s
  @cidr
end