Class: IPAdmin::CIDR

Inherits:
Object
  • Object
show all
Defined in:
lib/ip_admin.rb

Overview

A class & series of methods for creating and manipulating CIDR network

addresses. Both IPv4 and IPv6 are supported.

This class accepts a CIDR address in (x.x.x.x/yy or xxxx::/yy) format for
IPv4 and IPv6, or (x.x.x.x/y.y.y.y) for IPv4. An optional tag hash may be 
provided with each CIDR as a way of adding custom labels to the object.

Upon initialization, the IP version is auto-detected and assigned to the 
object. The original IP/Netmask passed within the CIDR is stored and then 
used to determine the confines of the CIDR block. Various properties of the
CIDR block are accessible via several different methods. There are also
methods for modifying the CIDR or creating new derivative CIDR's.

An example CIDR object is as follows:
   IPAdmin::CIDR.new(:CIDR => '192.168.1.20/24')

This would create a CIDR object (192.168.1.0/24) with the following properties:
   version = 4
   base network = 192.168.1.0
   ip address = 192.168.1.20
   netmask = /24 (255.255.255.0)
   size = 256 IP addresses
   broadcast = 192.168.1.255

You can see how the CIDR object is based around the entire IP space
defined by the provided IP/Netmask pair, and not necessarily the individual
IP address itself.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ CIDR

  • Arguments:

    • Hash with the following fields:

      - :CIDR -- IPv4 or IPv6 cidr block
      - :Netmask -- IPv4 netmask in extended format (optional)
      - :Tag -- Custom descriptor tag. Hash, tag => value. (optional)
      

Note:

Will assume a host address (/32 or /128) if netmask not specified
as either part of the :CIDR or :Netmask arguments.

Example:

cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.1/24')
cidr6 = IPAdmin::CIDR.new(:CIDR => 'fec0::/64',
                          :Tag => {'interface' => 'g0/1'})


1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
# File 'lib/ip_admin.rb', line 1517

def initialize(options)
    unless (options.kind_of? Hash)
        raise ArgumentError, "Expected Hash, but #{options.class} provided."
    end

    unless ( options.has_key?(:CIDR) )
        raise ArgumentError, "Missing argument: CIDR."
    end

    cidr =  options[:CIDR]

    if (cidr =~/\./) # assume IPv4
        @version = 4
        @max_bits = 32
        @all_f = 2**@max_bits - 1

        if (cidr =~ /\//)
            ip,netmask = cidr.split(/\//)

            # validate
            @ip = IPAdmin.validate_ipv4_addr(ip)
            @netmask = IPAdmin.validate_ipv4_netmask(netmask)

        elsif ( options.has_key?(:Netmask) )
            netmask = options[:Netmask]

            # validate
            @ip = IPAdmin.validate_ipv4_addr(cidr)
            @netmask = IPAdmin.validate_ipv4_netmask(netmask)

        else
            @ip = IPAdmin.validate_ipv4_addr(cidr)
            @netmask = IPAdmin.pack_ipv4_netmask(32) 

        end

        @hostmask = @netmask ^ @all_f

    elsif (cidr =~/:/) # assume IPv6
        @version = 6
        @max_bits = 128
        @all_f = 2**@max_bits - 1

        if (cidr =~ /\//)
            ip,netmask = cidr.split(/\//)

            # validate
            @ip = IPAdmin.validate_ipv6_addr(ip)
            @netmask = IPAdmin.validate_ipv6_netmask(netmask)

        else
            @ip = IPAdmin.validate_ipv6_addr(cidr)
            @netmask = IPAdmin.pack_ipv6_netmask(128)

        end

        @hostmask = @netmask ^ @all_f

    else
        raise "Invalid CIDR address format: #{cidr}."
    end

    # get @network
    @network = (@ip & @netmask)

    # set tag if present
    if ( options.has_key?(:Tag) )
        @tag = options[:Tag]
        unless (@tag.kind_of? Hash)
            raise "Expected Hash, but #{@tag.class} provided for option :Tag."
        end
    end

end

Instance Attribute Details

#tagObject

Hash of custom tags. Should be in the format tag => value.



1477
1478
1479
# File 'lib/ip_admin.rb', line 1477

def tag
  @tag
end

#versionObject (readonly)

IP version 4 or 6.



1474
1475
1476
# File 'lib/ip_admin.rb', line 1474

def version
  @version
end

Instance Method Details

#bitsObject

Provide number of bits in Netmask.

  • Arguments:

    • none

  • Returns:

    • Number of bits in Netmask.

Example:

puts cidr4.bits()   --> 24


1612
1613
1614
1615
1616
1617
1618
1619
1620
# File 'lib/ip_admin.rb', line 1612

def bits()
    if (@version == 4)
        bits = IPAdmin.unpack_ipv4_netmask(@netmask)
    else
        bits = IPAdmin.unpack_ipv6_netmask(@netmask)
    end

    return(bits)
end

#contains?(object) ⇒ Boolean

Determines if this object contains (is supernet of) provided IPAdmin::CIDR object.

  • Arguments:

    • IPAdmin:CIDR object

  • Returns:

    • true or false

Example:

cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/26')
contains? = cidr4.contains(cidr4_2)   --> true

Returns:

  • (Boolean)


1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
# File 'lib/ip_admin.rb', line 1644

def contains?(object)
    is_contained = false

    if (object.kind_of?(IPAdmin::CIDR))
        network = object.packed_network 
        netmask = object.packed_netmask

    else 
        raise ArgumentError, "Expected IPAdmin::CIDR " +
                             " object but #{object.class} provided."
    end


    unless (object.version == @version)
        raise "Attempted to compare a version #{object.version} CIDR " +
                  "with a version #{@version} CIDR."
    end

    # if network == @network, then we have to go by netmask length
    # else we can tell by or'ing network and @network by @hostmask
    # and comparing the results
    if (network == @network)
        is_contained = true if (netmask > @netmask)

    else
        if ( (network | @hostmask) == (@network | @hostmask) )
            is_contained = true
        end
    end

    return(is_contained)
end

#desc(options = nil) ⇒ Object

Displays base network, and netmask of this object.

  • Arguments:

    • Optional hash with the following fields:

      - :IP -- true, return the ip/netmask passed during initialization (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • Description in network/netmask format

Example:

puts cidr4.desc()   --> 192.168.1.0/24
puts cidr4.desc(:IP => 1)   --> 192.168.1.1/24


1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
# File 'lib/ip_admin.rb', line 1700

def desc(options=nil)
    short = false
    orig_ip = false

    if (options)
        unless (options.kind_of? Hash)
            raise ArgumentError, "Expected Hash, but #{options.class} provided."
        end
        
        if (options.has_key?(:Short))
            short = true
        end
        
        if (options.has_key?(:IP))
            orig_ip = true
        end
    end
    
    if (@version == 4)
        if (!orig_ip)
            ip = IPAdmin.unpack_ipv4_addr(@network)
        else
            ip = IPAdmin.unpack_ipv4_addr(@ip)
        end
        mask = IPAdmin.unpack_ipv4_netmask(@netmask)
    else
        if (!orig_ip)
            ip = IPAdmin.unpack_ipv6_addr(@network)
        else
            ip = IPAdmin.unpack_ipv6_addr(@ip)
        end
        ip = IPAdmin.shorten(ip) if (short)
        mask = IPAdmin.unpack_ipv6_netmask(@netmask)
    end

    return("#{ip}/#{mask}")

end

#enumerate(options = nil) ⇒ Object

Provide all IP addresses contained within the IP space of this CIDR. (warning: this can be quite large for big blocks)

  • Arguments:

    • Optional Hash with the following fields:

      - :Bitstep -- enumerate in X sized steps (optional)
      - :Limit -- limit returned list to X number of items (optional)
      - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • Array of IP addresses or IPAdmin::CIDR objects

Example:

ip_list = cidr4.enumerate(:Bitstep => 2, :Limit => 2)   --> ['192.168.1.0','192.168.1.1']


1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
# File 'lib/ip_admin.rb', line 1764

def enumerate(options=nil)
    bitstep = 1
    objectify = false
    limit = nil
    short = false

    if (options)
        if( options.has_key?(:Bitstep) )
            bitstep = options[:Bitstep]
        end

        if( options.has_key?(:Objectify) )
            objectify = true
        end

        if( options.has_key?(:Limit) )
            limit = options[:Limit]
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
    end

    list = []
    if (@version == 4)
        my_ip = @network
        change_mask = @hostmask | my_ip

        until ( change_mask != (@hostmask | @network) ) 
            if (!objectify)
                list.push( IPAdmin.unpack_ipv4_addr(my_ip) )
            else
                my_ip_s = IPAdmin.unpack_ipv4_addr(my_ip)
                list.push( IPAdmin::CIDR.new(:CIDR => my_ip_s) )
            end
            my_ip = my_ip + bitstep
            change_mask = @hostmask | my_ip
            if (limit)
                limit = limit -1
                break if (limit == 0)
            end
        end

    elsif (@version == 6)
        my_ip = @network
        change_mask = @hostmask | my_ip

        until ( change_mask != (@hostmask | @network) )                
            if (!objectify)
                my_ip_s = IPAdmin.unpack_ipv6_addr(my_ip)
                my_ip_s = IPAdmin.shorten(my_ip_s) if (short)
                list.push(my_ip_s)
            else
                my_ip_s = IPAdmin.unpack_ipv6_addr(my_ip)
                list.push( IPAdmin::CIDR.new(:CIDR => my_ip_s) )
            end
            my_ip = my_ip + bitstep
            change_mask = @hostmask | my_ip
            if (limit)
                limit = limit -1
                break if (limit == 0)
            end
        end

    else
        list = nil

    end

    return(list)
end

#hostmask_extObject

Provide IPv4 Hostmask in extended format.

  • Arguments:

    • none

  • Returns:

    • Hostmask in extended (y.y.y.y) format.

Example:

puts cidr4.hostmask_ext()   --> 0.0.0.255


1857
1858
1859
1860
1861
1862
1863
1864
1865
# File 'lib/ip_admin.rb', line 1857

def hostmask_ext()
    if (@version == 4)
        hostmask = IPAdmin.unpack_ipv4_addr(@hostmask)
    else
        raise "IPv6 does not support extended hostmask notation." 
    end

    return(hostmask)
end

#ip(options = nil) ⇒ Object

Provide original IP address passed during initialization.

  • Arguments:

    • Optional Hash with the following fields:

      - :Objectify -- if true, return IPAdmin::CIDR object (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • IP address or IPAdmin::CIDR object.

Example:

puts cidr4.ip()   --> 192.168.1.1


1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
# File 'lib/ip_admin.rb', line 1889

def ip(options=nil)
    objectify = false
    short = false
    
    if (options)
        unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
        
        if( options.has_key?(:Objectify) )
            objectify = true
        end
    end

    if (@version == 4)
        ip = IPAdmin.unpack_ipv4_addr(@ip)
    else
        ip = IPAdmin.unpack_ipv6_addr(@ip)
        ip = IPAdmin.shorten(ip) if (short && !objectify)
    end
    
    if (objectify)
        ip = IPAdmin::CIDR.new(:CIDR => ip)
    end

    return(ip)
end

#last(options = nil) ⇒ Object Also known as: broadcast

Provide last IP address in this CIDR object. The broadcast() method is aliased to this method, and thus works for IPv6 despite the fact that the IPv6 protocol does not support IP broadcasting.

  • Arguments:

    • Optional Hash with the following fields:

      - :Objectify -- if true, return IPAdmin::CIDR object (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • IP address or IPAdmin::CIDR object.

Example:

puts cidr4.last()   --> 192.168.1.255


1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
# File 'lib/ip_admin.rb', line 1946

def last(options=nil)
    objectify = false
    short = false
    
    if (options)
        unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
        
        if( options.has_key?(:Objectify) )
            objectify = true
        end

    end
    
    packed_ip = @network | @hostmask
    if (@version == 4)
        ip = IPAdmin.unpack_ipv4_addr(packed_ip)
    else
        ip = IPAdmin.unpack_ipv6_addr(packed_ip)
        ip = IPAdmin.shorten(ip) if (short && !objectify)
    end
    
    if (objectify)
        ip = IPAdmin::CIDR.new(:CIDR => ip)
    end

    return(ip)
end

#netmaskObject

Provide netmask in cidr format.

  • Arguments:

    • none

  • Returns:

    • Netmask in CIDR format.

Example:

puts cidr4.netmask()   --> /24


2003
2004
2005
2006
2007
2008
2009
2010
2011
# File 'lib/ip_admin.rb', line 2003

def netmask()
    if (@version == 4)
        bits = IPAdmin.unpack_ipv4_netmask(@netmask)
    else
        bits = IPAdmin.unpack_ipv6_netmask(@netmask)
    end

    return("/#{bits}")
end

#netmask_extObject

Provide IPv4 netmask in extended format.

  • Arguments:

    • none

  • Returns:

    • Netmask in extended (y.y.y.y) format.

Example:

puts cidr4.netmask_ext()   --> 255.255.255.0


2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
# File 'lib/ip_admin.rb', line 2033

def netmask_ext()    
    if (@version == 4)
        netmask = IPAdmin.unpack_ipv4_addr(@netmask)
    else
        raise "IPv6 does not support extended netmask notation. " +
              "Use netmask() method instead."
    end

    return(netmask)
end

#network(options = nil) ⇒ Object Also known as: base, first

Provide base network address.

  • Arguments:

    • Optional Hash with the following fields:

      - :Objectify -- if true, return IPAdmin::CIDR object (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • IP address or IPAdmin::CIDR object.

Example:

puts cidr4.network()   --> 192.168.1.0


2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
# File 'lib/ip_admin.rb', line 2066

def network(options=nil)
    objectify = false
    short = false
    
    if (options)
        unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
        
        if( options.has_key?(:Objectify) )
            objectify = true
        end
    end

    if (@version == 4)
        ip = IPAdmin.unpack_ipv4_addr(@network)
    else
        ip = IPAdmin.unpack_ipv6_addr(@network)
        ip = IPAdmin.shorten(ip) if (short && !objectify)
    end
    
    if (objectify)
        ip = IPAdmin::CIDR.new(:CIDR => ip)
    end

    return(ip)
end

#next_ip(options = nil) ⇒ Object

Provide the next IP following the last available IP within this CIDR object.

  • Arguments:

    • Optional Hash with the following fields:

      - :Bitstep -- step in X sized steps (optional)
      - :Objectify -- if true, return IPAdmin::CIDR object (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • IP address or IPAdmin::CIDR object.

Example:

puts cidr4.next_ip()   --> 192.168.2.0


2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
# File 'lib/ip_admin.rb', line 2126

def next_ip(options=nil)
    bitstep = 1
    objectify = false
    short = false
    
    if (options)
        unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
        end
        
        if( options.has_key?(:Bitstep) )
            bitstep = options[:Bitstep]
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
    
        if( options.has_key?(:Objectify) )
            objectify = true
        end
    end
    
    next_ip = @network + @hostmask + bitstep
    
    unless (next_ip <= @all_f)
        raise "Returned IP is out of bounds for IPv#{@version}."
    end

    if (@version == 4)
        next_ip = IPAdmin.unpack_ipv4_addr(next_ip)
    else
        next_ip = IPAdmin.unpack_ipv6_addr(next_ip)
        next_ip = IPAdmin.shorten(next_ip) if (short && !objectify)
    end
    
    if (objectify)
        next_ip = IPAdmin::CIDR.new(:CIDR => next_ip)
    end
    
    return(next_ip)
end

#next_subnet(options = nil) ⇒ Object

Provide the next subnet following this CIDR object. The next subnet will be of the same size as the current CIDR object.

  • Arguments:

    • Optional Hash with the following fields:

      - :Bitstep -- step in X sized steps. (optional)
      - :Objectify -- if true, return IPAdmin::CIDR object (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • CIDR address or IPAdmin::CIDR object.

Example:

puts cidr4.next_subnet()   --> 192.168.2.0/24


2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
# File 'lib/ip_admin.rb', line 2194

def next_subnet(options=nil)
    bitstep = 1
    objectify = false
    short = false
    
    if (options)
        unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
        end
        
        if( options.has_key?(:Bitstep) )
            bitstep = options[:Bitstep]
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
    
        if( options.has_key?(:Objectify) )
            objectify = true
        end
    end
    
    bitstep = bitstep * (2**(@max_bits - self.bits) )
    next_sub = @network + bitstep
    
    unless (next_sub <= @all_f)
        raise "Returned subnet is out of bounds for IPv#{@version}."
    end

    if (@version == 4)
        next_sub = IPAdmin.unpack_ipv4_addr(next_sub)
    else
        next_sub = IPAdmin.unpack_ipv6_addr(next_sub)
        next_sub = IPAdmin.shorten(next_sub) if (short && !objectify)
    end
    
    next_sub = next_sub << "/" << self.bits.to_s        
    if (objectify)
        next_sub = IPAdmin::CIDR.new(:CIDR => next_sub)
    end
    
    return(next_sub)
end

#nth(options) ⇒ Object

Provide the nth IP within this object.

  • Arguments:

    • Hash with the following fields:

      - :Index -- index number of the IP address to return
      - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • IP address or IPAdmin::CIDR object.

Example:

puts cidr4.nth(:Index => 1)   --> 192.168.1.1


2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
# File 'lib/ip_admin.rb', line 2263

def nth(options)
    objectify = false
    short = false

    unless(options.kind_of?(Hash))
        raise Argumenterror, "Expected Hash, but " +
                             "#{options.class} provided."
    end
    
    unless( options.has_key?(:Index) )
        raise ArgumentError, "Missing argument: Index."
    end
    index = options[:Index]

    if( options.has_key?(:Short) )
        short = true
    end
    
    if( options.has_key?(:Objectify) )
            objectify = true
    end

    my_ip = @network + index
    if ( (@hostmask | my_ip) == (@hostmask | @network) )

        if (@version == 4)
            my_ip = IPAdmin.unpack_ipv4_addr(my_ip)
            if (objectify)
                my_ip = IPAdmin::CIDR.new(:CIDR => my_ip)
            end
        elsif (@version == 6)
            my_ip = IPAdmin.unpack_ipv6_addr(my_ip)
            my_ip = IPAdmin.shorten(my_ip) if (short && !objectify)
            if (objectify)
                my_ip = IPAdmin::CIDR.new(:CIDR => my_ip)
            end
        end

    else
        raise "Index of #{index} returns IP that is out of " +
              "bounds of CIDR network."
    end

    return(my_ip)
end

#packed_hostmaskObject

Provide an integer representing the packed Hostmask of this object.

  • Arguments:

    • none

  • Returns:

    • Byte-packed Hostmask.

Example:

puts cidr4.packed_hostmask().to_s(16)   --> ff


2329
2330
2331
# File 'lib/ip_admin.rb', line 2329

def packed_hostmask()
    return(@hostmask)
end

#packed_ipObject

Provide an integer representing the packed IP of this object.

  • Arguments:

    • none

  • Returns:

    • Byte-packed IP.

Example:

puts cidr4.packed_ip().to_s(16)   --> c0c80101


2353
2354
2355
# File 'lib/ip_admin.rb', line 2353

def packed_ip()
    return(@ip)
end

#packed_netmaskObject

Provide an integer representing the packed Netmask of this object.

  • Arguments:

    • none

  • Returns:

    • Byte-packed Netmask.

Example:

puts cidr4.packed_netmask().to_s(16)   --> ffffff00


2377
2378
2379
# File 'lib/ip_admin.rb', line 2377

def packed_netmask()
    return(@netmask)
end

#packed_networkObject

Provide an integer representing the packed Network address of this object.

  • Arguments:

    • none

  • Returns:

    • Byte-packed Network Address.

Example:

packed = cidr4.packed_network().to_s(16)   --> c0c80100


2401
2402
2403
# File 'lib/ip_admin.rb', line 2401

def packed_network()
    return(@network)
end

#range(options) ⇒ Object

Given two Indexes, return all IP addresses within the CIDR that are between them (inclusive).

  • Arguments:

    • Hash with the following fields:

      - :Bitstep -- enumerate in X sized steps (optional)
      - :Indexes -- array of (2) index numbers of the addresses to use as boundaries
      - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • Array of IP addresses or IPAdmin::CIDR objects

Example:

list = cidr4.range(:Indexes => [0,1]) --> ['192.168.1.0','192.168.1.1']


2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
# File 'lib/ip_admin.rb', line 2430

def range(options)
    objectify = false
    short = false
    bitstep = 1

    unless(options.kind_of?(Hash))
        raise Argumenterror, "Expected Hash, but #{options.class} provided."
    end
    
    unless( options.has_key?(:Indexes) )
        raise ArgumentError, "Missing argument: Indexes."
    end
    indexes = options[:Indexes]
    indexes.sort!
    
    unless( (indexes.kind_of?(Array)) && (indexes.length == 2))
        raise ArgumentError, "Argument :Index should be an array of (2) index numbers."
    end

    unless ( (indexes[0] >= 0) && (indexes[0] < self.size) )
        raise ArgumentError, "Index #{indexes[0]} is out of bounds for this CIDR."
    end
    
    unless (indexes[1] < self.size)
        raise ArgumentError, "Index #{indexes[1]} is out of bounds for this CIDR."
    end
    
    if( options.has_key?(:Short) )
        short = true
    end
    
    if( options.has_key?(:Objectify) )
        objectify = true
    end
    
    if( options.has_key?(:Bitstep) )
        bitstep = options[:Bitstep]
    end

    start_ip = @network + indexes[0]
    end_ip = @network + indexes[1]
    my_ip = start_ip
    list = []
    until (my_ip > end_ip)
        if (@version == 4)
            my_ip_s = IPAdmin.unpack_ipv4_addr(my_ip)
        elsif (@version == 6)
            my_ip_s = IPAdmin.unpack_ipv6_addr(my_ip)
            my_ip_s = IPAdmin.shorten(my_ip_s) if (short && !objectify)
        end
        
        if (objectify)
            my_ip_s = IPAdmin::CIDR.new(:CIDR => my_ip_s)
        end
        
        list.push(my_ip_s)
        my_ip += bitstep
    end

    return(list)
end

#remainder(options) ⇒ Object

Given a subnet of the current CIDR, provide the remaining subnets of the CIDR.

  • Arguments:

    • Optional hash with the following fields:

      - :Exclude -- IPAdmin::CIDR object to use in calculating the remainder.
      - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      
  • Returns:

    • Array of CIDR addresses or IPAdmin::CIDR objects

Example:

cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.64/26')
cidr4.remainder(:Exclude => cidr4_2).each {|x| puts}


2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
# File 'lib/ip_admin.rb', line 2518

def remainder(options)
    short = nil
    objectify = nil
    
    unless (options.kind_of? Hash)
        raise ArgumentError, "Expected Hash, but #{options.class} provided."
    end
        
    unless ( options.has_key?(:Exclude) )
        raise ArgumentError, "Missing argument: Exclude."
    end
    to_exclude = options[:Exclude]
        
    unless ( to_exclude.kind_of?(IPAdmin::CIDR) )
        raise ArgumentError, "Expeced IPAdmin::CIDR, but #{exclude.class} " +
                             "for option: Exclude."
    end
    
    if( options.has_key?(:Short) )
        short = true
    end
    
    if( options.has_key?(:Objectify) )
        objectify = true
    end
    
    # make sure 'to_exclude' is the same ip version
    unless ( to_exclude.version == @version )
        raise "#{to_exclude.desc(:Short => true)} is of a different " +
              "IP version than #{self.desc(:Short => true)}."
    end    

    # make sure we contain 'to_exclude'
    unless ( self.contains?(to_exclude) == true )
        raise "#{to_exclude.desc(:Short => true)} does not fit " +
              "within the bounds of #{self.desc(:Short => true)}."
    end

    # split this cidr in half & see which half 'to_exclude'
    # belongs in. take that half & repeat the process. every time
    # we repeat, store off the non-matching half
    new_mask = self.bits + 1
    lower_network = self.packed_network
    upper_network = self.packed_network + 2**(@max_bits - new_mask)
    
    new_subnets = []
    until(new_mask > to_exclude.bits)
        if (to_exclude.packed_network < upper_network)
            match = lower_network
            non_match = upper_network
        else
            match = upper_network
            non_match = lower_network
        end
        
        if (@version == 4)
            non_match = IPAdmin.unpack_ipv4_addr(non_match)
        else
            non_match = IPAdmin.unpack_ipv6_addr(non_match)
            non_match = IPAdmin.shorten(non_match) if (short && !objectify)
        end
        
        if (!objectify)
            new_subnets.unshift("#{non_match}/#{new_mask}")
        else
            new_subnets.unshift(IPAdmin::CIDR.new(:CIDR => "#{non_match}/#{new_mask}"))
        end
        
        new_mask = new_mask + 1
        lower_network = match
        upper_network = match + 2**(@max_bits - new_mask)
    end
    
    return(new_subnets)
end

#resize(options) ⇒ Object

Resize the CIDR by changing the size of the Netmask. Return the resulting CIDR as a new object.

  • Arguments:

    • Hash with the following fields:

      - :Subnet -- Number of bits of new Netmask (24,26, etc...)
      
  • Returns:

    • IPAdmin::CIDR object

Example:

new_cidr = cidr4.resize(:Subnet => 23)
puts new_cidr.desc   --> 192.168.1.0/23


2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
# File 'lib/ip_admin.rb', line 2617

def resize(options)
    unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
    end
        
    unless( options.has_key?(:Subnet) )
            raise Argumenterror, "Missing argument: Subnet."
    end
    bits = options[:Subnet]
    
    if (@version == 4)
        netmask = IPAdmin.validate_ipv4_netmask(bits)
        network = IPAdmin.unpack_ipv4_addr(@network & netmask)
    else
        netmask = IPAdmin.validate_ipv6_netmask(bits)
        network = IPAdmin.unpack_ipv6_addr(@network & netmask)
    end
    
    cidr = IPAdmin::CIDR.new(:CIDR => "#{network}/#{bits}")
    return(cidr)
end

#resize!(options) ⇒ Object

Resize this object by changing the size of the Netmask.

  • Arguments:

    • Hash with the following fields:

      - :Subnet -- Number of bits of new Netmask (24,26, etc...)
      
  • Returns:

    • IPAdmin::CIDR object

Note: If CIDR is resized such that the original IP is no longer contained within, then that IP will be reset to the base network address.

Example:

cidr4.resize!(:Subnet => 23)
puts cidr4.desc   --> 192.168.1.0/23


2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
# File 'lib/ip_admin.rb', line 2666

def resize!(options)
    unless(options.kind_of?(Hash))
            raise Argumenterror, "Expected Hash, but " +
                                 "#{options.class} provided."
    end
        
    unless( options.has_key?(:Subnet) )
            raise Argumenterror, "Missing argument: Subnet."
    end
    bits = options[:Subnet]
    
    if (@version == 4)
        netmask = IPAdmin.validate_ipv4_netmask(bits)
    else
        netmask = IPAdmin.validate_ipv6_netmask(bits)
    end
    
    @netmask = netmask
    @network = @network & netmask
    @hostmask = @netmask ^ @all_f
    
    # check @ip
    if ((@ip & @netmask) != (@network))
        @ip = @network
    end
    
    return(nil)
end

#sizeObject

Provide number of IP addresses within this object.

  • Arguments:

    • none

  • Returns:

    • Number of IP addresses in this CIDR block.

Example:

puts cidr4.size()   --> 256


2715
2716
2717
# File 'lib/ip_admin.rb', line 2715

def size()
    return(@hostmask + 1)
end

#subnet(options = nil) ⇒ Object

Subnet this object. Object will be fully subnetted into X number of subnets of specified size. If :MinCount is provided, then method will return at least that number of subnets (of size X). The remainder of the new subnets will be merged together as tightly as possible. If a size is not provided, then the current object will be split in half.

  • Arguments:

    • Optional hash with the following fields:

      - :IPCount -- Minimum number of IP's that new subnets should contain (optional)
      - :MinCount -- Minimum number of X sized subnets to return (optional)
      - :Objectify -- if true, return IPAdmin::CIDR objects (optional)
      - :Short -- if true, return IPv6 addresses in short-hand notation (optional)
      - :Subnet --  Netmask (in bits) of new subnets (optional)
      
  • Returns:

    • Array of CIDR addresses or IPAdmin::CIDR objects

Note:

:Subnet always takes precedence over :IPCount.

Example:

cidr_list = cidr4.subnet(:Subnet => 28, :MinCount => 3)
cidr_list = cidr4.subnet(:IPCount => 19)
puts cidr_list[0]   --> 192.168.1.0/27


2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
# File 'lib/ip_admin.rb', line 2753

def subnet(options=nil)
    my_network = self.packed_network
    my_mask = self.bits
    subnet_bits = my_mask + 1
    min_count = nil 
    objectify = false
    short = false       
    
    if (options)
        unless (options.kind_of? Hash)
            raise ArgumentError, "Expected Hash, but #{options.class} provided."
        end
        
        if ( options.has_key?(:IPCount) )
            num_ips = options[:IPCount]
            bits_needed = 0
            until (2**bits_needed >= num_ips)
                bits_needed += 1
            end
            subnet_bits = @max_bits - bits_needed
        end
        
        if ( options.has_key?(:Subnet) )
            subnet_bits = options[:Subnet]
        end
        
        if ( options.has_key?(:MinCount) )
            min_count = options[:MinCount]
        end
        
        if( options.has_key?(:Short) )
            short = true
        end
    
        if( options.has_key?(:Objectify) )
            objectify = true
        end
        
    end

    # get number of subnets possible with the requested subnet_bits
    num_avail = 2**(subnet_bits - my_mask)        

    # get the number of bits in the next supernet and
    # make sure min_count is a power of 2
    bits_needed = 1
    min_count = num_avail if (!min_count)
    until (2**bits_needed >= min_count)
        bits_needed += 1
    end
    min_count = 2**bits_needed
    next_supernet_bits = subnet_bits - bits_needed
    

    # make sure subnet isnt bigger than available bits
    if (subnet_bits > @max_bits)
        raise "Requested subnet (#{subnet_bits}) does not fit " +
              "within the bounds of IPv#{@version}."
    end

    # make sure subnet is larger than mymask
    if (subnet_bits < my_mask)
        raise "Requested subnet (#{subnet_bits}) is too large for " +
              "current CIDR space."
    end

    # make sure MinCount is smaller than available subnets
    if (min_count > num_avail)
        raise "Requested subnet count (#{min_count}) exceeds subnets " +
              "available for allocation (#{num_avail})."
    end

    # list all 'subnet_bits' sized subnets of this cidr block
    # with a limit of min_count
    bitstep = 2**(@max_bits - subnet_bits)
    subnets = self.enumerate(:Bitstep => bitstep, :Limit => min_count)

    # turn the first min_count subnets into IPAdmin::CIDR
    # objects and push them to new_subnets
    new_subnets = []
    subnets.each do |subnet|
        subnet = IPAdmin.shorten(subnet) if ((@version == 6) && short && !objectify)
        if (!objectify)
            new_subnets.push("#{subnet}/#{subnet_bits}")
        else            
            new_subnets.push(IPAdmin::CIDR.new(:CIDR => "#{subnet}/#{subnet_bits}"))
        end
    end

    # now go through the rest of the cidr space and make the rest
    # of the subnets. we want these to be as tightly merged as possible
    next_supernet_bitstep = (bitstep * min_count)
    next_supernet_ip = my_network + next_supernet_bitstep
    until (next_supernet_bits == my_mask)
        if (@version == 4)
            next_network = IPAdmin.unpack_ipv4_addr(next_supernet_ip)
        else
            next_network = IPAdmin.unpack_ipv6_addr(next_supernet_ip)
            next_network = IPAdmin.shorten(next_network) if (short && !objectify)
        end
        
        if (!objectify)
            new_subnets.push("#{next_network}/#{next_supernet_bits}")
        else
            new_subnets.push(IPAdmin::CIDR.new(:CIDR => "#{next_network}/#{next_supernet_bits}"))
        end
        
        next_supernet_bits -= 1
        next_supernet_ip = next_supernet_ip + next_supernet_bitstep
        next_supernet_bitstep = next_supernet_bitstep << 1
    end

    return(new_subnets)
end