= ruby-ip library This is a library for manipulating IP addresses. {Build Status}[https://travis-ci.org/G7M3/ruby-ip2] {Coverage Status}[https://coveralls.io/github/G7M3/ruby-ip2?branch=master] == Installation Gem:: gem install ruby-ip Source:: git clone git://github.com/G7M3/ruby-ip2.git == Feature overview * Create from string and to string require 'ip' ip = IP.new("192.0.2.53/24") ip.to_s # "192.0.2.53/24" ip.to_i # 3221226037 ip.to_b # 11000000000000000000001000110101 ip.to_hex # "c0000235" ip.to_addr # "192.0.2.53" ip.to_arpa # "53.2.0.192.in-addr.arpa." ip.pfxlen # 24 * Convert from IPAddr to IP and back to IPAddr # new IPAddr ipaddr = IPAddr.new('192.168.2.1') # => # # convert it to IP ip_from_ipaddr = IP.new_ntoh(ipaddr.hton) # => # and back to IPAddr ipaddr_from_ip = IPAddr.new_ntoh(ip_from_ipaddr.hton) # => # * Qualify IP address with "routing context" (VRF) ip = IP.new("192.0.2.53/24@cust1") ip.to_s # "192.0.2.53/24@cust1" ip.to_addrlen # "192.0.2.53/24" ip.ctx # "cust1" * Clean implementation of IP::V4 and IP::V6 as subclasses of IP ip1 = IP.new("192.0.2.53/24") # ip2 = IP.new("2001:db8:be00::/48") # ip1.is_a?(IP::V4) # true * Create directly from integers or hex ip = IP::V4.new(3221226037, 24, "cust1") ip = IP::V4.new("c0000235", 24, "cust1") * Netmask manipulation ip = IP.new("192.0.2.53/24") ip.network # ip.network(1) # ip.broadcast # ip.broadcast(-1) # ip.mask # 255 ip.size # 256 ip.netmask.to_s # "255.255.255.0" ip.wildmask.to_s # "0.0.0.255" * Address masking ip = IP.new("192.0.2.53/24") ip.offset? # true ip.offset # 53 ip.mask! ip.to_s # "192.0.2.0/24" ip.offset? # false * Simple IP arithmetic ip = IP.new("192.0.2.53/24") ip + 4 # ip | 7 # ip ^ 7 # ~ip # * Advanced Subnet Operations sn = IP.new('192.168.0.0/24') ip = IP.new('192.168.0.48/32') sn.split [#, #] (2 evenly divided subnets) sn.divide_by_subnets(3) [#, #, #, #] (4 evenly divided subnets) #keep in mind this always takes into account a network and broadcast address sn.divide_by_hosts(100) [#, #] (128 hosts each) ip = IP.new('192.168.0.48/32') ip.is_in?(sn) => true * Deaggregate subnets from range IP.new('1.2.0.0').deaggregate(IP.new('1.3.255.255')) => [#] IP.new('1.2.0.0').deaggregate(IP.new('1.4.255.255')) => [#, #] IP.new('2001:db8:85a3:8d3::').deaggregate(IP.new('2001:0db8:85a3:08d3:ffff:ffff:ffff:ffff')) => [#] IP.new('2001:db8:85a3:8d3::').deaggregate(IP.new('2001:db8:85a3:8d3:1::')) => [#, #] * Convert to and from a compact Array representation ip1 = IP.new("192.0.2.53/24@cust1") ip1.to_a # ["v4", 3221226037, 24, "cust1"] ip2 = IP.new(["v4", 3221226037, 24, "cust1"]) ip1 == ip2 # true * Hex array representation, useful when talking to languages which don't have Bignum support ip1 = IP.new("2001:db8:be00::/48@cust1") ip1.to_ah # ["v6", "20010db8be0000000000000000000000", 48, "cust1"] ip2 = IP.new(["v6", "20010db8be0000000000000000000000", 48, "cust1"]) ip1 == ip2 # true * Addresses are Comparable, sortable, and can be used as Hash keys * Addresses can be stored in a VARBINARY(16) database column as string of bytes # == Schema Information # # Table name: ipaddresses # # id :integer not null, primary key # address :binary(16) # pfxlen :integer # created_at :datetime not null # updated_at :datetime not null # # Indexes # # index_ipaddresses_on_address (address) # index_ipaddresses_on_pfxlen (pfxlen) # require 'ip' class IpAddress < ActiveRecord::Base validates_uniqueness_of :address, scope: [:pfxlen] validates_presence_of :address, :pfxlen # IpAddress.last.address returns an IP object def address IP.new("#{IP.new_ntoh(super).to_s}/#{pfxlen}") end # Address can be set with string: # ipaddress = IpAddress.new({address: '2001:db8:be00::/128'}) # Or IP object: # ip = IP.new('2001:db8:be00::/128') # ipaddress = IpAddress.new({address: ip}) def address=(arg) ip = IP.new(arg) self.pfxlen = ip.pfxlen super(ip.hton) end end == Why not IPAddr? Ruby bundles an IPAddr class (ipaddr.rb). However there are a number of serious problems with this library. 1. Given an IP address with a netmask or prefix (e.g. 192.0.2.0/24) it's very hard to get access to the netmask part. It involves digging around instance variables. 2. It's impossible to deal with an off-base address with prefix, because IPAddr forcibly masks it to the base. e.g. 192.0.2.53/24 is stored as 192.0.2.0/24 3. IPAddr uses calls to the socket library to validate IP addresses, and this can trigger spurious DNS lookups when given an invalid IP address. ruby-ip does not depend on the socket library at all, unless you require 'ip/socket' to have access to the Socket::AF_INET and Socket::AF_INET6 constants. == Copying You may use, distribute and modify this software under the same terms as ruby itself (see LICENSE.txt and COPYING.txt)