Object
IPAddr provides a set of methods to manipulate an IP address.  Both IPv4 and IPv6 are supported.
require 'ipaddr' ipaddr1 = IPAddr.new "3ffe:505:2::1" p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff> p ipaddr1.to_s #=> "3ffe:505:2::1" ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000> p ipaddr2.to_s #=> "3ffe:505:2::" ipaddr3 = IPAddr.new "192.168.2.0/24" p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
32 bit mask for IPv4
Format string for IPv6
128 bit mask for IPv6
Regexp internally used for parsing IPv4 address.
Regexp internally used for parsing IPv6 address.
Regexp internally used for parsing IPv6 address.
Creates a new ipaddr object either from a human readable IP address representation in string, or from a packed in_addr value followed by an address family.
In the former case, the following are the valid formats that will be recognized: “address”, “address/prefixlen” and “address/mask”, where IPv6 address may be enclosed in square brackets (`[' and `]'). If a prefixlen or a mask is specified, it returns a masked IP address. Although the address family is determined automatically from a specified string, you can specify one explicitly by the optional second argument.
Otherwise an IP address is generated from a packed in_addr value and an address family.
The IPAddr class defines many methods and operators, and some of those, such as &, |, include? and ==, accept a string, or a packed in_addr value instead of an IPAddr object.
 
               # File ipaddr.rb, line 557
def initialize(addr = '::', family = Socket::AF_UNSPEC)
  if !addr.kind_of?(String)
    case family
    when Socket::AF_INET, Socket::AF_INET6
      set(addr.to_i, family)
      @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
      return
    when Socket::AF_UNSPEC
      raise AddressFamilyError, "address family must be specified"
    else
      raise AddressFamilyError, "unsupported address family: #{family}"
    end
  end
  prefix, prefixlen = addr.split('/')
  if prefix =~ /\A\[(.*)\]\z/i
    prefix = $1
    family = Socket::AF_INET6
  end
  # It seems AI_NUMERICHOST doesn't do the job.
  #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
  #                  Socket::AI_NUMERICHOST)
  @addr = @family = nil
  if family == Socket::AF_UNSPEC || family == Socket::AF_INET
    @addr = in_addr(prefix)
    if @addr
      @family = Socket::AF_INET
    end
  end
  if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
    @addr = in6_addr(prefix)
    @family = Socket::AF_INET6
  end
  if family != Socket::AF_UNSPEC && @family != family
    raise AddressFamilyError, "address family mismatch"
  end
  if prefixlen
    mask!(prefixlen)
  else
    @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
  end
end
             
            Creates a new ipaddr containing the given network byte ordered string form of an IP address.
 
               # File ipaddr.rb, line 106
def IPAddr::new_ntoh(addr)
  return IPAddr.new(IPAddr::ntop(addr))
end
             
            Convert a network byte ordered string form of an IP address into human readable form.
 
               # File ipaddr.rb, line 112
def IPAddr::ntop(addr)
  case addr.size
  when 4
    s = addr.unpack('C4').join('.')
  when 16
    s = IN6FORMAT % addr.unpack('n8')
  else
    raise AddressFamilyError, "unsupported address family"
  end
  return s
end
             
            Returns a new ipaddr built by bitwise AND.
 
               # File ipaddr.rb, line 125
def &(other)
  return self.clone.set(@addr & coerce_other(other).to_i)
end
             
            Returns a new ipaddr built by bitwise left shift.
 
               # File ipaddr.rb, line 140
def <<(num)
  return self.clone.set(addr_mask(@addr << num))
end
             
            Compares the ipaddr with another.
 
               # File ipaddr.rb, line 391
def <=>(other)
  other = coerce_other(other)
rescue
  nil
else
  @addr <=> other.to_i if other.family == @family
end
             
            Returns true if two ipaddrs are equal.
 
               # File ipaddr.rb, line 150
def ==(other)
  other = coerce_other(other)
rescue
  false
else
  @family == other.family && @addr == other.to_i
end
             
            Returns a new ipaddr built by bitwise right-shift.
 
               # File ipaddr.rb, line 135
def >>(num)
  return self.clone.set(@addr >> num)
end
             
            Checks equality used by Hash.
 
               # File ipaddr.rb, line 401
def eql?(other)
  return self.class == other.class && self.hash == other.hash && self == other
end
             
            Returns a hash value used by Hash, Set, and Array classes
 
               # File ipaddr.rb, line 406
def hash
  return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
end
             
            Returns a network byte ordered string form of the IP address.
 
               # File ipaddr.rb, line 239
def hton
  case @family
  when Socket::AF_INET
    return [@addr].pack('N')
  when Socket::AF_INET6
    return (0..7).map { |i|
      (@addr >> (112 - 16 * i)) & 0xffff
    }.pack('n8')
  else
    raise AddressFamilyError, "unsupported address family"
  end
end
             
            Returns true if the given ipaddr is in the range.
e.g.:
require 'ipaddr' net1 = IPAddr.new("192.168.2.0/24") net2 = IPAddr.new("192.168.2.100") net3 = IPAddr.new("192.168.3.0") p net1.include?(net2) #=> true p net1.include?(net3) #=> false
 
               # File ipaddr.rb, line 173
def include?(other)
  other = coerce_other(other)
  if ipv4_mapped?
    if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
      return false
    end
    mask_addr = (@mask_addr & IN4MASK)
    addr = (@addr & IN4MASK)
    family = Socket::AF_INET
  else
    mask_addr = @mask_addr
    addr = @addr
    family = @family
  end
  if other.ipv4_mapped?
    other_addr = (other.to_i & IN4MASK)
    other_family = Socket::AF_INET
  else
    other_addr = other.to_i
    other_family = other.family
  end
  if family != other_family
    return false
  end
  return ((addr & mask_addr) == (other_addr & mask_addr))
end
             
            Returns a string containing a human-readable representation of the ipaddr. (“#<IPAddr: family:address/mask>”)
 
               # File ipaddr.rb, line 457
def inspect
  case @family
  when Socket::AF_INET
    af = "IPv4"
  when Socket::AF_INET6
    af = "IPv6"
  else
    raise AddressFamilyError, "unsupported address family"
  end
  return sprintf("#<%s: %s:%s/%s>", self.class.name,
                 af, _to_string(@addr), _to_string(@mask_addr))
end
             
            Returns a string for DNS reverse lookup compatible with RFC3172.
 
               # File ipaddr.rb, line 370
def ip6_arpa
  if !ipv6?
    raise InvalidAddressError, "not an IPv6 address"
  end
  return _reverse + ".ip6.arpa"
end
             
            Returns a string for DNS reverse lookup compatible with RFC1886.
 
               # File ipaddr.rb, line 378
def ip6_int
  if !ipv6?
    raise InvalidAddressError, "not an IPv6 address"
  end
  return _reverse + ".ip6.int"
end
             
            Returns true if the ipaddr is an IPv4 address.
 
               # File ipaddr.rb, line 253
def ipv4?
  return @family == Socket::AF_INET
end
             
            Returns a new ipaddr built by converting the native IPv4 address into an IPv4-compatible IPv6 address.
 
               # File ipaddr.rb, line 338
def ipv4_compat
  warn "IPAddr\##{__callee__} is obsolete", uplevel: 1 if $VERBOSE
  if !ipv4?
    raise InvalidAddressError, "not an IPv4 address"
  end
  return self.clone.set(@addr, Socket::AF_INET6)
end
             
            Returns true if the ipaddr is an IPv4-compatible IPv6 address.
 
               # File ipaddr.rb, line 312
def ipv4_compat?
  warn "IPAddr\##{__callee__} is obsolete", uplevel: 1 if $VERBOSE
  _ipv4_compat?
end
             
            Returns a new ipaddr built by converting the native IPv4 address into an IPv4-mapped IPv6 address.
 
               # File ipaddr.rb, line 329
def ipv4_mapped
  if !ipv4?
    raise InvalidAddressError, "not an IPv4 address"
  end
  return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
end
             
            Returns true if the ipaddr is an IPv4-mapped IPv6 address.
 
               # File ipaddr.rb, line 307
def ipv4_mapped?
  return ipv6? && (@addr >> 32) == 0xffff
end
             
            Returns true if the ipaddr is an IPv6 address.
 
               # File ipaddr.rb, line 258
def ipv6?
  return @family == Socket::AF_INET6
end
             
            Returns true if the ipaddr is a link-local address. IPv4 addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are considered link-local.
 
               # File ipaddr.rb, line 295
def link_local?
  case @family
  when Socket::AF_INET
    @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
  when Socket::AF_INET6
    @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
  else
    raise AddressFamilyError, "unsupported address family"
  end
end
             
            Returns true if the ipaddr is a loopback address.
 
               # File ipaddr.rb, line 263
def loopback?
  case @family
  when Socket::AF_INET
    @addr & 0xff000000 == 0x7f000000
  when Socket::AF_INET6
    @addr == 1
  else
    raise AddressFamilyError, "unsupported address family"
  end
end
             
            Returns a new ipaddr built by masking IP address with the given prefixlen/netmask. (e.g. 8, 64, “255.255.255.0”, etc.)
 
               # File ipaddr.rb, line 160
def mask(prefixlen)
  return self.clone.mask!(prefixlen)
end
             
            Returns a new ipaddr built by converting the IPv6 address into a native IPv4 address. If the IP address is not an IPv4-mapped or IPv4-compatible IPv6 address, returns self.
 
               # File ipaddr.rb, line 349
def native
  if !ipv4_mapped? && !_ipv4_compat?
    return self
  end
  return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
end
             
            Returns the prefix length in bits for the ipaddr.
 
               # File ipaddr.rb, line 427
def prefix
  case @family
  when Socket::AF_INET
    n = IN4MASK ^ @mask_addr
    i = 32
  when Socket::AF_INET6
    n = IN6MASK ^ @mask_addr
    i = 128
  else
    raise AddressFamilyError, "unsupported address family"
  end
  while n.positive?
    n >>= 1
    i -= 1
  end
  i
end
             
            Sets the prefix length in bits
 
               # File ipaddr.rb, line 446
def prefix=(prefix)
  case prefix
  when Integer
    mask!(prefix)
  else
    raise InvalidPrefixError, "prefix must be an integer"
  end
end
             
            Returns true if the ipaddr is a private address. IPv4 addresses in 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 as defined in RFC 1918 and IPv6 Unique Local Addresses in fc00::/7 as defined in RFC 4193 are considered private.
 
               # File ipaddr.rb, line 278
def private?
  case @family
  when Socket::AF_INET
    @addr & 0xff000000 == 0x0a000000 ||    # 10.0.0.0/8
      @addr & 0xfff00000 == 0xac100000 ||  # 172.16.0.0/12
      @addr & 0xffff0000 == 0xc0a80000     # 192.168.0.0/16
  when Socket::AF_INET6
    @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000
  else
    raise AddressFamilyError, "unsupported address family"
  end
end
             
            Returns a string for DNS reverse lookup. It returns a string in RFC3172 form for an IPv6 address.
 
               # File ipaddr.rb, line 358
def reverse
  case @family
  when Socket::AF_INET
    return _reverse + ".in-addr.arpa"
  when Socket::AF_INET6
    return ip6_arpa
  else
    raise AddressFamilyError, "unsupported address family"
  end
end
             
            Returns the successor to the ipaddr.
 
               # File ipaddr.rb, line 386
def succ
  return self.clone.set(@addr + 1, @family)
end
             
            Returns the integer representation of the ipaddr.
 
               # File ipaddr.rb, line 203
def to_i
  return @addr
end
             
            Creates a Range object for the network address.
 
               # File ipaddr.rb, line 411
def to_range
  begin_addr = (@addr & @mask_addr)
  case @family
  when Socket::AF_INET
    end_addr = (@addr | (IN4MASK ^ @mask_addr))
  when Socket::AF_INET6
    end_addr = (@addr | (IN6MASK ^ @mask_addr))
  else
    raise AddressFamilyError, "unsupported address family"
  end
  return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
end
             
            Returns a string containing the IP address representation.
 
               # File ipaddr.rb, line 208
def to_s
  str = to_string
  return str if ipv4?
  str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
  loop do
    break if str.sub!(/\A0:0:0:0:0:0:0:0\z/, '::')
    break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0:0\b/, ':')
    break if str.sub!(/\b0:0:0\b/, ':')
    break if str.sub!(/\b0:0\b/, ':')
    break
  end
  str.sub!(/:{3,}/, '::')
  if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\z/i =~ str
    str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
  end
  str
end
             
            Returns a string containing the IP address representation in canonical form.
 
               # File ipaddr.rb, line 234
def to_string
  return _to_string(@addr)
end
             
            Set current netmask to given mask.
 
               # File ipaddr.rb, line 496
def mask!(mask)
  case mask
  when String
    if mask =~ /\A\d+\z/
      prefixlen = mask.to_i
    else
      m = IPAddr.new(mask)
      if m.family != @family
        raise InvalidPrefixError, "address family is not same"
      end
      @mask_addr = m.to_i
      n = @mask_addr ^ m.instance_variable_get(:@mask_addr)
      unless ((n + 1) & n).zero?
        raise InvalidPrefixError, "invalid mask #{mask}"
      end
      @addr &= @mask_addr
      return self
    end
  else
    prefixlen = mask
  end
  case @family
  when Socket::AF_INET
    if prefixlen < 0 || prefixlen > 32
      raise InvalidPrefixError, "invalid length"
    end
    masklen = 32 - prefixlen
    @mask_addr = ((IN4MASK >> masklen) << masklen)
  when Socket::AF_INET6
    if prefixlen < 0 || prefixlen > 128
      raise InvalidPrefixError, "invalid length"
    end
    masklen = 128 - prefixlen
    @mask_addr = ((IN6MASK >> masklen) << masklen)
  else
    raise AddressFamilyError, "unsupported address family"
  end
  @addr = ((@addr >> masklen) << masklen)
  return self
end
             
            Set +@addr+, the internal stored ip address, to given addr. The parameter addr is validated using the first family member, which is Socket::AF_INET or Socket::AF_INET6.
 
               # File ipaddr.rb, line 475
def set(addr, *family)
  case family[0] ? family[0] : @family
  when Socket::AF_INET
    if addr < 0 || addr > IN4MASK
      raise InvalidAddressError, "invalid address"
    end
  when Socket::AF_INET6
    if addr < 0 || addr > IN6MASK
      raise InvalidAddressError, "invalid address"
    end
  else
    raise AddressFamilyError, "unsupported address family"
  end
  @addr = addr
  if family[0]
    @family = family[0]
  end
  return self
end