ipaddress 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +73 -0
- data/README.rdoc +120 -86
- data/Rakefile +7 -15
- data/VERSION +1 -1
- data/lib/ipaddress.rb +131 -15
- data/lib/ipaddress/extensions/extensions.rb +8 -2
- data/lib/ipaddress/ipv4.rb +132 -49
- data/lib/ipaddress/ipv6.rb +64 -18
- data/lib/ipaddress/prefix.rb +38 -1
- data/test/ipaddress/ipv4_test.rb +92 -38
- data/test/ipaddress/ipv6_test.rb +34 -10
- data/test/ipaddress/prefix_test.rb +15 -0
- data/test/ipaddress_test.rb +17 -0
- data/test/test_helper.rb +0 -5
- metadata +11 -25
- data/lib/ipaddress/ipbase.rb +0 -83
- data/test/ipaddress/ipbase_test.rb +0 -28
    
        data/Rakefile
    CHANGED
    
    | @@ -1,8 +1,6 @@ | |
| 1 1 | 
             
            require 'rubygems'
         | 
| 2 2 | 
             
            require 'rake'
         | 
| 3 3 | 
             
            require 'rake/clean'
         | 
| 4 | 
            -
            require 'rcov/rcovtask'
         | 
| 5 | 
            -
             | 
| 6 4 |  | 
| 7 5 | 
             
            begin
         | 
| 8 6 | 
             
              require 'jeweler'
         | 
| @@ -12,9 +10,13 @@ begin | |
| 12 10 | 
             
                gem.email = "ceresa@gmail.com"
         | 
| 13 11 | 
             
                gem.homepage = "http://github.com/bluemonk/ipaddress"
         | 
| 14 12 | 
             
                gem.authors = ["Marco Ceresa"]
         | 
| 15 | 
            -
                 | 
| 13 | 
            +
                gem.description   = <<-EOD
         | 
| 14 | 
            +
                  IPAddress is a Ruby library designed to make manipulation 
         | 
| 15 | 
            +
                  of IPv4 and IPv6 addresses both powerful and simple. It mantains
         | 
| 16 | 
            +
                  a layer of compatibility with Ruby's own IPAddr, while 
         | 
| 17 | 
            +
                  addressing many of its issues.
         | 
| 18 | 
            +
                EOD
         | 
| 16 19 | 
             
              end
         | 
| 17 | 
            -
             | 
| 18 20 | 
             
            rescue LoadError
         | 
| 19 21 | 
             
              puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
         | 
| 20 22 | 
             
            end
         | 
| @@ -59,7 +61,7 @@ end | |
| 59 61 |  | 
| 60 62 | 
             
            desc "Open an irb session preloaded with this library"
         | 
| 61 63 | 
             
            task :console do
         | 
| 62 | 
            -
              sh " | 
| 64 | 
            +
              sh "irb1.9 -rubygems -I lib -r ipaddress.rb"
         | 
| 63 65 | 
             
            end
         | 
| 64 66 |  | 
| 65 67 | 
             
            desc "Look for TODO and FIXME tags in the code"
         | 
| @@ -79,13 +81,3 @@ task :todo do | |
| 79 81 | 
             
              end
         | 
| 80 82 | 
             
              egrep /(FIXME|TODO|TBD)/
         | 
| 81 83 | 
             
            end
         | 
| 82 | 
            -
             | 
| 83 | 
            -
            begin
         | 
| 84 | 
            -
              require 'jeweler'
         | 
| 85 | 
            -
              Jeweler::Tasks.new do |gemspec|
         | 
| 86 | 
            -
                # omitted for brevity
         | 
| 87 | 
            -
              end
         | 
| 88 | 
            -
              Jeweler::GemcutterTasks.new
         | 
| 89 | 
            -
            rescue LoadError
         | 
| 90 | 
            -
              puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
         | 
| 91 | 
            -
            end
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.6.0
         | 
    
        data/lib/ipaddress.rb
    CHANGED
    
    | @@ -1,9 +1,136 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # = IPAddress
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # A ruby library to manipulate IPv4 and IPv6 addresses
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            # Package::     IPAddress
         | 
| 8 | 
            +
            # Author::      Marco Ceresa <ceresa@ieee.org>
         | 
| 9 | 
            +
            # License::     Ruby License
         | 
| 10 | 
            +
            #
         | 
| 11 | 
            +
            #--
         | 
| 12 | 
            +
            #
         | 
| 13 | 
            +
            #++
         | 
| 3 14 |  | 
| 4 | 
            -
            require 'ipaddress/ipbase'
         | 
| 5 15 | 
             
            require 'ipaddress/ipv4'
         | 
| 6 16 | 
             
            require 'ipaddress/ipv6'
         | 
| 17 | 
            +
            require 'ipaddress/extensions/extensions'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 | 
            +
            module IPAddress
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              NAME            = "IPAddress"
         | 
| 23 | 
            +
              GEM             = "ipaddress"
         | 
| 24 | 
            +
              AUTHORS         = ["Marco Ceresa <ceresa@ieee.org>"]
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              # Parse the argument string to create a new
         | 
| 28 | 
            +
              # IPv4, IPv6 or Mapped IP object
         | 
| 29 | 
            +
              #
         | 
| 30 | 
            +
              #   ip  = IPAddress.parse "172.16.10.1/24"
         | 
| 31 | 
            +
              #   ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
         | 
| 32 | 
            +
              #   ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
         | 
| 33 | 
            +
              #
         | 
| 34 | 
            +
              # All the object created will be instances of the 
         | 
| 35 | 
            +
              # correct class:
         | 
| 36 | 
            +
              #
         | 
| 37 | 
            +
              #  ip.class
         | 
| 38 | 
            +
              #    #=> IPAddress::IPv4
         | 
| 39 | 
            +
              #  ip6.class
         | 
| 40 | 
            +
              #    #=> IPAddress::IPv6
         | 
| 41 | 
            +
              #  ip_mapped.class
         | 
| 42 | 
            +
              #    #=> IPAddress::IPv6::Mapped
         | 
| 43 | 
            +
              #
         | 
| 44 | 
            +
              def IPAddress::parse(str)
         | 
| 45 | 
            +
                case str
         | 
| 46 | 
            +
                when /:.+\./
         | 
| 47 | 
            +
                  IPAddress::IPv6::Mapped.new(str)
         | 
| 48 | 
            +
                else
         | 
| 49 | 
            +
                  begin
         | 
| 50 | 
            +
                    IPAddress::IPv4.new(str)
         | 
| 51 | 
            +
                  rescue ArgumentError
         | 
| 52 | 
            +
                    IPAddress::IPv6.new(str)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              # 
         | 
| 58 | 
            +
              # Checks if the given string is a valid IP address,
         | 
| 59 | 
            +
              # either IPv4 or IPv6
         | 
| 60 | 
            +
              #
         | 
| 61 | 
            +
              # Example:
         | 
| 62 | 
            +
              #
         | 
| 63 | 
            +
              #   IPAddress::valid? "2002::1"
         | 
| 64 | 
            +
              #     #=> true
         | 
| 65 | 
            +
              #
         | 
| 66 | 
            +
              #   IPAddress::valid? "10.0.0.256"   
         | 
| 67 | 
            +
              #     #=> false
         | 
| 68 | 
            +
              #
         | 
| 69 | 
            +
              def self.valid?(addr)
         | 
| 70 | 
            +
                valid_ipv4?(addr) || valid_ipv6?(addr)
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
              
         | 
| 73 | 
            +
              #
         | 
| 74 | 
            +
              # Checks if the given string is a valid IPv4 address
         | 
| 75 | 
            +
              #
         | 
| 76 | 
            +
              # Example:
         | 
| 77 | 
            +
              #
         | 
| 78 | 
            +
              #   IPAddress::valid_ipv4? "2002::1"
         | 
| 79 | 
            +
              #     #=> false
         | 
| 80 | 
            +
              #
         | 
| 81 | 
            +
              #   IPAddress::valid_ipv4? "172.16.10.1"
         | 
| 82 | 
            +
              #     #=> true
         | 
| 83 | 
            +
              #
         | 
| 84 | 
            +
              def self.valid_ipv4?(addr)
         | 
| 85 | 
            +
                if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
         | 
| 86 | 
            +
                  return $~.captures.all? {|i| i.to_i < 256}
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
                false
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
              
         | 
| 91 | 
            +
              #
         | 
| 92 | 
            +
              # Checks if the argument is a valid IPv4 netmask
         | 
| 93 | 
            +
              # expressed in dotted decimal format.
         | 
| 94 | 
            +
              #
         | 
| 95 | 
            +
              #   IPAddress.valid_ipv4_netmask? "255.255.0.0"
         | 
| 96 | 
            +
              #     #=> true
         | 
| 97 | 
            +
              #
         | 
| 98 | 
            +
              def self.valid_ipv4_netmask?(addr)
         | 
| 99 | 
            +
                arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
         | 
| 100 | 
            +
                arr.empty? && valid_ipv4?(addr)
         | 
| 101 | 
            +
              rescue
         | 
| 102 | 
            +
                return false
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
              
         | 
| 105 | 
            +
              #
         | 
| 106 | 
            +
              # Checks if the given string is a valid IPv6 address
         | 
| 107 | 
            +
              #
         | 
| 108 | 
            +
              # Example:
         | 
| 109 | 
            +
              #
         | 
| 110 | 
            +
              #   IPAddress::valid_ipv6? "2002::1"
         | 
| 111 | 
            +
              #     #=> true
         | 
| 112 | 
            +
              #
         | 
| 113 | 
            +
              #   IPAddress::valid_ipv6? "2002::DEAD::BEEF"
         | 
| 114 | 
            +
              #     #=> false
         | 
| 115 | 
            +
              #
         | 
| 116 | 
            +
              def self.valid_ipv6?(addr)
         | 
| 117 | 
            +
                # IPv6 (normal)
         | 
| 118 | 
            +
                return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
         | 
| 119 | 
            +
                return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
         | 
| 120 | 
            +
                return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
         | 
| 121 | 
            +
                # IPv6 (IPv4 compat)
         | 
| 122 | 
            +
                return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
         | 
| 123 | 
            +
                return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
         | 
| 124 | 
            +
                return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
         | 
| 125 | 
            +
                false
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              def self.deprecate(message = nil) # :nodoc:
         | 
| 129 | 
            +
                message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
         | 
| 130 | 
            +
                warn("DEPRECATION WARNING: #{message}")
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
              
         | 
| 133 | 
            +
            end # module IPAddress
         | 
| 7 134 |  | 
| 8 135 | 
             
            #
         | 
| 9 136 | 
             
            # IPAddress is a wrapper method built around 
         | 
| @@ -35,18 +162,7 @@ require 'ipaddress/ipv6' | |
| 35 162 | 
             
            #    #=> IPAddress::IPv6::Mapped
         | 
| 36 163 | 
             
            #
         | 
| 37 164 | 
             
            def IPAddress(str)
         | 
| 38 | 
            -
               | 
| 39 | 
            -
              when /:.+\./
         | 
| 40 | 
            -
                IPAddress::IPv6::Mapped.new(str)
         | 
| 41 | 
            -
              else
         | 
| 42 | 
            -
                begin
         | 
| 43 | 
            -
                  IPAddress::IPv4.new(str)
         | 
| 44 | 
            -
                rescue ArgumentError
         | 
| 45 | 
            -
                  IPAddress::IPv6.new(str)
         | 
| 46 | 
            -
                end
         | 
| 47 | 
            -
              end
         | 
| 165 | 
            +
              IPAddress::parse str
         | 
| 48 166 | 
             
            end
         | 
| 49 167 |  | 
| 50 168 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| @@ -2,13 +2,19 @@ class << Math | |
| 2 2 | 
             
              def log2(n); log(n) / log(2); end
         | 
| 3 3 | 
             
            end
         | 
| 4 4 |  | 
| 5 | 
            +
            if RUBY_VERSION =~ /1\.8/
         | 
| 6 | 
            +
                class Hash
         | 
| 7 | 
            +
                    alias :key :index
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 5 11 | 
             
            class Integer
         | 
| 6 12 | 
             
              def power_of_2?
         | 
| 7 13 | 
             
                Math::log2(self).to_i == Math::log2(self)
         | 
| 8 14 | 
             
              end
         | 
| 9 15 |  | 
| 10 | 
            -
              def closest_power_of_2
         | 
| 11 | 
            -
                self.upto( | 
| 16 | 
            +
              def closest_power_of_2(limit=32)
         | 
| 17 | 
            +
                self.upto(limit) do |i|
         | 
| 12 18 | 
             
                  return i if i.power_of_2?
         | 
| 13 19 | 
             
                end
         | 
| 14 20 | 
             
              end
         | 
    
        data/lib/ipaddress/ipv4.rb
    CHANGED
    
    | @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'ipaddress/ipbase'
         | 
| 2 1 | 
             
            require 'ipaddress/prefix'
         | 
| 3 2 |  | 
| 4 3 | 
             
            module IPAddress; 
         | 
| @@ -15,7 +14,7 @@ module IPAddress; | |
| 15 14 | 
             
              # 
         | 
| 16 15 | 
             
              # Class IPAddress::IPv4 is used to handle IPv4 type addresses. 
         | 
| 17 16 | 
             
              #
         | 
| 18 | 
            -
              class IPv4 | 
| 17 | 
            +
              class IPv4
         | 
| 19 18 |  | 
| 20 19 | 
             
                include IPAddress
         | 
| 21 20 | 
             
                include Enumerable  
         | 
| @@ -102,6 +101,7 @@ module IPAddress; | |
| 102 101 | 
             
                # as a string.
         | 
| 103 102 | 
             
                #
         | 
| 104 103 | 
             
                #   ip = IPAddress("172.16.100.4/22")
         | 
| 104 | 
            +
                #
         | 
| 105 105 | 
             
                #   ip.address
         | 
| 106 106 | 
             
                #     #=> "172.16.100.4"
         | 
| 107 107 | 
             
                #
         | 
| @@ -114,8 +114,10 @@ module IPAddress; | |
| 114 114 | 
             
                # as a IPAddress::Prefix32 object
         | 
| 115 115 | 
             
                #
         | 
| 116 116 | 
             
                #   ip = IPAddress("172.16.100.4/22")
         | 
| 117 | 
            +
                #
         | 
| 117 118 | 
             
                #   ip.prefix
         | 
| 118 119 | 
             
                #     #=> 22
         | 
| 120 | 
            +
                #
         | 
| 119 121 | 
             
                #   ip.prefix.class
         | 
| 120 122 | 
             
                #     #=> IPAddress::Prefix32
         | 
| 121 123 | 
             
                #
         | 
| @@ -132,10 +134,12 @@ module IPAddress; | |
| 132 134 | 
             
                # mask.
         | 
| 133 135 | 
             
                #
         | 
| 134 136 | 
             
                #   ip = IPAddress("172.16.100.4")
         | 
| 137 | 
            +
                #
         | 
| 135 138 | 
             
                #   puts ip
         | 
| 136 139 | 
             
                #     #=> 172.16.100.4/16
         | 
| 137 140 | 
             
                #   
         | 
| 138 141 | 
             
                #   ip.prefix = 22
         | 
| 142 | 
            +
                #
         | 
| 139 143 | 
             
                #   puts ip
         | 
| 140 144 | 
             
                #     #=> 172.16.100.4/22
         | 
| 141 145 | 
             
                #
         | 
| @@ -147,6 +151,7 @@ module IPAddress; | |
| 147 151 | 
             
                # Returns the address as an array of decimal values
         | 
| 148 152 | 
             
                #
         | 
| 149 153 | 
             
                #   ip = IPAddress("172.16.100.4")
         | 
| 154 | 
            +
                #
         | 
| 150 155 | 
             
                #   ip.octets
         | 
| 151 156 | 
             
                #     #=> [172, 16, 100, 4]
         | 
| 152 157 | 
             
                #
         | 
| @@ -154,22 +159,38 @@ module IPAddress; | |
| 154 159 | 
             
                  @octets
         | 
| 155 160 | 
             
                end
         | 
| 156 161 |  | 
| 162 | 
            +
                #
         | 
| 163 | 
            +
                # Returns a string with the address portion of 
         | 
| 164 | 
            +
                # the IPv4 object
         | 
| 165 | 
            +
                #
         | 
| 166 | 
            +
                #   ip = IPAddress("172.16.100.4/22")
         | 
| 167 | 
            +
                #
         | 
| 168 | 
            +
                #   ip.to_s
         | 
| 169 | 
            +
                #     #=> "172.16.100.4"
         | 
| 170 | 
            +
                #
         | 
| 171 | 
            +
                def to_s
         | 
| 172 | 
            +
                  @address
         | 
| 173 | 
            +
                end
         | 
| 174 | 
            +
             | 
| 157 175 | 
             
                #
         | 
| 158 176 | 
             
                # Returns a string with the IP address in canonical
         | 
| 159 177 | 
             
                # form.
         | 
| 160 178 | 
             
                #
         | 
| 161 179 | 
             
                #   ip = IPAddress("172.16.100.4/22")
         | 
| 162 | 
            -
                # | 
| 180 | 
            +
                #
         | 
| 181 | 
            +
                #   ip.to_string
         | 
| 163 182 | 
             
                #     #=> "172.16.100.4/22"
         | 
| 164 183 | 
             
                #
         | 
| 165 | 
            -
                def  | 
| 184 | 
            +
                def to_string
         | 
| 166 185 | 
             
                  "#@address/#@prefix"
         | 
| 167 186 | 
             
                end
         | 
| 168 187 |  | 
| 188 | 
            +
             | 
| 169 189 | 
             
                # 
         | 
| 170 190 | 
             
                # Returns the prefix as a string in IP format
         | 
| 171 191 | 
             
                #
         | 
| 172 192 | 
             
                #   ip = IPAddress("172.16.100.4/22")
         | 
| 193 | 
            +
                #
         | 
| 173 194 | 
             
                #   ip.netmask
         | 
| 174 195 | 
             
                #     #=> "255.255.252.0"
         | 
| 175 196 | 
             
                #
         | 
| @@ -183,10 +204,12 @@ module IPAddress; | |
| 183 204 | 
             
                # object.
         | 
| 184 205 | 
             
                #
         | 
| 185 206 | 
             
                #   ip = IPAddress("172.16.100.4")
         | 
| 207 | 
            +
                #
         | 
| 186 208 | 
             
                #   puts ip
         | 
| 187 209 | 
             
                #     #=> 172.16.100.4/16
         | 
| 188 210 | 
             
                #
         | 
| 189 211 | 
             
                #   ip.netmask = "255.255.252.0"
         | 
| 212 | 
            +
                #
         | 
| 190 213 | 
             
                #   puts ip
         | 
| 191 214 | 
             
                #     #=> 172.16.100.4/22
         | 
| 192 215 | 
             
                #
         | 
| @@ -203,6 +226,7 @@ module IPAddress; | |
| 203 226 | 
             
                # structure. 
         | 
| 204 227 | 
             
                #
         | 
| 205 228 | 
             
                #   ip = IPAddress("10.0.0.0/8")
         | 
| 229 | 
            +
                #
         | 
| 206 230 | 
             
                #   ip.to_u32
         | 
| 207 231 | 
             
                #     #=> 167772160
         | 
| 208 232 | 
             
                #
         | 
| @@ -216,6 +240,7 @@ module IPAddress; | |
| 216 240 | 
             
                # in a network byte order format.
         | 
| 217 241 | 
             
                #
         | 
| 218 242 | 
             
                #   ip = IPAddress("172.16.10.1/24")
         | 
| 243 | 
            +
                #
         | 
| 219 244 | 
             
                #   ip.data
         | 
| 220 245 | 
             
                #     #=> "\254\020\n\001"
         | 
| 221 246 | 
             
                #
         | 
| @@ -237,6 +262,7 @@ module IPAddress; | |
| 237 262 | 
             
                # Returns the octet specified by index
         | 
| 238 263 | 
             
                #
         | 
| 239 264 | 
             
                #   ip = IPAddress("172.16.100.50/24")
         | 
| 265 | 
            +
                #
         | 
| 240 266 | 
             
                #   ip[0]
         | 
| 241 267 | 
             
                #     #=> 172
         | 
| 242 268 | 
             
                #   ip[1]
         | 
| @@ -256,6 +282,7 @@ module IPAddress; | |
| 256 282 | 
             
                # as a string containing a sequence of 0 and 1
         | 
| 257 283 | 
             
                #
         | 
| 258 284 | 
             
                #   ip = IPAddress("127.0.0.1")
         | 
| 285 | 
            +
                #
         | 
| 259 286 | 
             
                #   ip.bits
         | 
| 260 287 | 
             
                #     #=> "01111111000000000000000000000001"
         | 
| 261 288 | 
             
                #
         | 
| @@ -267,8 +294,9 @@ module IPAddress; | |
| 267 294 | 
             
                # Returns the broadcast address for the given IP.
         | 
| 268 295 | 
             
                #
         | 
| 269 296 | 
             
                #   ip = IPAddress("172.16.10.64/24")
         | 
| 297 | 
            +
                #
         | 
| 270 298 | 
             
                #   ip.broadcast.to_s
         | 
| 271 | 
            -
                #     #=> "172.16.10.255 | 
| 299 | 
            +
                #     #=> "172.16.10.255"
         | 
| 272 300 | 
             
                #
         | 
| 273 301 | 
             
                def broadcast
         | 
| 274 302 | 
             
                  self.class.parse_u32(broadcast_u32, @prefix)
         | 
| @@ -278,10 +306,12 @@ module IPAddress; | |
| 278 306 | 
             
                # Checks if the IP address is actually a network
         | 
| 279 307 | 
             
                #
         | 
| 280 308 | 
             
                #   ip = IPAddress("172.16.10.64/24")
         | 
| 309 | 
            +
                #
         | 
| 281 310 | 
             
                #   ip.network?
         | 
| 282 311 | 
             
                #     #=> false
         | 
| 283 312 | 
             
                # 
         | 
| 284 313 | 
             
                #   ip = IPAddress("172.16.10.64/26")
         | 
| 314 | 
            +
                #
         | 
| 285 315 | 
             
                #   ip.network?
         | 
| 286 316 | 
             
                #     #=> true
         | 
| 287 317 | 
             
                #
         | 
| @@ -294,8 +324,9 @@ module IPAddress; | |
| 294 324 | 
             
                # for the given IP.
         | 
| 295 325 | 
             
                #
         | 
| 296 326 | 
             
                #   ip = IPAddress("172.16.10.64/24")
         | 
| 327 | 
            +
                #
         | 
| 297 328 | 
             
                #   ip.network.to_s
         | 
| 298 | 
            -
                #     #=> "172.16.10.0 | 
| 329 | 
            +
                #     #=> "172.16.10.0"
         | 
| 299 330 | 
             
                #
         | 
| 300 331 | 
             
                def network
         | 
| 301 332 | 
             
                  self.class.parse_u32(network_u32, @prefix)
         | 
| @@ -309,15 +340,17 @@ module IPAddress; | |
| 309 340 | 
             
                # host IP address is 192.168.100.1.
         | 
| 310 341 | 
             
                #
         | 
| 311 342 | 
             
                #   ip = IPAddress("192.168.100.0/24")
         | 
| 343 | 
            +
                #
         | 
| 312 344 | 
             
                #   ip.first.to_s
         | 
| 313 | 
            -
                #     #=> "192.168.100.1 | 
| 345 | 
            +
                #     #=> "192.168.100.1"
         | 
| 314 346 | 
             
                #
         | 
| 315 347 | 
             
                # The object IP doesn't need to be a network: the method
         | 
| 316 348 | 
             
                # automatically gets the network number from it
         | 
| 317 349 | 
             
                #
         | 
| 318 350 | 
             
                #   ip = IPAddress("192.168.100.50/24")
         | 
| 351 | 
            +
                #
         | 
| 319 352 | 
             
                #   ip.first.to_s
         | 
| 320 | 
            -
                #     #=> "192.168.100.1 | 
| 353 | 
            +
                #     #=> "192.168.100.1"
         | 
| 321 354 | 
             
                #
         | 
| 322 355 | 
             
                def first
         | 
| 323 356 | 
             
                  self.class.parse_u32(network_u32+1, @prefix)
         | 
| @@ -329,18 +362,20 @@ module IPAddress; | |
| 329 362 | 
             
                # last host IP address in the range.
         | 
| 330 363 | 
             
                # 
         | 
| 331 364 | 
             
                # Example: given the 192.168.100.0/24 network, the last
         | 
| 332 | 
            -
                # host IP address is 192.168.100. | 
| 365 | 
            +
                # host IP address is 192.168.100.254
         | 
| 333 366 | 
             
                #
         | 
| 334 367 | 
             
                #   ip = IPAddress("192.168.100.0/24")
         | 
| 368 | 
            +
                #
         | 
| 335 369 | 
             
                #   ip.last.to_s
         | 
| 336 | 
            -
                #     #=> "192.168.100.254 | 
| 370 | 
            +
                #     #=> "192.168.100.254"
         | 
| 337 371 | 
             
                #
         | 
| 338 372 | 
             
                # The object IP doesn't need to be a network: the method
         | 
| 339 373 | 
             
                # automatically gets the network number from it
         | 
| 340 374 | 
             
                #
         | 
| 341 375 | 
             
                #   ip = IPAddress("192.168.100.50/24")
         | 
| 376 | 
            +
                #
         | 
| 342 377 | 
             
                #   ip.last.to_s
         | 
| 343 | 
            -
                #     #=> "192.168.100.254 | 
| 378 | 
            +
                #     #=> "192.168.100.254"
         | 
| 344 379 | 
             
                #
         | 
| 345 380 | 
             
                def last
         | 
| 346 381 | 
             
                  self.class.parse_u32(broadcast_u32-1, @prefix)
         | 
| @@ -350,9 +385,10 @@ module IPAddress; | |
| 350 385 | 
             
                # Iterates over all the hosts IP addresses for the given
         | 
| 351 386 | 
             
                # network (or IP address).
         | 
| 352 387 | 
             
                #
         | 
| 353 | 
            -
                #   ip =  | 
| 388 | 
            +
                #   ip = IPAddress("10.0.0.1/29")
         | 
| 389 | 
            +
                #
         | 
| 354 390 | 
             
                #   ip.each do |i|
         | 
| 355 | 
            -
                #     p i
         | 
| 391 | 
            +
                #     p i.to_s
         | 
| 356 392 | 
             
                #   end
         | 
| 357 393 | 
             
                #     #=> "10.0.0.1"
         | 
| 358 394 | 
             
                #     #=> "10.0.0.2"
         | 
| @@ -374,7 +410,8 @@ module IPAddress; | |
| 374 410 | 
             
                # The object yielded is a new IPv4 object created
         | 
| 375 411 | 
             
                # from the iteration.
         | 
| 376 412 | 
             
                #
         | 
| 377 | 
            -
                #   ip =  | 
| 413 | 
            +
                #   ip = IPAddress("10.0.0.1/29")
         | 
| 414 | 
            +
                #
         | 
| 378 415 | 
             
                #   ip.each do |i|
         | 
| 379 416 | 
             
                #     p i.address
         | 
| 380 417 | 
             
                #   end
         | 
| @@ -406,8 +443,8 @@ module IPAddress; | |
| 406 443 | 
             
                # Example:
         | 
| 407 444 | 
             
                #
         | 
| 408 445 | 
             
                #   ip1 = IPAddress "10.100.100.1/8"
         | 
| 409 | 
            -
                #   ip2 = IPAddress " | 
| 410 | 
            -
                #   ip3 = IPAddress " | 
| 446 | 
            +
                #   ip2 = IPAddress "172.16.0.1/16"
         | 
| 447 | 
            +
                #   ip3 = IPAddress "10.100.100.1/16"
         | 
| 411 448 | 
             
                #
         | 
| 412 449 | 
             
                #   ip1 < ip2
         | 
| 413 450 | 
             
                #     #=> true
         | 
| @@ -434,7 +471,8 @@ module IPAddress; | |
| 434 471 | 
             
                # in the network. It also counts the network
         | 
| 435 472 | 
             
                # address and the broadcast address.
         | 
| 436 473 | 
             
                #
         | 
| 437 | 
            -
                #   ip =  | 
| 474 | 
            +
                #   ip = IPAddress("10.0.0.1/29")
         | 
| 475 | 
            +
                #
         | 
| 438 476 | 
             
                #   ip.size
         | 
| 439 477 | 
             
                #     #=> 8
         | 
| 440 478 | 
             
                #
         | 
| @@ -446,7 +484,8 @@ module IPAddress; | |
| 446 484 | 
             
                # Returns an array with the IP addresses of
         | 
| 447 485 | 
             
                # all the hosts in the network.
         | 
| 448 486 | 
             
                # 
         | 
| 449 | 
            -
                #   ip =  | 
| 487 | 
            +
                #   ip = IPAddress("10.0.0.1/29")
         | 
| 488 | 
            +
                #
         | 
| 450 489 | 
             
                #   ip.hosts.map {|i| i.address}
         | 
| 451 490 | 
             
                #     #=> ["10.0.0.1",
         | 
| 452 491 | 
             
                #     #=>  "10.0.0.2",
         | 
| @@ -462,7 +501,8 @@ module IPAddress; | |
| 462 501 | 
             
                #
         | 
| 463 502 | 
             
                # Returns the network number in Unsigned 32bits format
         | 
| 464 503 | 
             
                #
         | 
| 465 | 
            -
                #   ip =  | 
| 504 | 
            +
                #   ip = IPAddress("10.0.0.1/29")
         | 
| 505 | 
            +
                #
         | 
| 466 506 | 
             
                #   ip.network_u32
         | 
| 467 507 | 
             
                #     #=> 167772160
         | 
| 468 508 | 
             
                #
         | 
| @@ -474,6 +514,7 @@ module IPAddress; | |
| 474 514 | 
             
                # Returns the broadcast address in Unsigned 32bits format
         | 
| 475 515 | 
             
                #
         | 
| 476 516 | 
             
                #   ip = IPaddress("10.0.0.1/29")
         | 
| 517 | 
            +
                #
         | 
| 477 518 | 
             
                #   ip.broadcast_u32
         | 
| 478 519 | 
             
                #     #=> 167772167
         | 
| 479 520 | 
             
                #
         | 
| @@ -490,6 +531,7 @@ module IPAddress; | |
| 490 531 | 
             
                #   ip = IPAddress("192.168.10.100/24")
         | 
| 491 532 | 
             
                #
         | 
| 492 533 | 
             
                #   addr = IPAddress("192.168.10.102/24")
         | 
| 534 | 
            +
                #
         | 
| 493 535 | 
             
                #   ip.include? addr
         | 
| 494 536 | 
             
                #     #=> true
         | 
| 495 537 | 
             
                #
         | 
| @@ -505,12 +547,14 @@ module IPAddress; | |
| 505 547 | 
             
                # for DNS lookups
         | 
| 506 548 | 
             
                #
         | 
| 507 549 | 
             
                #   ip = IPAddress("172.16.100.50/24")
         | 
| 550 | 
            +
                #
         | 
| 508 551 | 
             
                #   ip.reverse
         | 
| 509 552 | 
             
                #     #=> "50.100.16.172.in-addr.arpa"
         | 
| 510 553 | 
             
                #
         | 
| 511 554 | 
             
                def reverse
         | 
| 512 555 | 
             
                  @octets.reverse.join(".") + ".in-addr.arpa"
         | 
| 513 556 | 
             
                end
         | 
| 557 | 
            +
                alias_method :arpa, :reverse
         | 
| 514 558 |  | 
| 515 559 | 
             
                #
         | 
| 516 560 | 
             
                # Subnetting a network
         | 
| @@ -524,7 +568,8 @@ module IPAddress; | |
| 524 568 | 
             
                # networks will be divided evenly from the supernet.
         | 
| 525 569 | 
             
                #
         | 
| 526 570 | 
             
                #   network = IPAddress("172.16.10.0/24")
         | 
| 527 | 
            -
                # | 
| 571 | 
            +
                #
         | 
| 572 | 
            +
                #   network / 4   # implies map{|i| i.to_string}
         | 
| 528 573 | 
             
                #     #=> ["172.16.10.0/26",
         | 
| 529 574 | 
             
                #          "172.16.10.64/26",
         | 
| 530 575 | 
             
                #          "172.16.10.128/26",
         | 
| @@ -535,7 +580,8 @@ module IPAddress; | |
| 535 580 | 
             
                # other networks with the remaining addresses.
         | 
| 536 581 | 
             
                #
         | 
| 537 582 | 
             
                #   network = IPAddress("172.16.10.0/24")
         | 
| 538 | 
            -
                # | 
| 583 | 
            +
                #
         | 
| 584 | 
            +
                #   network / 3   # implies map{|i| i.to_string}
         | 
| 539 585 | 
             
                #     #=> ["172.16.10.0/26",
         | 
| 540 586 | 
             
                #          "172.16.10.64/26",
         | 
| 541 587 | 
             
                #          "172.16.10.128/25"]
         | 
| @@ -546,7 +592,6 @@ module IPAddress; | |
| 546 592 | 
             
                  unless (1..(2**(32-prefix.to_i))).include? subnets
         | 
| 547 593 | 
             
                    raise ArgumentError, "Value #{subnets} out of range" 
         | 
| 548 594 | 
             
                  end
         | 
| 549 | 
            -
             | 
| 550 595 | 
             
                  calculate_subnets(subnets)
         | 
| 551 596 | 
             
                end
         | 
| 552 597 | 
             
                alias_method :/, :subnet
         | 
| @@ -564,13 +609,13 @@ module IPAddress; | |
| 564 609 | 
             
                #
         | 
| 565 610 | 
             
                # you can supernet it with a new /23 prefix
         | 
| 566 611 | 
             
                #
         | 
| 567 | 
            -
                #   ip.supernet(23). | 
| 612 | 
            +
                #   ip.supernet(23).to_string
         | 
| 568 613 | 
             
                #     #=> "172.16.10.0/23"
         | 
| 569 614 | 
             
                #
         | 
| 570 615 | 
             
                # However if you supernet it with a /22 prefix, the
         | 
| 571 616 | 
             
                # network address will change:
         | 
| 572 617 | 
             
                #
         | 
| 573 | 
            -
                #   ip.supernet(22). | 
| 618 | 
            +
                #   ip.supernet(22).to_string
         | 
| 574 619 | 
             
                #     #=> "172.16.8.0/22"
         | 
| 575 620 | 
             
                # 
         | 
| 576 621 | 
             
                def supernet(new_prefix)
         | 
| @@ -583,6 +628,14 @@ module IPAddress; | |
| 583 628 | 
             
                # Returns the difference between two IP addresses
         | 
| 584 629 | 
             
                # in unsigned int 32 bits format
         | 
| 585 630 | 
             
                #  
         | 
| 631 | 
            +
                # Example:
         | 
| 632 | 
            +
                #
         | 
| 633 | 
            +
                #   ip1 = IPAddress("172.16.10.0/24")
         | 
| 634 | 
            +
                #   ip2 = IPAddress("172.16.11.0/24")
         | 
| 635 | 
            +
                #
         | 
| 636 | 
            +
                #   puts ip1 - ip2
         | 
| 637 | 
            +
                #     #=> 256
         | 
| 638 | 
            +
                #
         | 
| 586 639 | 
             
                def -(oth)
         | 
| 587 640 | 
             
                  return (to_u32 - oth.to_u32).abs
         | 
| 588 641 | 
             
                end
         | 
| @@ -596,14 +649,21 @@ module IPAddress; | |
| 596 649 | 
             
                #
         | 
| 597 650 | 
             
                #   ip1 = IPAddress("172.16.10.1/24")
         | 
| 598 651 | 
             
                #   ip2 = IPAddress("172.16.11.2/24")
         | 
| 599 | 
            -
                # | 
| 600 | 
            -
                # | 
| 652 | 
            +
                #
         | 
| 653 | 
            +
                #   p (ip1 + ip2).map {|i| i.to_string}
         | 
| 654 | 
            +
                #     #=> ["172.16.10.0/23"]
         | 
| 601 655 | 
             
                #
         | 
| 602 656 | 
             
                # If the networks are not contiguous, returns
         | 
| 603 657 | 
             
                # the two network numbers from the objects
         | 
| 604 658 | 
             
                #
         | 
| 659 | 
            +
                #   ip1 = IPAddress("10.0.0.1/24")
         | 
| 660 | 
            +
                #   ip2 = IPAddress("10.0.2.1/24")
         | 
| 661 | 
            +
                #
         | 
| 662 | 
            +
                #   p (ip1 + ip2).map {|i| i.to_string}
         | 
| 663 | 
            +
                #     #=> ["10.0.0.0/24","10.0.2.0/24"]
         | 
| 664 | 
            +
                #
         | 
| 605 665 | 
             
                def +(oth)
         | 
| 606 | 
            -
                   | 
| 666 | 
            +
                  aggregate(*[self,oth].sort.map{|i| i.network})
         | 
| 607 667 | 
             
                end
         | 
| 608 668 |  | 
| 609 669 | 
             
                #
         | 
| @@ -614,11 +674,12 @@ module IPAddress; | |
| 614 674 | 
             
                # Example:
         | 
| 615 675 | 
             
                # 
         | 
| 616 676 | 
             
                #   ip = IPAddress("10.0.0.1/24")
         | 
| 677 | 
            +
                #
         | 
| 617 678 | 
             
                #   ip.a?
         | 
| 618 679 | 
             
                #     #=> true
         | 
| 619 680 | 
             
                #
         | 
| 620 681 | 
             
                def a?
         | 
| 621 | 
            -
                  CLASSFUL. | 
| 682 | 
            +
                  CLASSFUL.key(8) === bits
         | 
| 622 683 | 
             
                end
         | 
| 623 684 |  | 
| 624 685 | 
             
                #
         | 
| @@ -629,11 +690,12 @@ module IPAddress; | |
| 629 690 | 
             
                # Example:
         | 
| 630 691 | 
             
                #
         | 
| 631 692 | 
             
                #   ip = IPAddress("172.16.10.1/24")
         | 
| 693 | 
            +
                #
         | 
| 632 694 | 
             
                #   ip.b?
         | 
| 633 695 | 
             
                #     #=> true
         | 
| 634 696 | 
             
                #
         | 
| 635 697 | 
             
                def b?
         | 
| 636 | 
            -
                  CLASSFUL. | 
| 698 | 
            +
                  CLASSFUL.key(16) === bits
         | 
| 637 699 | 
             
                end
         | 
| 638 700 |  | 
| 639 701 | 
             
                #
         | 
| @@ -644,11 +706,12 @@ module IPAddress; | |
| 644 706 | 
             
                # Example:
         | 
| 645 707 | 
             
                #
         | 
| 646 708 | 
             
                #   ip = IPAddress("192.168.1.1/30")
         | 
| 709 | 
            +
                #
         | 
| 647 710 | 
             
                #   ip.c?
         | 
| 648 711 | 
             
                #     #=> true
         | 
| 649 712 | 
             
                #
         | 
| 650 713 | 
             
                def c?
         | 
| 651 | 
            -
                  CLASSFUL. | 
| 714 | 
            +
                  CLASSFUL.key(24) === bits
         | 
| 652 715 | 
             
                end
         | 
| 653 716 |  | 
| 654 717 | 
             
                #
         | 
| @@ -658,6 +721,7 @@ module IPAddress; | |
| 658 721 | 
             
                # Example:
         | 
| 659 722 | 
             
                #
         | 
| 660 723 | 
             
                #   ip = IPAddress("172.16.10.1/24")
         | 
| 724 | 
            +
                #
         | 
| 661 725 | 
             
                #   ip.to_ipv6
         | 
| 662 726 | 
             
                #     #=> "ac10:0a01"
         | 
| 663 727 | 
             
                #
         | 
| @@ -670,14 +734,16 @@ module IPAddress; | |
| 670 734 | 
             
                # unsigned 32bits integer.
         | 
| 671 735 | 
             
                #
         | 
| 672 736 | 
             
                #   ip = IPAddress::IPv4::parse_u32(167772160)
         | 
| 737 | 
            +
                #
         | 
| 673 738 | 
             
                #   ip.prefix = 8
         | 
| 674 | 
            -
                #   ip. | 
| 739 | 
            +
                #   ip.to_string
         | 
| 675 740 | 
             
                #     #=> "10.0.0.0/8"
         | 
| 676 741 | 
             
                #
         | 
| 677 742 | 
             
                # The +prefix+ parameter is optional:
         | 
| 678 743 | 
             
                #
         | 
| 679 744 | 
             
                #   ip = IPAddress::IPv4::parse_u32(167772160, 8)
         | 
| 680 | 
            -
                # | 
| 745 | 
            +
                #
         | 
| 746 | 
            +
                #   ip.to_string
         | 
| 681 747 | 
             
                #     #=> "10.0.0.0/8"
         | 
| 682 748 | 
             
                #
         | 
| 683 749 | 
             
                def self.parse_u32(u32, prefix=nil)
         | 
| @@ -699,7 +765,7 @@ module IPAddress; | |
| 699 765 | 
             
                #   ip = IPAddress::IPv4::parse_data "\254\020\n\001"
         | 
| 700 766 | 
             
                #   ip.prefix = 24
         | 
| 701 767 | 
             
                #
         | 
| 702 | 
            -
                #   ip. | 
| 768 | 
            +
                #   ip.to_string
         | 
| 703 769 | 
             
                #     #=> "172.16.10.1/24"
         | 
| 704 770 | 
             
                #
         | 
| 705 771 | 
             
                def self.parse_data(str)
         | 
| @@ -713,10 +779,10 @@ module IPAddress; | |
| 713 779 | 
             
                # Example:
         | 
| 714 780 | 
             
                #
         | 
| 715 781 | 
             
                #   str = "foobar172.16.10.1barbaz"
         | 
| 716 | 
            -
                #   ip =  | 
| 782 | 
            +
                #   ip = IPAddress::IPv4::extract str
         | 
| 717 783 | 
             
                #
         | 
| 718 784 | 
             
                #   ip.to_s
         | 
| 719 | 
            -
                #     #=> "172.16.10.1 | 
| 785 | 
            +
                #     #=> "172.16.10.1"
         | 
| 720 786 | 
             
                #
         | 
| 721 787 | 
             
                def self.extract(str)
         | 
| 722 788 | 
             
                  self.new REGEXP.match(str).to_s
         | 
| @@ -770,7 +836,8 @@ module IPAddress; | |
| 770 836 | 
             
                #   ip2 = IPAddress("10.0.1.1/24")
         | 
| 771 837 | 
             
                #   ip3 = IPAddress("10.0.2.1/24")
         | 
| 772 838 | 
             
                #   ip4 = IPAddress("10.0.3.1/24")
         | 
| 773 | 
            -
                # | 
| 839 | 
            +
                #
         | 
| 840 | 
            +
                #   IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
         | 
| 774 841 | 
             
                #     #=> "10.0.0.0/22", 
         | 
| 775 842 | 
             
                #
         | 
| 776 843 | 
             
                # But the following networks can't be summarized in a single network:
         | 
| @@ -779,27 +846,28 @@ module IPAddress; | |
| 779 846 | 
             
                #   ip2 = IPAddress("10.0.2.1/24")
         | 
| 780 847 | 
             
                #   ip3 = IPAddress("10.0.3.1/24")
         | 
| 781 848 | 
             
                #   ip4 = IPAddress("10.0.4.1/24")
         | 
| 782 | 
            -
                # | 
| 849 | 
            +
                #
         | 
| 850 | 
            +
                #   IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
         | 
| 783 851 | 
             
                #     #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
         | 
| 784 852 | 
             
                #
         | 
| 785 853 | 
             
                def self.summarize(*args)
         | 
| 786 854 | 
             
                  # one network? no need to summarize
         | 
| 787 | 
            -
                  return args. | 
| 855 | 
            +
                  return [args.first.network] if args.size == 1
         | 
| 788 856 |  | 
| 789 | 
            -
                   | 
| 790 | 
            -
                   | 
| 791 | 
            -
             | 
| 792 | 
            -
                     | 
| 793 | 
            -
             | 
| 794 | 
            -
                     | 
| 795 | 
            -
                      result << x.network unless result.any?{|i| i.include? x}
         | 
| 796 | 
            -
                    end
         | 
| 857 | 
            +
                  i = 0
         | 
| 858 | 
            +
                  result = args.dup.sort.map{|ip| ip.network}
         | 
| 859 | 
            +
                  while i < result.size-1
         | 
| 860 | 
            +
                    sum = result[i] + result[i+1]
         | 
| 861 | 
            +
                    result[i..i+1] = sum.first if sum.size == 1
         | 
| 862 | 
            +
                    i += 1
         | 
| 797 863 | 
             
                  end
         | 
| 798 | 
            -
                  result << last unless result.any?{|i| i.include? last}
         | 
| 799 864 |  | 
| 865 | 
            +
                  result.flatten!
         | 
| 800 866 | 
             
                  if result.size == args.size
         | 
| 867 | 
            +
                    # nothing more to summarize
         | 
| 801 868 | 
             
                    return result
         | 
| 802 869 | 
             
                  else
         | 
| 870 | 
            +
                    # keep on summarizing
         | 
| 803 871 | 
             
                    return self.summarize(*result)
         | 
| 804 872 | 
             
                  end
         | 
| 805 873 | 
             
                end
         | 
| @@ -815,12 +883,12 @@ module IPAddress; | |
| 815 883 |  | 
| 816 884 | 
             
                def prefix_from_ip(ip)
         | 
| 817 885 | 
             
                  bits = bits_from_address(ip)
         | 
| 818 | 
            -
                  CLASSFUL.each {|reg,prefix| return prefix if bits =~ reg}
         | 
| 886 | 
            +
                  CLASSFUL.each {|reg,prefix| return Prefix32.new(prefix) if bits =~ reg}
         | 
| 819 887 | 
             
                end
         | 
| 820 888 |  | 
| 821 889 | 
             
                def calculate_subnets(subnets)
         | 
| 822 890 | 
             
                  po2 = subnets.closest_power_of_2
         | 
| 823 | 
            -
                  new_prefix = @prefix | 
| 891 | 
            +
                  new_prefix = @prefix + Math::log2(po2).to_i
         | 
| 824 892 | 
             
                  networks = Array.new
         | 
| 825 893 | 
             
                  (0..po2-1).each do |i|
         | 
| 826 894 | 
             
                    mul = i * (2**(32-new_prefix))
         | 
| @@ -843,6 +911,21 @@ module IPAddress; | |
| 843 911 | 
             
                  end
         | 
| 844 912 | 
             
                  return dup.reverse
         | 
| 845 913 | 
             
                end
         | 
| 914 | 
            +
             | 
| 915 | 
            +
                def aggregate(ip1,ip2)
         | 
| 916 | 
            +
                  if ip1.include? ip2
         | 
| 917 | 
            +
                    return [ip1]
         | 
| 918 | 
            +
                  else
         | 
| 919 | 
            +
                    snet = ip1.supernet(ip1.prefix-1)
         | 
| 920 | 
            +
                    arr1 = ip1.subnet(2**(ip2.prefix-ip1.prefix)).map{|i| i.to_string}
         | 
| 921 | 
            +
                    arr2 = snet.subnet(2**(ip2.prefix-snet.prefix)).map{|i| i.to_string} 
         | 
| 922 | 
            +
                    if (arr2 - [ip2.to_string] - arr1).empty?
         | 
| 923 | 
            +
                      return [snet]
         | 
| 924 | 
            +
                    else
         | 
| 925 | 
            +
                      return [ip1, ip2]
         | 
| 926 | 
            +
                    end
         | 
| 927 | 
            +
                  end
         | 
| 928 | 
            +
                end
         | 
| 846 929 |  | 
| 847 930 | 
             
              end # class IPv4
         | 
| 848 931 | 
             
            end # module IPAddress
         |