class Ronin::Support::Network::IPRange::Glob

Represents an IP-glob range.

## Examples

ip_range = IPRange::Glob.new('10.0.1-3.*/24')
ip_range.each { |ip| puts ip }
# 10.0.1.0
# 10.0.1.1
# ...
# 10.0.1.254
# 10.0.1.255
# ...
# 10.0.2.0
# 10.0.2.1
# ...
# 10.0.2.254
# 10.0.2.255
# ...
# 10.0.3.0
# 10.0.3.1
# ...
# 10.0.3.254
# 10.0.3.255

@api public

@since 1.0.0

Constants

IPV4_REGEX

Regular expression that matches IPv4-glob ranges.

@api private

@since 1.1.0

IPV6_REGEX

Regular expression that matches IPv6-glob ranges.

@api private

@since 1.1.0

REGEX

Regular expression to match IP-glob ranges.

@api private

@since 1.1.0

Attributes

string[R]

The IP glob string.

@return [String]

Public Class Methods

each(string,&block) click to toggle source

Enumerates over the IP-glob range.

@param [String] string

The IP-glob string to parse and enumerate over.

@yield [ip]

The block which will be passed each IP address contained within
the IP address range.

@yieldparam [String] ip

An IP address within the IP address range.

@return [self]

@example Enumerate through a IPv4 glob range:

IPRange::Glob.each('10.0.1-3.*') { |ip| puts ip }
# 10.0.1.0
# 10.0.1.1
# ...
# 10.0.1.254
# 10.0.1.255
# ...
# 10.0.2.0
# 10.0.2.1
# ...
# 10.0.2.254
# 10.0.2.255
# ...
# 10.0.3.0
# 10.0.3.1
# ...
# 10.0.3.254
# 10.0.3.255

@example Enumerate through a globbed IPv6 range:

IPRange::Glob.each('::ff::02-0a::c3') { |ip| puts ip }
# File lib/ronin/support/network/ip_range/glob.rb, line 205
def self.each(string,&block)
  new(string).each(&block)
end
new(string) click to toggle source

Initializes and parses the IP-glob range.

@param [String] string

The IP-glob string to parse.

@raise [ArgumentError]

The IP-glob string was neither a valid IPv4 or IPv6 glob address.
# File lib/ronin/support/network/ip_range/glob.rb, line 121
def initialize(string)
  @string = string

  case string
  when IPV4_REGEX
    @version   = 4
    @base      = 10
    @formatter = method(:format_ipv4_address)

    separator   = '.'
    octet_range = (0..255)
  when IPV6_REGEX
    @version   = 6
    @base      = 16
    @formatter = method(:format_ipv6_address)

    separator   = ':'
    octet_range = (0..0xffff)
  else
    raise(ArgumentError,"invalid IP-glob range: #{string.inspect}")
  end

  @ranges = string.split(separator).map do |segment|
    if    segment == '*'        then octet_range
    elsif segment.include?(',') then parse_list(segment)
    elsif segment.include?('-') then parse_range(segment)
    else                             [segment]
    end
  end
end
parse(string) click to toggle source

Alias for {#initialize new}.

@param [String] string

The IP-glob string to parse.

@return [Glob]

The parsed IP-glob range.

@see initialize

# File lib/ronin/support/network/ip_range/glob.rb, line 163
def self.parse(string)
  new(string)
end

Public Instance Methods

==(other) click to toggle source

Compares the IP glob range to another IP range.

@param [Object] other

The other IP range.

@return [Boolean]

@since 1.1.0

# File lib/ronin/support/network/ip_range/glob.rb, line 252
def ==(other)
  other.kind_of?(self.class) && @string == other.string
end
===(other) click to toggle source

Determines if the given IP range is a sub-set of the IP CIDR range.

@param [Glob, CIDR, Enumerable<String>] other

The other IP range.

@return [Boolean]

@since 1.1.0

# File lib/ronin/support/network/ip_range/glob.rb, line 266
def ===(other)
  case other
  when Enumerable
    other.all? { |ip| include?(ip) }
  else
    false
  end
end
each() { |call| ... } click to toggle source

Enumerates over the IP-glob range.

@yield [ip]

The block which will be passed each IP address contained within
the IP address range.

@yieldparam [String] ip

An IP address within the IP address range.

@return [self]

@example Enumerate through a IPv4 glob range:

ip_range = IPRange::Glob.new('10.0.1-3.*')
ip_range.each { |ip| puts ip }
# 10.0.1.0
# 10.0.1.1
# ...
# 10.0.1.254
# 10.0.1.255
# ...
# 10.0.2.0
# 10.0.2.1
# ...
# 10.0.2.254
# 10.0.2.255
# ...
# 10.0.3.0
# 10.0.3.1
# ...
# 10.0.3.254
# 10.0.3.255

@example Enumerate through a globbed IPv6 range:

ip_range = IPRange::Glob.new('::ff::02-0a::c3')
ip_range.each { |ip| puts ip }
# File lib/ronin/support/network/ip_range/glob.rb, line 312
def each
  return enum_for(__method__) unless block_given?

  # cycle through the address ranges
  @ranges.comprehension do |address|
    yield @formatter.call(address)
  end

  return self
end
first() click to toggle source

The first address in the IP glob range.

@return [String]

The first IP address in the IP glob range.

@since 1.1.0

# File lib/ronin/support/network/ip_range/glob.rb, line 331
def first
  @formatter.call(@ranges.map(&:first))
end
include?(ip) click to toggle source

Determines whether the IP address exists within the IP range.

@param [IP, IPAddr, String] ip

The IP address to check.

@return [Boolean]

Indicates whether the IP address exists within the IP range.

@since 1.1.0

Calls superclass method
# File lib/ronin/support/network/ip_range/glob.rb, line 238
def include?(ip)
  super(ip.to_s)
end
inspect() click to toggle source

Inspects the IP-glob range.

@return [String]

# File lib/ronin/support/network/ip_range/glob.rb, line 374
def inspect
  "#<#{self.class}: #{@string}>"
end
ipv4?() click to toggle source

Determines if the IP-glob range is IPv4.

@return [Boolean]

# File lib/ronin/support/network/ip_range/glob.rb, line 214
def ipv4?
  @version == 4
end
ipv6?() click to toggle source

Determines if the IP-glob range is IPv6.

@return [Boolean]

# File lib/ronin/support/network/ip_range/glob.rb, line 223
def ipv6?
  @version == 6
end
last() click to toggle source

The last address in the IP glob range.

@return [String]

The last IP address in the IP glob range.

@since 1.1.0

# File lib/ronin/support/network/ip_range/glob.rb, line 343
def last
  @formatter.call(@ranges.map(&:last))
end
size() click to toggle source

Calculates the size of the IP glob range.

@return [Integer]

@since 1.1.0

# File lib/ronin/support/network/ip_range/glob.rb, line 354
def size
  @ranges.reduce(1) do |total,parts|
    total * parts.size
  end
end
to_s() click to toggle source

Converts the IP-glob range back into a String.

@return [String]

# File lib/ronin/support/network/ip_range/glob.rb, line 365
def to_s
  @string
end

Private Instance Methods

format_ipv4_address(parts) click to toggle source

Formats an IPv4 address.

@param [Array<String, Integer>] parts

The address parts to format.

@return [String]

The formatted IPv4 address.
# File lib/ronin/support/network/ip_range/glob.rb, line 427
def format_ipv4_address(parts)
  parts.join('.')
end
format_ipv6_address(parts) click to toggle source

Formats an IPv6 address.

@param [Array<String, Integer>] parts

The address parts to format.

@return [String]

The formatted IPv6 address.
# File lib/ronin/support/network/ip_range/glob.rb, line 440
def format_ipv6_address(parts)
  parts.map { |part|
    case part
    when Integer then part.to_s(16)
    else              part
    end
  }.join(':')
end
parse_list(list) click to toggle source

Parses a comma separated list of numbers or ranges (ex: ‘i,j,k-l`).

@param [String] list

The string to parse.

@return [Array<Integer, Range>]

The parsed list.
# File lib/ronin/support/network/ip_range/glob.rb, line 389
def parse_list(list)
  list.split(',').flat_map do |octet|
    if octet.include?('-')
      # i-j range
      parse_range(octet)
    else
      octet.to_i(@base)
    end
  end
end
parse_range(range) click to toggle source

Parses a range of numbers. (ex: ‘i-j`).

@param [String] range

The string to parse.

@return [Range<Integer,Integer>]

The parsed range.
# File lib/ronin/support/network/ip_range/glob.rb, line 409
def parse_range(range)
  start, stop = range.split('-',2)

  start = start.to_i(@base)
  stop  = stop.to_i(@base)

  (start..stop).to_a
end