summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Sandström <mail+github@a16m.se>2023-05-06 18:36:01 +0200
committerAlexander Sandström <mail+github@a16m.se>2023-05-06 18:36:01 +0200
commite2dbf164e313112119c299f40bfa97cb4a77ee88 (patch)
tree1ad67bbfc2f705f5b3d8c3c30c600ac693ef007c
parentc94ff01a4f665226d16693d37674bf003e9793b5 (diff)
downloadipaddress-readme.tar.gz
Convert readme to Markdownreadme
-rw-r--r--.document2
-rw-r--r--README.md1057
-rw-r--r--README.rdoc995
-rw-r--r--ipaddress.gemspec4
4 files changed, 1060 insertions, 998 deletions
diff --git a/.document b/.document
index ecf3673..dd2904d 100644
--- a/.document
+++ b/.document
@@ -1,4 +1,4 @@
-README.rdoc
+README.md
lib/**/*.rb
bin/*
features/**/*.feature
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..357ec21
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1057 @@
+# IPAddress
+
+IPAddress is a Ruby library designed to make the use of IPv4 and IPv6
+addresses simple, powerful and enjoyable. It provides a complete set of
+methods to handle IP addresses for any need, from simple scripting to full
+network design.
+
+This document provides a brief introduction to the library and examples of
+typical usage.
+
+## Requirements
+
+* Ruby 1.9.3 or later
+
+Please refer to [Travis CI](https://travis-ci.org/ipaddress-gem/ipaddress) for
+Build Tests on specific versions of Ruby.
+
+[<img src="https://travis-ci.org/ipaddress-gem/ipaddress.svg?branch=master"
+alt="Build Status" />](https://travis-ci.org/ipaddress-gem/ipaddress) [<img
+src="https://codeclimate.com/github/ipaddress-gem/ipaddress/badges/gpa.svg"
+/>](https://codeclimate.com/github/ipaddress-gem/ipaddress) [<img
+src="https://www.versioneye.com/user/projects/57001305fcd19a0051853bde/badge.s
+vg?style=flat" alt="Dependency Status"
+/>](https://www.versioneye.com/user/projects/57001305fcd19a0051853bde)
+
+IPAddress 0.8.2 was manually tested on:
+
+* ruby-1.8.7-p334 [ i386 ]
+* ree-1.8.7-2011.03 [ i386 ]
+* rbx-head [ ]
+* jruby-1.6.1 [ linux-i386-java ]
+* ruby-1.9.1-p431 [ i386 ]
+* ruby-1.9.2-p180 [ i386 ]
+* ruby-2.0.0-p353 [ x86_64-darwin14.0.0 ]
+* ruby-2.1.3-p242 [ x86_64-darwin14.0.0 ]
+
+
+If you want to contribute, please refer to
+[Contributing.md](https://github.com/ipaddress-gem/ipaddress/blob/master/CONTR
+IBUTING.md).
+
+## Installation
+
+This gem is installed like any other:
+
+```bash
+# Install it generally:
+$ gem install ipaddress
+
+# or, add it to your current application gemfile:
+$ bundle add ipaddress
+```
+
+## Documentation
+
+The code is fully documented with RDoc. You can generate the
+documentation with Rake:
+
+```bash
+$ rake rdoc
+```
+
+The latest documentation can be found online at
+[this address][https://rubydoc.info/gems/ipaddress/]
+
+## Introduction via examples
+
+Below are two sections with examples. The first section is for IPv4,
+the second for IPv6 (further down).
+
+## IPv4
+
+The class `IPAddress::IPv4` is used to handle IPv4 type addresses.
+
+### Create a new IPv4 address
+
+The usual way to express an IP Address is using its dotted decimal form, such
+as `172.16.10.1`, and a prefix, such as `24`, separated by a slash.
+
+```
+172.16.10.1/24
+```
+
+To create a new IPv4 object, you can use IPv4 own class
+
+```ruby
+ip = IPAddress::IPv4.new "172.16.10.1/24"
+```
+
+or, in a easier way, using the IPAddress parse method
+
+```ruby
+ip = IPAddress.parse "172.16.10.1/24"
+```
+
+which accepts and parses any kind of IP (uint32, IPv4, IPV6 and IPv4 IPv6
+mapped addresses).
+
+If you like syntactic sugar, you can use the wrapper method `IPAddress()`,
+which is built around `IPAddress::parse`:
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+```
+
+You can specify an IPv4 address in any of two ways:
+
+```ruby
+IPAddress "172.16.10.1/24"
+IPAddress "172.16.10.1/255.255.255.0"
+```
+
+In this example, prefix `/24` and netmask `255.255.255.0` are the same and you
+have the flexibility to use either one of them.
+
+If you don't explicitly specify the prefix (or the subnet mask), IPAddress
+thinks you're dealing with host addresses and not with networks. Therefore,
+the default prefix will be `/32`, or `255.255.255.255`. For example:
+
+```ruby
+# let's declare an host address
+host = IPAddress::IPv4.new "10.1.1.1"
+
+puts host.to_s #=> "10.1.1.1/32"
+```
+
+The new created object has prefix `/32`, which is the same as we created the
+following:
+
+```ruby
+host = IPAddress::IPv4.new "10.1.1.1/32"
+```
+
+You can also pass a `uint32` to obtain an `IPAddress::IPv4` object:
+
+```ruby
+# Create host object
+ip = IPAddress 167837953
+puts ip.to_s #=> "10.1.1.1/32"
+```
+
+### Handling the IPv4 address
+
+Once created, you can obtain the attributes for an IPv4 object:
+
+```ruby
+ip = IPAddress("172.16.10.1/24")
+
+ip.address #=> "172.16.10.1"
+ip.prefix #=> 24
+```
+
+In case you need to retrieve the netmask in IPv4 format, you can use the
+`IPv4#netmask` method:
+
+```ruby
+ip.netmask #=> "255.255.255.0"
+```
+
+A special attribute, `IPv4#octets`, is available to get the four decimal
+octets from the IP address:
+
+```ruby
+ip.octets #=> [172,16,10,1]
+```
+
+The shortcut method `IPv4#[]`, provides access to a given octet whithin the range:
+
+```ruby
+ip[1] #=> 16
+```
+
+If you need to print out the IPv4 address in a canonical form, you can use
+`IPv4#to_s`:
+
+```ruby
+ip.to_s #=> "172.16.10.1/24"
+```
+
+### Changing netmask
+
+You can set a new prefix (netmask) after creating an IPv4 object. For
+example:
+
+```ruby
+ip.prefix = 25
+
+ip.to_s #=> "172.16.10.1/25"
+```
+
+If you need to use a netmask in IPv4 format, you can achive so by using the
+`IPv4#netmask=` method:
+
+```ruby
+ip.netmask = "255.255.255.252"
+
+ip.to_s #=> "172.16.10.1/30"
+```
+
+### Working with networks, broadcasts and addresses
+
+Some important topics in dealing with IP addresses are the concepts of
+`network` and `broadcast`, as well as the addresses included in a range.
+
+When you specify an IPv4 address such as `172.16.10.1/24`, you are actually
+handling two different information:
+
+* The IP address itself, "172.16.10.1"
+* The subnet mask which indicates the network
+
+The network number is the IP which has all zeroes in the host portion. In our
+example, because the prefix is 24, we identify our network number to have the
+last 8 (32-24) bits all zeroes. Thus, IP address `172.16.10.1/24` belongs to
+network `172.16.10.0/24`.
+
+This is important because, for instance, IP `172.16.10.1/16` is
+different to the previous one, belonging to the different network
+`172.16.0.0/16`.
+
+#### Networks
+
+With IPAddress it's easy to calculate the network for an IP address:
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+
+net = ip.network #=> #<IPAddress::IPv4:0xb7a5ab24 @octets=[172, 16, 10, 0], @prefix=24, @address="172.16.10.0">
+net.to_s #=> "172.16.10.0/24"
+```
+
+Method IPv4#network creates a new IPv4 object from the network number,
+calculated after the original object. We want to outline here that the network
+address is a perfect legitimate IPv4 address, which just happen to have all
+zeroes in the host portion.
+
+You can use method `IPv4#network?` to check whether an IP address is a network
+or not:
+
+```ruby
+ip1 = IPAddress "172.16.10.1/24"
+ip2 = IPAddress "172.16.10.4/30"
+
+ip1.network? #=> false
+ip2.network? #=> true
+```
+
+#### Broadcast
+
+The broadcast address is the contrary than the network number: where the
+network number has all zeroes in the host portion, the broadcast address has
+all one's. For example, ip `172.16.10.1/24` has broadcast `172.16.10.255/24`,
+where ip `172.16.10.1/16` has broadcast `172.16.255.255/16`.
+
+Method `IPv4#broadcast` has the same behavior as is `#network` counterpart: it
+creates a new IPv4 object to handle the broadcast address:
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+
+bcast = ip.broadcast #=> #<IPAddress::IPv4:0xb7a406fc @octets=[172, 16, 10, 255], @prefix=24, @address="172.16.10.255">
+bcast.to_s #=> "172.16.10.255/24"
+```
+
+#### Addresses, ranges and iterators
+
+So we see that the netmask essentially specifies a range for IP addresses that
+are included in a network: all the addresses between the network number and
+the broadcast. IPAddress has many methods to iterate between those addresses.
+Let's start with `IPv4#each`, which iterates over all addresses in a range
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+
+ip.each do |addr|
+ puts addr
+end
+```
+
+It is important to note that it doesn't matter if the original IP is a host IP
+or a network number (or a broadcast address): the #each method only considers
+the range that the original IP specifies.
+
+If you only want to iterate over hosts IP, use the `IPv4#each_host` method:
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+
+ip.each_host do |host|
+ puts host
+end
+```
+
+Methods `IPv4#first` and `IPv4#last` return a new object containing
+respectively the first and the last host address in the range
+
+```ruby
+ip = IPAddress "172.16.10.100/24"
+
+ip.first.to_s #=> "172.16.10.1/24"
+ip.last.to_s #=> "172.16.10.254/24"
+```
+
+Checking if an address is loopback is easy with the `IPv4#loopback?` method:
+
+```ruby
+ip = IPAddress "127.0.0.1"
+
+ip.loopback? #=> true
+```
+
+Checking if an address is in the multicast range can be done using the
+`IPv4#multicast?` method:
+
+```ruby
+ip = IPAddress "224.0.0.1/32"
+
+ip.multicast? #=> true
+```
+
+The ability to generate a range also exists by using the `IPv4#to()` method.
+This allows you to create a subnet agnostic range based off a fixed amount.
+
+```ruby
+ip = IPAddress "172.16.10.100/24"
+ip.to('172.16.10.110') #=> ["172.16.10.100", ..., "172.16.10.110"]
+```
+
+### IP special formats
+
+The IPAddress library provides a complete set of methods to access an IPv4
+address in special formats, such as binary, 32 bits unsigned int, data and
+hexadecimal.
+
+Let's take the following IPv4 as an example:
+
+```ruby
+ip = IPAddress "172.16.10.1/24"
+
+ip.address #=> "172.16.10.1"
+```
+
+The first thing to highlight here is that all these conversion methods only
+take into consideration the address portion of an IPv4 object and not the
+prefix (netmask).
+
+So, to express the address in binary format, use the `IPv4#bits` method:
+
+```ruby
+ip.bits #=> "10101100000100000000101000000001"
+```
+
+To calculate the 32 bits unsigned int format of the ip address, use the
+`IPv4#to_u32` method
+
+```ruby
+ip.to_u32 #=> 2886732289
+```
+
+This method is the equivalent of the Unix call `pton()`, expressing an IP
+address in the so called +network byte order+ notation. However, if you want
+to transmit your IP over a network socket, you might need to transform it in
+data format using the `IPv4#data` method:
+
+```ruby
+ip.data #=> "\254\020\n\001"
+```
+
+Also, you can transform an IPv4 address into a format which is suitable to use
+in IPv4-IPv6 mapped addresses:
+
+```ruby
+ip.to_ipv6 #=> "ac10:0a01"
+```
+
+Finally, much like `IPv4#to_ipv6` you can use to `IPv4#to_h` method to return
+a non-semicolon delineated string (useful with pcap/byte level usage):
+
+```ruby
+ip.to_h #=> "ac100a01"
+```
+
+### Classful networks
+
+IPAddress allows you to create and manipulate objects using the old and
+deprecated (but apparently still popular) classful networks concept.
+
+Classful networks and addresses don't have a prefix: their subnet mask is
+univocally identified by their address, and therefore divided in classes. As
+per RFC 791, these classes are:
+
+* Class A, from 0.0.0.0 to 127.255.255.255
+* Class B, from 128.0.0.0 to 191.255.255.255
+* Class C, from 192.0.0.0 to 255.255.255.255
+
+Since classful networks here are only considered to calculate the default
+prefix number, classes D and E are not considered.
+
+To create a classful IP and prefix from an IP address, use the
+IPv4::parse_classful method:
+
+```ruby
+# classful ip
+ip = IPAddress::IPv4::parse_classful "10.1.1.1"
+
+ip.prefix #=> 8
+```
+
+The method automatically created a new IPv4 object and assigned it the correct
+prefix.
+
+You can easily check which classful network an IPv4 object belongs:
+
+```ruby
+ip = IPAddress("10.0.0.1/24")
+ip.a? #=> true
+
+ip = IPAddress("172.16.10.1/24")
+ip.b? #=> true
+
+ip = IPAddress("192.168.1.1/30")
+ip.c? #=> true
+```
+
+Remember that these methods are only checking the address portion of an IP,
+and are independent from its prefix, as classful networks have no concept of
+prefix.
+
+For more information on classful networks visit the [Wikipedia
+page](https://en.wikipedia.org/wiki/Classful_network)
+
+### Network design with IPAddress
+
+IPAddress includes a lot of useful methods to manipulate IPv4 and IPv6
+networks and do some basic network design.
+
+#### Subnetting
+
+The process of subnetting is the division of a network into smaller (in terms
+of hosts capacity) networks, called subnets, so that they all share a common
+root, which is the starting network.
+
+For example, if you have network "172.16.10.0/24", we can subnet it into 4
+smaller subnets. The new prefix will be /26, because 4 is 2^2 and therefore we
+add 2 bits to the network prefix (24+2=26).
+
+Subnetting is easy with IPAddress. You actually have two options:
+
+* IPv4#subnet: specify a new prefix
+* IPv4#split: tell IPAddress how many subnets you want to create.
+
+Let's examine `IPv4#subnet` first. Say you have network "172.16.10.0/24" and
+you want to subnet it into /26 networks.
+
+```ruby
+network = IPAddress "172.16.10.0/24"
+
+subnets = network.subnet(26)
+
+subnets.map { |i| i.to_s } #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", "172.16.10.192/26"]
+```
+
+As you can see, an Array has been created, containing 4 new IPv4 objects
+representing the new subnets.
+
+Another way to create subnets is to tell IPAddress how many subnets you'd
+like to have, and letting the library calculate the new prefix for you.
+
+Let's see how it works, using `IPv4#split` method. Say you want 4 new subnets:
+
+```ruby
+network = IPAddress("172.16.10.0/24")
+
+subnets = network.split(4)
+
+subnets.map { |i| i.to_s } #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", "172.16.10.192/26"]
+```
+
+Hey, that's the same result as before! This actually makes sense, as the two
+operations are complementary. When you use `IPv4#subnet` with the new prefix,
+IPAddress will always create a number of subnets that is a power of two. This
+is equivalent to use IPv4#split with a power of 2.
+
+Where `IPv4#split` really shines is with the so called "uneven subnetting".
+You are not limited to split a network into a power-of-two numbers of subnets:
+IPAddress lets you create any number of subnets, and it will try to organize
+the new created network in the best possible way, making an efficient
+allocation of the space.
+
+An example here is worth a thousand words. Let's use the same network as the
+previous examples:
+
+```ruby
+network = IPAddress("172.16.10.0/24")
+```
+
+How do we split this network into 3 subnets? Easy:
+
+```ruby
+subnets = network.split(3)
+
+subnets.map { |i| i.to_s } #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/25"]
+```
+
+As you can see, IPAddress tried to perform a good allocation by filling up all
+the address space from the original network. There is no point in splitting a
+network into 3 subnets like `172.16.10.0/26`, `172.16.10.64/26` and
+`172.16.10.128/26`, as you would end up having `172.16.10.192/26` wasted.
+
+We can go even further and split into 11 subnets:
+
+```ruby
+network.split(11)
+#=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28",
+# "172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28",
+# "172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27",
+# "172.16.10.160/27", "172.16.10.192/26"]
+```
+
+As you can see, most of the networks are `/28`, with a few `/27` and one `/26`
+to fill up the remaining space.
+
+#### Summarization
+
+Summarization (or aggregation) is the process when two or more networks are
+taken together to check if a supernet, including all and only these networks,
+exists. If it exists then this supernet is called the summarized (or
+aggregated) network.
+
+It is important to understand that summarization can
+only occur if there are no holes in the aggregated network, or, in other
+words, if the given networks fill completely the address space of the
+supernet.
+
+So the two rules are:
+
+1. The aggregate network must contain `all` the IP addresses of the original
+networks;
+
+2. The aggregate network must contain `only` the IP addresses of the original
+networks;
+
+A few examples will help clarify the above. Let's consider for instance the
+following two networks:
+
+```ruby
+ip1 = IPAddress("172.16.10.0/24")
+ip2 = IPAddress("172.16.11.0/24")
+```
+
+These two networks can be expressed using only one IP address network if we
+change the prefix:
+
+```ruby
+IPAddress::IPv4::summarize(ip1,ip2).map(&:to_s) #=> "172.16.10.0/23"
+```
+
+We note how the network `172.16.10.0/23` includes all the addresses specified
+in the above networks, and (more important) includes only those addresses.
+
+If we summarized `ip1` and `ip2` with the following network:
+
+```ruby
+"172.16.0.0/16"
+```
+
+we would have satisfied rule #1 above, but not rule #2. So
+
+```ruby
+"172.16.0.0/16"
+```
+
+is not an aggregate network for `ip1` and `ip2`.
+
+If it's not possible to compute a single aggregated network for all the
+original networks, the method returns an array with all the aggregate networks
+found. For example, the following four networks can be aggregated in a single
+`/22`:
+
+```ruby
+ip1 = IPAddress("10.0.0.1/24")
+ip2 = IPAddress("10.0.1.1/24")
+ip3 = IPAddress("10.0.2.1/24")
+ip4 = IPAddress("10.0.3.1/24")
+
+IPAddress::IPv4::summarize(ip1, ip2, ip3, ip4).map { |i| i.to_s } #=> ["10.0.0.0/22"]
+```
+
+But the following networks can't be summarized in a single network:
+
+```ruby
+ip1 = IPAddress("10.0.1.1/24")
+ip2 = IPAddress("10.0.2.1/24")
+ip3 = IPAddress("10.0.3.1/24")
+ip4 = IPAddress("10.0.4.1/24")
+
+IPAddress::IPv4::summarize(ip1, ip2, ip3, ip4).map { |i| i.to_s } #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
+```
+
+In this case, the two summarizables networks have been aggregated into a
+single `/23`, while the other two networks have been left untouched.
+
+#### Supernetting
+
+Supernetting is a different operation than aggregation, as it only works on a
+single network and returns a new single IPv4 object, representing the
+supernet.
+
+Supernetting is similar to subnetting, except that you getting as a result a
+network with a smaller prefix (bigger host space). For example, given the
+network
+
+```ruby
+ip = IPAddress("172.16.10.0/24")
+```
+
+you can supernet it with a new /23 prefix
+
+```ruby
+ip.supernet(23).to_s #=> "172.16.10.0/23"
+```
+
+However if you supernet it with a `/22` prefix, the network address will
+change:
+
+```ruby
+ip.supernet(22).to_s #=> "172.16.8.0/22"
+```
+
+This is because `172.16.10.0/22` is not a network anymore, but an host
+address.
+
+## IPv6
+
+IPAddress is not only fantastic for IPv4 addresses, it's also great to handle
+IPv6 addresses family! Let's discover together how to use it in our projects.
+
+### IPv6 addresses
+
+IPv6 addresses are 128 bits long, in contrast with IPv4 addresses which are
+only 32 bits long. An IPv6 address is generally written as eight groups of
+four hexadecimal digits, each group representing 16 bits or two octet. For
+example, the following is a valid IPv6 address:
+
+```
+2001:0db8:0000:0000:0008:0800:200c:417a
+```
+
+Letters in an IPv6 address are usually written downcase, as per RFC. You can
+create a new IPv6 object using uppercase letters, but they will be converted.
+
+#### Compression
+
+Since IPv6 addresses are long to write, there are some simplifications
+and compressions that you can use to shorten them.
+
+* Leading zeroes: all the leading zeroes within a group can be omitted:
+"0008" would become "8"
+
+* A string of consecutive zeroes can be replaced by the string "::". This
+can be only applied once.
+
+Using compression, the IPv6 address written above can be shorten into the
+following, equivalent, address
+
+```
+2001:db8::8:800:200c:417a
+```
+
+This short version is often used in human representation.
+
+#### Network Mask
+
+As we used to do with IPv4 addresses, an IPv6 address can be written using the
+prefix notation to specify the subnet mask:
+
+```
+2001:db8::8:800:200c:417a/64
+```
+
+The /64 part means that the first 64 bits of the address are representing the
+network portion, and the last 64 bits are the host portion.
+
+### Using IPAddress with IPv6 addresses
+
+All the IPv6 representations we've just seen are perfectly fine when you want
+to create a new IPv6 address:
+
+```ruby
+ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"
+
+ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"
+
+ip6 = IPAddress "2001:db8:8:800:200C:417A"
+```
+
+All three are giving out the same IPv6 object. The default subnet mask for an
+IPv6 is 128, as IPv6 addresses don't have classes like IPv4 addresses. If you
+want a different mask, you can go ahead and explicit it:
+
+```ruby
+ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
+```
+
+Access the address portion and the prefix by using the respective methods:
+
+```ruby
+ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
+
+ip6.address #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
+
+ip6.prefix #=> 64
+```
+
+A compressed version of the IPv6 address can be obtained with the
+`IPv6#compressed` method:
+
+```ruby
+ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"
+
+ip6.compressed #=> "2001:db8::8:800:200c:417a"
+```
+
+### Handling the IPv6 address
+
+Accessing the groups that form an IPv6 address is easy with the
+`IPv6#groups` method:
+
+```ruby
+ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
+
+ip6.groups #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
+```
+
+As with IPv4 addresses, each individual group can be accessed using the
+`IPv6#[]` shortcut method:
+
+```ruby
+ip6[0] #=> 8193
+ip6[1] #=> 3512
+ip6[2] #=> 0
+ip6[3] #=> 0
+```
+
+Note that each 16 bits group is expressed in its decimal form. You can also
+obtain the groups into hexadecimal format using the `IPv6#hexs` method:
+
+```ruby
+ip6.hexs #=> ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
+```
+
+A few other methods are available to transform an IPv6 address into decimal
+representation, with `IPv6.to_i`
+
+```ruby
+ip6.to_i #=> 42540766411282592856906245548098208122
+```
+
+or to hexadecimal representation:
+
+```ruby
+ip6.to_hex #=> "20010db80000000000080800200c417a"
+```
+
+To print out an IPv6 address in human readable form, use the `IPv6#to_string`,
+`IPv6#to_s` and `IPv6#to_string_uncompressed` methods:
+
+```ruby
+ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
+
+ip6.to_string #=> "2001:db8::8:800:200c:417a/96"
+ip6.to_s #=> "2001:db8::8:800:200c:417a/96"
+
+ip6.to_string_uncompressed #=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"
+```
+
+As you can see, `IPv6.to_string` prints out the compressed form, while
+`IPv6.to_string_uncompressed` uses the expanded version.
+
+#### Compressing and uncompressing
+
+If you have a string representing an IPv6 address, you can easily compress it
+and uncompress it using the two class methods IPv6::expand and IPv6::compress.
+
+For example, let's say you have the following uncompressed IPv6 address:
+
+```ruby
+str = "2001:0DB8:0000:CD30:0000:0000:0000:0000"
+```
+
+Here is the compressed version:
+
+```ruby
+IPAddress::IPv6.compress(str) #=> "2001:db8:0:cd30::"
+```
+
+The other way works as well:
+
+```ruby
+str = "2001:db8:0:cd30::"
+
+IPAddress::IPv6.expand(str) #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
+```
+
+These methods can be used when you don't want to create a new object just for
+expanding or compressing an address (although a new object is actually created
+internally).
+
+### New IPv6 address from other formats
+
+You can create a new IPv6 address from different formats than just a string
+representing the colon-hex groups.
+
+For instance, if you have a data stream, you can use `IPv6::parse_data`, like
+in the following example:
+
+```ruby
+data = " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
+
+ip6 = IPAddress::IPv6::parse_data data
+ip6.prefix = 64
+
+ip6.to_s #=> "2001:db8::8:800:200c:417a/64"
+```
+
+A new IPv6 address can also be created from an unsigned 128 bits integer:
+
+```ruby
+u128 = 42540766411282592856906245548098208122
+
+ip6 = IPAddress::IPv6::parse_u128 u128
+ip6.prefix = 64
+
+ip6.to_s #=>"2001:db8::8:800:200c:417a/64"
+```
+
+Finally, a new IPv6 address can be created from an hex string:
+
+```ruby
+hex = "20010db80000000000080800200c417a"
+
+ip6 = IPAddress::IPv6::parse_hex hex
+ip6.prefix = 64
+
+ip6.to_s #=> "2001:db8::8:800:200c:417a/64"
+```
+
+### Special IPv6 addresses
+
+Some IPv6 have a special meaning and are expressed in a special form, quite
+different than an usual IPv6 address. IPAddress has built-in support for
+unspecified, loopback and mapped IPv6 addresses.
+
+#### Unspecified address
+
+The address with all zero bits is called the `unspecified` address
+(corresponding to `0.0.0.0` in IPv4). It should be something like this:
+
+```
+0000:0000:0000:0000:0000:0000:0000:0000
+```
+
+but, with the use of compression, it is usually written as just two colons:
+
+```
+::
+```
+
+or, specifying the netmask:
+
+```
+::/128
+```
+
+With IPAddress, create a new unspecified IPv6 address using its own subclass:
+
+```ruby
+ip = IPAddress::IPv6::Unspecified.new
+
+ip.to_s #=> "::/128"
+```
+
+You can easily check if an IPv6 object is an unspecified address by using the
+IPv6#unspecified? method
+
+```ruby
+ip.unspecified? #=> true
+```
+
+An unspecified IPv6 address can also be created with the wrapper method, like
+we've seen before
+
+```ruby
+ip = IPAddress "::"
+
+ip.unspecified? #=> true
+```
+
+This address must never be assigned to an interface and is to be used only in
+software before the application has learned its host's source address
+appropriate for a pending connection. Routers must not forward packets with
+the unspecified address.
+
+#### Loopback address
+
+The loopback address is a unicast localhost address. If an application in a
+host sends packets to this address, the IPv6 stack will loop these packets
+back on the same virtual interface.
+
+Loopback addresses are expressed in the following form:
+
+```
+::1
+```
+
+or, with their appropriate prefix,
+
+```
+::1/128
+```
+
+As for the unspecified addresses, IPv6 loopbacks can be created with IPAddress
+calling their own class:
+
+```ruby
+ip = IPAddress::IPv6::Loopback.new
+
+ip.to_s #=> "::1/128"
+```
+
+or by using the wrapper:
+
+```ruby
+ip = IPAddress "::1"
+
+ip.to_s #=> "::1/128"
+```
+
+Checking if an address is loopback is easy with the `IPv6#loopback?` method:
+
+```ruby
+ip.loopback? #=> true
+```
+
+The IPv6 loopback address corresponds to `127.0.0.1` in IPv4.
+
+#### Mapped address
+
+It is usually identified as a IPv4 mapped IPv6 address, a particular IPv6
+address which aids the transition from IPv4 to IPv6. The structure of the
+address is
+
+```
+::ffff:w.y.x.z
+```
+
+where `w.x.y.z` is a normal IPv4 address. For example, the following is a
+mapped IPv6 address:
+
+```
+::ffff:192.168.100.1
+```
+
+IPAddress is powerful in handling mapped IPv6 addresses, as the IPv4
+portion is stored internally as a normal IPv4 object. Let's have a look at
+some examples. To create a new mapped address, just use the class builder
+itself
+
+```ruby
+ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
+```
+
+or just use the wrapper method
+
+```ruby
+ip6 = IPAddress "::ffff:172.16.10.1/128"
+```
+
+Let's check it's really a mapped address:
+
+```ruby
+ip6.mapped? #=> true
+
+ip6.to_s #=> "::ffff:172.16.10.1/128"
+```
+
+Now with the `#ipv4` attribute, we can easily access the IPv4 portion of the
+mapped IPv6 address:
+
+```ruby
+ip6.ipv4.address #=> "172.16.10.1"
+```
+
+Internally, the IPv4 address is stored as two 16 bits groups. Therefore all
+the usual methods for an IPv6 address are working perfectly fine:
+
+```ruby
+ip6.to_hex #=> "00000000000000000000ffffac100a01"
+
+ip6.address #=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"
+```
+
+A mapped IPv6 can also be created just by specify the address in the following
+format:
+
+```ruby
+ip6 = IPAddress "::172.16.10.1"
+```
+
+That is, two colons and the IPv4 address. However, as by RFC, the `ffff` group
+will be automatically added at the beginning
+
+```ruby
+ip6.to_s #=> "::ffff:172.16.10.1/128"
+```
+
+making it a mapped IPv6 compatible address.
+
+## Why not using IPAddr?
+
+IPAddr is the IP addresses library that comes with Ruby standard lib. We found
+this library, although well written, not suitable for all our needs.
+
+Some quick examples of things you can't do with IPAddr:
+
+* store both the address and the prefix information
+* quickly find the broadcast address of a network
+* iterate over hosts
+* perform subnetting or network aggregation
+
+Many methods and procedures are so old that they have been declared
+deprecated by the IETF, and some others have bugs in their implementation.
+
+Moreover, IPAddress is more robust and is roughly twice as fast as IPAddr,
+in addition to provide an organic API with logical separation and code structure.
+
+We hope that IPAddress will address all these issues and meet all your needs
+in network programming.
+
+## Community
+
+Want to join the community?
+
+We have [discussions setup on Github](https://github.com/ipaddress-gem/ipaddress/discussions),
+where anyone can participate and discuss.
+
+## Thanks to
+
+Thanks to Luca Russo (vargolo) and Simone Carletti (weppos) for all the
+support and technical review. Thanks to Marco Beri, Bryan T. Richardson,
+Nicolas Fevrier, jdpace, Daniele Alessandri, jrdioko, Ghislain Charrier,
+Pawel Krzesniak, Mark Sullivan, Leif Gensert, Erik Ahlström, Peter Vandenberk
+and Steve Rawlinson for their support, feedback and bug reports.
+
+## Copyright
+
+Copyright (c) 2009-today Marco Ceresa and Mike Mackintosh.
+See LICENSE for details.
diff --git a/README.rdoc b/README.rdoc
deleted file mode 100644
index bb5cf72..0000000
--- a/README.rdoc
+++ /dev/null
@@ -1,995 +0,0 @@
-= IPAddress
-
-IPAddress is a Ruby library designed to make the use of IPv4 and IPv6
-addresses simple, powerful and enjoyable. It provides a complete set of
-methods to handle IP addresses for any need, from simple scripting to
-full network design.
-
-IPAddress is written with a full OO interface, and its code is easy to
-read, maintain and extend. The documentation is full of examples, to
-let you start being productive immediately.
-
-This document provides a brief introduction to the library and
-examples of typical usage.
-
-== Requirements
-
-* Ruby 1.9.3 or later
-
-Please refer to {Travis CI}[https://travis-ci.org/ipaddress-gem/ipaddress] for Build Tests on specific versions of Ruby.
-
-{<img src="https://travis-ci.org/ipaddress-gem/ipaddress.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/ipaddress-gem/ipaddress] {<img src="https://codeclimate.com/github/ipaddress-gem/ipaddress/badges/gpa.svg" />}[https://codeclimate.com/github/ipaddress-gem/ipaddress] {<img src="https://www.versioneye.com/user/projects/57001305fcd19a0051853bde/badge.svg?style=flat" alt="Dependency Status" />}[https://www.versioneye.com/user/projects/57001305fcd19a0051853bde]
-
-IPAddress 0.8.2 was manually tested on:
-
-* ruby-1.8.7-p334 [ i386 ]
-* ree-1.8.7-2011.03 [ i386 ]
-* rbx-head [ ]
-* jruby-1.6.1 [ linux-i386-java ]
-* ruby-1.9.1-p431 [ i386 ]
-* ruby-1.9.2-p180 [ i386 ]
-* ruby-2.0.0-p353 [ x86_64-darwin14.0.0 ]
-* ruby-2.1.3-p242 [ x86_64-darwin14.0.0 ]
-
-If you want to contribute, please refer to {Contributing.md}[https://github.com/ipaddress-gem/ipaddress/blob/master/CONTRIBUTING.md].
-
-
-== Installation
-
-Install the library using rubygems
-
- $ gem install ipaddress
-
-You can then use it in your programs:
-
- require 'rubygems' # optional
- require 'ipaddress'
-
-Another way would be to clone the git repository
-
- $ git clone git://github.com/bluemonk/ipaddress.git
-
-And then install the library
-
- $ cd ipaddress
- ipaddress$ rake install
-
-== Documentation
-
-The code is fully documented with RDoc. You can generate the
-documentation with Rake:
-
- ipaddress$ rake rdoc
-
-The latest documentation can be found online at
-{this address}[http://rubydoc.info/gems/ipaddress/0.8.0/frames]
-
-== IPv4
-
-Class `IPAddress::IPv4` is used to handle IPv4 type addresses. IPAddress
-is similar to other IP Addresses libraries, like Ruby's own
-IPAddr. However it works slightly different, as we will see.
-
-=== Create a new IPv4 address
-
-The usual way to express an IP Address is using its dotted decimal
-form, such as `172.16.10.1`, and a prefix, such as `24`, separated by a
-slash.
-
- 172.16.10.1/24
-
-To create a new IPv4 object, you can use IPv4 own class
-
- ip = IPAddress::IPv4.new "172.16.10.1/24"
-
-or, in a easier way, using the IPAddress parse method
-
- ip = IPAddress.parse "172.16.10.1/24"
-
-which accepts and parses any kind of IP (uint32, IPv4, IPV6 and
-IPv4 IPv6 Mapped addresses).
-
-If you like syntactic sugar, you can use the wrapper method
-`IPAddress()`, which is built around `IPAddress::parse`:
-
- ip = IPAddress "172.16.10.1/24"
-
-You can specify an IPv4 address in any of two ways:
-
- IPAddress "172.16.10.1/24"
- IPAddress "172.16.10.1/255.255.255.0"
-
-In this example, prefix `/24` and netmask `255.255.255.0` are the same and
-you have the flexibility to use either one of them.
-
-If you don't explicitly specify the prefix (or the subnet mask),
-IPAddress thinks you're dealing with host addresses and not with
-networks. Therefore, the default prefix will be `/32`, or
-`255.255.255.255`. For example:
-
- # let's declare an host address
- host = IPAddress::IPv4.new "10.1.1.1"
-
- puts host.to_string
- #=> "10.1.1.1/32"
-
-The new created object has prefix `/32`, which is the same
-as we created the following:
-
- host = IPAddress::IPv4.new "10.1.1.1/32"
-
-You can also pass a `uint32` to obtain an `IPAddress::IPv4` object:
-
- # Create host object
- ip = IPAddress 167837953
- puts ip.to_string
- #=> "10.1.1.1/32"
-
-=== Handling the IPv4 address
-
-Once created, you can obtain the attributes for an IPv4 object:
-
- ip = IPAddress("172.16.10.1/24")
-
- ip.address
- #=> "172.16.10.1"
- ip.prefix
- #=> 24
-
-In case you need to retrieve the netmask in IPv4 format, you can use
-the `IPv4#netmask` method:
-
- ip.netmask
- #=> "255.255.255.0"
-
-A special attribute, `IPv4#octets`, is available to get the four
-decimal octets from the IP address:
-
- ip.octets
- #=> [172,16,10,1]
-
-Shortcut method `IPv4#[]`, provides access to a given octet whithin the
-range:
-
- ip[1]
- #=> 16
-
-If you need to print out the IPv4 address in a canonical form, you can
-use `IPv4#to_string`:
-
- ip.to_string
- #=> "172.16.10.1/24"
-
-=== Changing netmask
-
-You can set a new prefix (netmask) after creating an IPv4
-object. For example:
-
- ip.prefix = 25
-
- ip.to_string
- #=> "172.16.10.1/25"
-
-If you need to use a netmask in IPv4 format, you can achive so by
-using the `IPv4#netmask=` method:
-
- ip.netmask = "255.255.255.252"
-
- ip.to_string
- #=> "172.16.10.1/30"
-
-=== Working with networks, broadcasts and addresses
-
-Some very important topics in dealing with IP addresses are the
-concepts of +network+ and +broadcast+, as well as the addresses
-included in a range.
-
-When you specify an IPv4 address such as `172.16.10.1/24`, you are
-actually handling two different information:
-
-* The IP address itself, "172.16.10.1"
-* The subnet mask which indicates the network
-
-The network number is the IP which has all zeroes in the host
-portion. In our example, because the prefix is 24, we identify our
-network number to have the last 8 (32-24) bits all zeroes. Thus, IP
-address `172.16.10.1/24` belongs to network `172.16.10.0/24`.
-
-This is very important because, for instance, IP `172.16.10.1/16` is
-very different to the previous one, belonging to the very different
-network `172.16.0.0/16`.
-
-==== Networks
-
-With IPAddress it's very easy to calculate the network for an IP
-address:
-
- ip = IPAddress "172.16.10.1/24"
-
- net = ip.network
- #=> #<IPAddress::IPv4:0xb7a5ab24 @octets=[172, 16, 10, 0],
- @prefix=24,
- @address="172.16.10.0">
- net.to_string
- #=> "172.16.10.0/24"
-
-Method IPv4#network creates a new IPv4 object from the network
-number, calculated after the original object. We want to outline here
-that the network address is a perfect legitimate IPv4 address, which
-just happen to have all zeroes in the host portion.
-
-You can use method `IPv4#network?` to check whether an IP address is a
-network or not:
-
- ip1 = IPAddress "172.16.10.1/24"
- ip2 = IPAddress "172.16.10.4/30"
-
- ip1.network?
- #=> false
- ip2.network?
- #=> true
-
-==== Broadcast
-
-The broadcast address is the contrary than the network number: where
-the network number has all zeroes in the host portion, the broadcast
-address has all one's. For example, ip `172.16.10.1/24` has broadcast
-`172.16.10.255/24`, where ip `172.16.10.1/16` has broadcast
-`172.16.255.255/16`.
-
-Method `IPv4#broadcast` has the same behavior as is `#network`
-counterpart: it creates a new IPv4 object to handle the broadcast
-address:
-
- ip = IPAddress "172.16.10.1/24"
-
- bcast = ip.broadcast
- #=> #<IPAddress::IPv4:0xb7a406fc @octets=[172, 16, 10, 255],
- @prefix=24,
- @address="172.16.10.255">
- bcast.to_string
- #=> "172.16.10.255/24"
-
-==== Addresses, ranges and iterators
-
-So we see that the netmask essentially specifies a range for IP
-addresses that are included in a network: all the addresses between
-the network number and the broadcast. IPAddress has many methods to
-iterate between those addresses. Let's start with `IPv4#each`, which
-iterates over all addresses in a range
-
- ip = IPAddress "172.16.10.1/24"
-
- ip.each do |addr|
- puts addr
- end
-
-It is important to note that it doesn't matter if the original IP is a
-host IP or a network number (or a broadcast address): the #each method
-only considers the range that the original IP specifies.
-
-If you only want to iterate over hosts IP, use the `IPv4#each_host`
-method:
-
- ip = IPAddress "172.16.10.1/24"
-
- ip.each_host do |host|
- puts host
- end
-
-Methods `IPv4#first` and `IPv4#last` return a new object containing
-respectively the first and the last host address in the range
-
- ip = IPAddress "172.16.10.100/24"
-
- ip.first.to_string
- #=> "172.16.10.1/24"
-
- ip.last.to_string
- #=> "172.16.10.254/24"
-
-Checking if an address is loopback is easy with the `IPv4#loopback?`
-method:
-
- ip = IPAddress "127.0.0.1"
-
- ip.loopback?
- #=> true
-
-Checking if an address is in the multicast range can be done using the `IPv4#multicast?`
-method:
-
- ip = IPAddress "224.0.0.1/32"
-
- ip.multicast?
- #=> true
-
-The ability to generate a range also exists by using the `IPv4#to()` method. This allows you to create a subnet agnostic range based off a fixed amount.
-
- ip = IPAddress "172.16.10.100/24"
- ip.to('172.16.10.110')
- #=> ["172.16.10.100", ..., "172.16.10.110"]
-
-=== IP special formats
-
-The IPAddress library provides a complete set of methods to access an
-IPv4 address in special formats, such as binary, 32 bits unsigned int,
-data and hexadecimal.
-
-Let's take the following IPv4 as an example:
-
- ip = IPAddress "172.16.10.1/24"
-
- ip.address
- #=> "172.16.10.1"
-
-The first thing to highlight here is that all these conversion methods
-only take into consideration the address portion of an IPv4 object and
-not the prefix (netmask).
-
-So, to express the address in binary format, use the `IPv4#bits` method:
-
- ip.bits
- #=> "10101100000100000000101000000001"
-
-To calculate the 32 bits unsigned int format of the ip address, use
-the `IPv4#to_u32` method
-
- ip.to_u32
- #=> 2886732289
-
-This method is the equivalent of the Unix call `pton()`, expressing an
-IP address in the so called +network byte order+ notation. However, if
-you want to transmit your IP over a network socket, you might need to
-transform it in data format using the `IPv4#data` method:
-
- ip.data
- #=> "\254\020\n\001"
-
-Also, you can transform an IPv4 address into a format which is
-suitable to use in IPv4-IPv6 mapped addresses:
-
- ip.to_ipv6
- #=> "ac10:0a01"
-
-Finally, much like `IPv4#to_ipv6` you can use to `IPv4#to_h` method to return a non-semicolon delineated string (useful with pcap/byte level usage):
-
- ip.to_h
- #=> "ac100a01"
-
-=== Classful networks
-
-IPAddress allows you to create and manipulate objects using the old
-and deprecated (but apparently still popular) classful networks concept.
-
-Classful networks and addresses don't have a prefix: their subnet mask
-is univocally identified by their address, and therefore divided in classes.
-As per RFC 791, these classes are:
-
-* Class A, from 0.0.0.0 to 127.255.255.255
-* Class B, from 128.0.0.0 to 191.255.255.255
-* Class C, from 192.0.0.0 to 255.255.255.255
-
-Since classful networks here are only considered to calculate the default
-prefix number, classes D and E are not considered.
-
-To create a classful IP and prefix from an IP address, use the
-IPv4::parse_classful method:
-
- # classful ip
- ip = IPAddress::IPv4::parse_classful "10.1.1.1"
-
- ip.prefix
- #=> 8
-
-The method automatically created a new IPv4 object and assigned it
-the correct prefix.
-
-You can easily check which CLASSFUL network an IPv4 object belongs:
-
- ip = IPAddress("10.0.0.1/24")
- ip.a?
- #=> true
-
- ip = IPAddress("172.16.10.1/24")
- ip.b?
- #=> true
-
- ip = IPAddress("192.168.1.1/30")
- ip.c?
- #=> true
-
-Remember that these methods are only checking the address portion of an IP, and are
-independent from its prefix, as classful networks have no concept of prefix.
-
-For more information on CLASSFUL networks visit the
-{Wikipedia page}[http://en.wikipedia.org/wiki/Classful_network]
-
-=== Network design with IPAddress
-
-IPAddress includes a lot of useful methods to manipulate IPv4 and IPv6
-networks and do some basic network design.
-
-==== Subnetting
-
-The process of subnetting is the division of a network into smaller
-(in terms of hosts capacity) networks, called subnets, so that they
-all share a common root, which is the starting network.
-
-For example, if you have network "172.16.10.0/24", we can subnet it
-into 4 smaller subnets. The new prefix will be /26, because 4 is 2^2
-and therefore we add 2 bits to the network prefix (24+2=26).
-
-Subnetting is easy with IPAddress. You actually have two options:
-
-* IPv4#subnet: specify a new prefix
-* IPv4#split: tell IPAddress how many subnets you want to create.
-
-Let's examine `IPv4#subnet` first. Say you have network "172.16.10.0/24"
-and you want to subnet it into /26 networks. With IPAddress it's very
-easy:
-
- network = IPAddress "172.16.10.0/24"
-
- subnets = network.subnet(26)
-
- subnets.map{|i| i.to_string}
- #=> ["172.16.10.0/26",
- "172.16.10.64/26",
- "172.16.10.128/26",
- "172.16.10.192/26"]
-
-As you can see, an Array has been created, containing 4 new IPv4 objects
-representing the new subnets.
-
-Another way to create subnets is to tell IPAddress how many subnets you'd
-like to have, and letting the library calculate the new prefix for you.
-
-Let's see how it works, using `IPv4#split` method. Say you want 4 new subnets:
-
- network = IPAddress("172.16.10.0/24")
-
- subnets = network.split(4)
-
- subnets.map{|i| i.to_string}
- #=> ["172.16.10.0/26",
- "172.16.10.64/26",
- "172.16.10.128/26",
- "172.16.10.192/26"]
-
-Hey, that's the same result as before! This actually makes sense, as the
-two operations are complementary. When you use `IPv4#subnet` with the new
-prefix, IPAddress will always create a number of subnets that is a power
-of two. This is equivalent to use IPv4#split with a power of 2.
-
-Where `IPv4#split` really shines is with the so called "uneven subnetting".
-You are not limited to split a network into a power-of-two numbers of
-subnets: IPAddress lets you create any number of subnets, and it will
-try to organize the new created network in the best possible way, making
-an efficient allocation of the space.
-
-An example here is worth a thousand words. Let's use the same network
-as the previous examples:
-
- network = IPAddress("172.16.10.0/24")
-
-How do we split this network into 3 subnets? Very easy:
-
- subnets = network.split(3)
-
- subnets.map{|i| i.to_string}
- #=> ["172.16.10.0/26",
- "172.16.10.64/26",
- "172.16.10.128/25"]
-
-As you can see, IPAddress tried to perform a good allocation by filling up
-all the address space from the original network. There is no point in splitting
-a network into 3 subnets like `172.16.10.0/26`, `172.16.10.64/26` and
-`172.16.10.128/26`, as you would end up having `172.16.10.192/26` wasted (plus,
-I suppose I wouldn't need a Ruby library to perform un-efficient IP
-allocation, as I do that myself very well ;) ).
-
-We can go even further and split into 11 subnets:
-
- network.split(11)
- #=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28",
- "172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28",
- "172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27",
- "172.16.10.160/27", "172.16.10.192/26"]
-
-As you can see, most of the networks are `/28`, with a few `/27` and one
-`/26` to fill up the remaining space.
-
-==== Summarization
-
-Summarization (or aggregation) is the process when two or more
-networks are taken together to check if a supernet, including
-all and only these networks, exists. If it exists then this supernet
-is called the summarized (or aggregated) network.
-It is very important to understand that summarization can only
-occur if there are no holes in the aggregated network, or, in
-other words, if the given networks fill completely the address space
-of the supernet. So the two rules are:
-
-1) The aggregate network must contain +all+ the IP addresses of the
-original networks;
-
-2) The aggregate network must contain +only+ the IP addresses of the
-original networks;
-
-A few examples will help clarify the above. Let's consider for
-instance the following two networks:
-
- ip1 = IPAddress("172.16.10.0/24")
- ip2 = IPAddress("172.16.11.0/24")
-
-These two networks can be expressed using only one IP address
-network if we change the prefix. Let Ruby do the work:
-
- IPAddress::IPv4::summarize(ip1,ip2).map(&:to_string)
- #=> "172.16.10.0/23"
-
-We note how the network `172.16.10.0/23` includes all the
-addresses specified in the above networks, and (more important) includes
-ONLY those addresses.
-
-If we summarized +ip1+ and +ip2+ with the following network:
-
- "172.16.0.0/16"
-
-we would have satisfied rule #1 above, but not rule #2. So
-
- "172.16.0.0/16"
-
-is not an aggregate network for +ip1+ and +ip2+.
-
-If it's not possible to compute a single aggregated network for
-all the original networks, the method returns an array with all the
-aggregate networks found. For example, the following four networks can be
-aggregated in a single `/22`:
-
- ip1 = IPAddress("10.0.0.1/24")
- ip2 = IPAddress("10.0.1.1/24")
- ip3 = IPAddress("10.0.2.1/24")
- ip4 = IPAddress("10.0.3.1/24")
-
- IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
- #=> ["10.0.0.0/22"]
-
-But the following networks can't be summarized in a single
-network:
-
- ip1 = IPAddress("10.0.1.1/24")
- ip2 = IPAddress("10.0.2.1/24")
- ip3 = IPAddress("10.0.3.1/24")
- ip4 = IPAddress("10.0.4.1/24")
-
- IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
- #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
-
-In this case, the two summarizables networks have been aggregated into
-a single `/23`, while the other two networks have been left untouched.
-
-==== Supernetting
-
-Supernetting is a different operation than aggregation, as it only
-works on a single network and returns a new single IPv4 object,
-representing the supernet.
-
-Supernetting is similar to subnetting, except that you getting as a
-result a network with a smaller prefix (bigger host space). For
-example, given the network
-
- ip = IPAddress("172.16.10.0/24")
-
-you can supernet it with a new /23 prefix
-
- ip.supernet(23).to_string
- #=> "172.16.10.0/23"
-
-However if you supernet it with a `/22` prefix, the network address will
-change:
-
- ip.supernet(22).to_string
- #=> "172.16.8.0/22"
-
-This is because `172.16.10.0/22` is not a network anymore, but an host
-address.
-
-== IPv6
-
-IPAddress is not only fantastic for IPv4 addresses, it's also great to
-handle IPv6 addresses family! Let's discover together how to use it in
-our projects.
-
-=== IPv6 addresses
-
-IPv6 addresses are 128 bits long, in contrast with IPv4 addresses
-which are only 32 bits long. An IPv6 address is generally written as
-eight groups of four hexadecimal digits, each group representing 16
-bits or two octet. For example, the following is a valid IPv6
-address:
-
- 2001:0db8:0000:0000:0008:0800:200c:417a
-
-Letters in an IPv6 address are usually written downcase, as per
-RFC. You can create a new IPv6 object using uppercase letters, but
-they will be converted.
-
-==== Compression
-
-Since IPv6 addresses are very long to write, there are some
-simplifications and compressions that you can use to shorten them.
-
-* Leading zeroes: all the leading zeroes within a group can be
- omitted: "0008" would become "8"
-
-* A string of consecutive zeroes can be replaced by the string
- "::". This can be only applied once.
-
-Using compression, the IPv6 address written above can be shorten into
-the following, equivalent, address
-
- 2001:db8::8:800:200c:417a
-
-This short version is often used in human representation.
-
-==== Network Mask
-
-As we used to do with IPv4 addresses, an IPv6 address can be written
-using the prefix notation to specify the subnet mask:
-
- 2001:db8::8:800:200c:417a/64
-
-The /64 part means that the first 64 bits of the address are
-representing the network portion, and the last 64 bits are the host
-portion.
-
-=== Using IPAddress with IPv6 addresses
-
-All the IPv6 representations we've just seen are perfectly fine when
-you want to create a new IPv6 address:
-
- ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"
-
- ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"
-
- ip6 = IPAddress "2001:db8:8:800:200C:417A"
-
-All three are giving out the same IPv6 object. The default subnet mask
-for an IPv6 is 128, as IPv6 addresses don't have classes like IPv4
-addresses. If you want a different mask, you can go ahead and explicit
-it:
-
- ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
-
-Access the address portion and the prefix by using the respective
-methods:
-
- ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
-
- ip6.address
- #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
-
- ip6.prefix
- #=> 64
-
-A compressed version of the IPv6 address can be obtained with the
-`IPv6#compressed` method:
-
- ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"
-
- ip6.compressed
- #=> "2001:db8::8:800:200c:417a"
-
-=== Handling the IPv6 address
-
-Accessing the groups that form an IPv6 address is very easy with the
-`IPv6#groups` method:
-
- ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
-
- ip6.groups
- #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
-
-As with IPv4 addresses, each individual group can be accessed using
-the `IPv6#[]` shortcut method:
-
- ip6[0]
- #=> 8193
- ip6[1]
- #=> 3512
- ip6[2]
- #=> 0
- ip6[3]
- #=> 0
-
-Note that each 16 bits group is expressed in its decimal form. You can
-also obtain the groups into hexadecimal format using the `IPv6#hexs`
-method:
-
- ip6.hexs
- #=> => ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
-
-A few other methods are available to transform an IPv6 address into
-decimal representation, with `IPv6.to_i`
-
- ip6.to_i
- #=> 42540766411282592856906245548098208122
-
-or to hexadecimal representation
-
- ip6.to_hex
- #=> "20010db80000000000080800200c417a"
-
-To print out an IPv6 address in human readable form, use the `IPv6#to_s`, `IPv6#to_string`
-and `IPv6#to_string_uncompressed` methods
-
- ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
-
- ip6.to_string
- #=> "2001:db8::8:800:200c:417a/96"
-
- ip6.to_string_uncompressed
- #=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"
-
-As you can see, `IPv6.to_string` prints out the compressed form, while
-`IPv6.to_string_uncompressed` uses the expanded version.
-
-==== Compressing and uncompressing
-
-If you have a string representing an IPv6 address, you can easily
-compress it and uncompress it using the two class methods IPv6::expand
-and IPv6::compress.
-
-For example, let's say you have the following uncompressed IPv6
-address:
-
- ip6str = "2001:0DB8:0000:CD30:0000:0000:0000:0000"
-
-Here is the compressed version:
-
- IPAddress::IPv6.compress ip6str
- #=> "2001:db8:0:cd30::"
-
-The other way works as well:
-
- ip6str = "2001:db8:0:cd30::"
-
- IPAddress::IPv6.expand ip6str
- #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
-
-These methods can be used when you don't want to create a new object
-just for expanding or compressing an address (although a new object is
-actually created internally).
-
-=== New IPv6 address from other formats
-
-You can create a new IPv6 address from different formats than just a
-string representing the colon-hex groups.
-
-For instance, if you have a data stream, you can use `IPv6::parse_data`,
-like in the following example:
-
- data = " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
-
- ip6 = IPAddress::IPv6::parse_data data
- ip6.prefix = 64
-
- ip6.to_string
- #=> "2001:db8::8:800:200c:417a/64"
-
-A new IPv6 address can also be created from an unsigned 128 bits
-integer:
-
- u128 = 42540766411282592856906245548098208122
-
- ip6 = IPAddress::IPv6::parse_u128 u128
- ip6.prefix = 64
-
- ip6.to_string
- #=>"2001:db8::8:800:200c:417a/64"
-
-Finally, a new IPv6 address can be created from an hex string:
-
- hex = "20010db80000000000080800200c417a"
-
- ip6 = IPAddress::IPv6::parse_hex hex
- ip6.prefix = 64
-
- ip6.to_string
- #=> "2001:db8::8:800:200c:417a/64"
-
-=== Special IPv6 addresses
-
-Some IPv6 have a special meaning and are expressed in a special form,
-quite different than an usual IPv6 address. IPAddress has built-in
-support for unspecified, loopback and mapped IPv6 addresses.
-
-==== Unspecified address
-
-The address with all zero bits is called the +unspecified+ address
-(corresponding to `0.0.0.0` in IPv4). It should be something like this:
-
- 0000:0000:0000:0000:0000:0000:0000:0000
-
-but, with the use of compression, it is usually written as just two
-colons:
-
- ::
-
-or, specifying the netmask:
-
- ::/128
-
-With IPAddress, create a new unspecified IPv6 address using its own
-subclass:
-
- ip = IPAddress::IPv6::Unspecified.new
-
- ip.to_string
- #=> "::/128"
-
-You can easily check if an IPv6 object is an unspecified address by
-using the IPv6#unspecified? method
-
- ip.unspecified?
- #=> true
-
-An unspecified IPv6 address can also be created with the wrapper
-method, like we've seen before
-
- ip = IPAddress "::"
-
- ip.unspecified?
- #=> true
-
-This address must never be assigned to an interface and is to be used
-only in software before the application has learned its host's source
-address appropriate for a pending connection. Routers must not forward
-packets with the unspecified address.
-
-==== Loopback address
-
-The loopback address is a unicast localhost address. If an
-application in a host sends packets to this address, the IPv6 stack
-will loop these packets back on the same virtual interface.
-
-Loopback addresses are expressed in the following form:
-
- ::1
-
-or, with their appropriate prefix,
-
- ::1/128
-
-As for the unspecified addresses, IPv6 loopbacks can be created with
-IPAddress calling their own class:
-
- ip = IPAddress::IPv6::Loopback.new
-
- ip.to_string
- #=> "::1/128"
-
-or by using the wrapper:
-
- ip = IPAddress "::1"
-
- ip.to_string
- #=> "::1/128"
-
-Checking if an address is loopback is easy with the `IPv6#loopback?`
-method:
-
- ip.loopback?
- #=> true
-
-The IPv6 loopback address corresponds to `127.0.0.1` in IPv4.
-
-==== Mapped address
-
-It is usually identified as a IPv4 mapped IPv6 address, a particular
-IPv6 address which aids the transition from IPv4 to IPv6. The
-structure of the address is
-
- ::ffff:w.y.x.z
-
-where `w.x.y.z` is a normal IPv4 address. For example, the following is
-a mapped IPv6 address:
-
- ::ffff:192.168.100.1
-
-IPAddress is very powerful in handling mapped IPv6 addresses, as the
-IPv4 portion is stored internally as a normal IPv4 object. Let's have
-a look at some examples. To create a new mapped address, just use the
-class builder itself
-
- ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
-
-or just use the wrapper method
-
- ip6 = IPAddress "::ffff:172.16.10.1/128"
-
-Let's check it's really a mapped address:
-
- ip6.mapped?
- #=> true
-
- ip6.to_string
- #=> "::ffff:172.16.10.1/128"
-
-Now with the `#ipv4` attribute, we can easily access the IPv4 portion
-of the mapped IPv6 address:
-
- ip6.ipv4.address
- #=> "172.16.10.1"
-
-Internally, the IPv4 address is stored as two 16 bits
-groups. Therefore all the usual methods for an IPv6 address are
-working perfectly fine:
-
- ip6.to_hex
- #=> "00000000000000000000ffffac100a01"
-
- ip6.address
- #=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"
-
-A mapped IPv6 can also be created just by specify the address in the
-following format:
-
- ip6 = IPAddress "::172.16.10.1"
-
-That is, two colons and the IPv4 address. However, as by RFC, the `ffff`
-group will be automatically added at the beginning
-
- ip6.to_string
- => "::ffff:172.16.10.1/128"
-
-making it a mapped IPv6 compatible address.
-
-== Why not using IPAddr?
-
-IPAddr is the IP addresses library that comes with Ruby standard
-lib. We found this library, although very well written, not very
-suitable for all our needs, and not very flexible.
-
-Some quick examples of things you can't do with IPAddr:
-
-* store both the address and the prefix information
-* quickly find the broadcast address of a network
-* iterate over hosts
-* perform subnetting or network aggregation
-
-Many methods and procedures are so old that they have been
-declared deprecated by the IETF, and some others have bugs in their
-implementation.
-
-Moreover, IPAddress is more robust and is already around 50% faster than IPAddr,
-in addition to provide an organic API with logical separation and OO structure.
-
-We hope that IPAddress will address all these issues and meet all your
-needs in network programming.
-
-
-== Community
-
-Want to join the community?
-
-* {IPAddress google group}[http://groups.google.com/group/ruby-ipaddress]
-
-We've created a group to discuss about
-IPAddress future development, features and provide some kind of support.
-Feel free to join us and tell us what you think!
-
-== Thanks to
-
-Thanks to Luca Russo (vargolo) and Simone Carletti
-(weppos) for all the support and technical review. Thanks to Marco Beri,
-Bryan T. Richardson, Nicolas Fevrier, jdpace, Daniele Alessandri, jrdioko,
-Ghislain Charrier, Pawel Krzesniak, Mark Sullivan, Leif Gensert,
-Erik Ahlström, Peter Vandenberk and Steve Rawlinson for their support,
-feedback and bug reports.
-
-== Copyright
-
-Copyright (c) 2009-2015 Marco Ceresa and Mike Mackintosh. See LICENSE for details.
diff --git a/ipaddress.gemspec b/ipaddress.gemspec
index 599c9bd..d49c1aa 100644
--- a/ipaddress.gemspec
+++ b/ipaddress.gemspec
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
s.extra_rdoc_files = [
"CHANGELOG.rdoc",
"LICENSE.txt",
- "README.rdoc"
+ "README.md"
]
s.files = [
".document",
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
"CONTRIBUTING.md",
"Gemfile",
"LICENSE.txt",
- "README.rdoc",
+ "README.md",
"Rakefile",
"VERSION",
"ipaddress.gemspec",