README.rdoc in ipaddress-0.5.0 vs README.rdoc in ipaddress-0.6.0
- old
+ new
@@ -1,21 +1,39 @@
= IPAddress
IPAddress is a Ruby library designed to make the use of IPv4 and IPv6
-addresses easy, powerful and enjoyable. It provides a complete set of
+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.
-=== Why not using IPAddr?
+== Requirements
+* Ruby >= 1.8.6 (not tested with previous versions)
+
+IPAddress works perfectly on:
+
+* Ruby 1.8.6 (2007-03-13 patchlevel 0)
+* Ruby 1.8.7
+* Ruby 1.9.1
+* Ruby 1.9.2dev (2010-06-08 revision 28230)
+* Ruby 1.9.2dev (2010-07-15 revision 28653)
+* Rubinius 1.0.1 (1.8.7 release 2010-06-03 JI)
+* Ironruby >= 1.0
+
+It hasn't yet been tested on any other platform, so if you want to collaborate feel
+free to send a small report to my email address, or
+{join the discussion}[http://groups.google.com/group/ruby-ipaddress].
+
+== 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:
@@ -23,14 +41,17 @@
* store both the address and the prefix information
* quickly find the broadcast address of a network
* iterate over hosts
* perform subnetting or network aggregation
+Moreover, many methods and procedures are so old that they have been
+declared deprecated by the IETF.
+
We hope that IPAddress will address all these issues and meet all your
needs in network programming.
-= Installation
+== Installation
Install the library using rubygems
$ gem install ipaddress
@@ -39,40 +60,39 @@
require 'rubygems' # optional
require 'ipaddress'
Another way would be to clone the git repository
- $ git clone git://github.com/bluemonk/net-dns.git
+ $ git clone git://github.com/bluemonk/ipaddress.git
And then install the library
$ cd ipaddress
ipaddress$ rake install
-= Documentation
+== 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 the following address
+The latest documentation can be found online at
+{this address}[http://marcoceresa.com/ipaddress]
-http://marcoceresa.com/ipaddress
+== Usage
-= Usage
-
In this section I will illustrate how to use the IPAddress library
through some examples of common tasks.
-== IPv4
+=== 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
+==== 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.
@@ -92,11 +112,11 @@
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.
-=== Classful networks
+==== Classful networks
If you don't specify a prefix (or a subnet mask), then the library
will create an object base on the CLASSFUL network from the given
IP. Remember the CLASSFUL network are the following (RFC 791)
@@ -122,14 +142,14 @@
#=> true
These methods are only checking the address portion of an IP, and are
indipendent from its prefix.
-For more information on CLASSFUL networks visit the following
-Wikipedia page: http://en.wikipedia.org/wiki/Classful_network
+For more information on CLASSFUL networks visit the
+{Wikipedia page}[http://en.wikipedia.org/wiki/Classful_network]
-=== Handling the IPv4 address
+==== Handling the IPv4 address
Once created, you can obtain the attributes for an IPv4 object:
ip = IPAddress("172.16.10.1/24")
@@ -155,32 +175,34 @@
ip[1]
#=> 16
If you need to print out the IPv4 address in a canonical form, you can
-use IPv4#to_s
+use IPv4#to_string
- ip.to_s
+ ip.to_string
#=> "172.16.10.l/24"
-=== Changing netmask
+==== Changing netmask
You can set a new prefix (netmask) after creating an IPv4
object. For example:
ip.prefix = 25
- ip.to_s
+
+ ip.to_string
#=> "172.16.10.l/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_s
+
+ ip.to_string
#=> "172.16.10.1/30"
-=== Working with networks, broadcasts and addresses
+==== 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.
@@ -197,19 +219,22 @@
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_s
+ net.to_string
#=> "172.16.10.0/24"
The IPv4#network method 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
@@ -224,10 +249,12 @@
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".
@@ -235,17 +262,20 @@
Method IPv4#broadcast has the same behaviour 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_s
+ 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
@@ -272,25 +302,26 @@
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_s
+ ip.first.to_string
#=> "172.16.10.1/24"
- ip.last.to_s
+ ip.last.to_string
#=> "172.16.10.254/24"
-=== IP special formats
+==== 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
@@ -320,16 +351,16 @@
ip.to_ipv6
#=> "ac10:0a01"
-== Network design with IPAddress
+=== Network design with IPAddress
IPAddress includes a lot of useful methods to manipulate IPv4 and IPv6
networks and do some basic network design.
-=== Subnetting
+==== 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.
@@ -345,11 +376,11 @@
#=> [#<IPAddress::IPv4:0xb7b10e10 @octets=[172,16,10,0] [...]
#<IPAddress::IPv4:0xb7b0f1b4 @octets=[172,16,10,64] [...]
#<IPAddress::IPv4:0xb7b0e5ac @octets=[172,16,10,128] [...]
#<IPAddress::IPv4:0xb7b0e0c0 @octets=[172,16,10,192] [...]]
- subnets.map{|i| i.to_s}
+ 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"]
You can also use method IPv4#subnets, which is an alias for
IPv4#/. Please note that you don't have to specify a network to
@@ -357,72 +388,75 @@
calculate the network number for that network and then subnet it. For
example:
ip = IPAddress("172.16.10.58/24")
- ip.subnet(4).map{|i| i.to_s}
+ ip.subnet(4).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"]
Usually, subnetting implies dividing a network to a number of subnets
which is a power of two: in this way, you can be sure that the network
will be divived evenly, and all the subnets will have the same number
of hosts.
-=== Uneven subnetting
+==== Uneven subnetting
IPAddress also handles un-even subnetting: if you specify any number
(up to the prefix limit), the network will be divided so that the
first power-of-two networks will be even, and all the rest will just
fill out the space.
As an example, let's divide network 172.16.10.0/24 into 3 different subnets:
network = IPAddress("172.16.10.0/24")
- network.subnet(3).map{|i| i.to_s}
+
+ network.subnet(3).map{|i| i.to_string}
#=> ["172.16.10.0/26",
"172.16.10.64/26",
"172.16.10.128/25"]
We can go even further and divide into 11 subnets:
network = IPAddress("172.16.10.0/24")
- network.subnet(11).map{|i| i.to_s}
+
+ network.subnet(11).map{|i| i.to_string}
#=> ["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 remaning space.
-=== Summarization
+==== 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;
+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).to_s
+ IPAddress::IPv4::summarize(ip1,ip2).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.
@@ -445,27 +479,28 @@
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).to_s
- #=> "10.0.0.0/22",
+ 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_s}
+
+ 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
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.
@@ -475,30 +510,29 @@
ip = IPAddress("172.16.10.0/24")
you can supernet it with a new /23 prefix
- ip.supernet(23).to_s
+ 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_s
+ 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
-=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
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 octect. For example, the following is a valid IPv6
@@ -508,11 +542,11 @@
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
+==== Compression
Since IPv6 addresses are very long to write, there are some
semplifications and compressions that you can use to shorten them.
* Leading zeroes: all the leading zeroes within a group can be
@@ -526,22 +560,22 @@
1080::8:800:200c:417a
This short version is often used in human representation.
-=== Network Mask
+==== 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:
1080::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
+=== 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 "1080:0000:0000:0000:0008:0800:200C:417A"
@@ -574,11 +608,11 @@
ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"
ip6.compressed
#=> "2001:db8::8:800:200c:417a"
-== Handling the IPv6 address
+=== 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"
@@ -614,25 +648,25 @@
or to hexadecimal representation
ip6.to_hex
#=> "20010db80000000000080800200c417a"
-To print out an IPv6 address in human readable form, use the IPv6#to_s
-and IPv6#to_string methods
+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_s
+ ip6.to_string
#=> "2001:db8::8:800:200c:417a/96"
- ip6.to_string
+ ip6.to_string_uncompressed
#=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"
-As you can see, IPv6.to_s prints out the compressed form, while
-IPv6.to_string uses the expanded version.
+As you can see, IPv6.to_string prints out the compressed form, while
+IPv6.to_string_uncompressed uses the expanded version.
-=== Compressing and uncompressing
+==== 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.
@@ -655,11 +689,11 @@
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
+=== 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,
@@ -668,41 +702,41 @@
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
+ 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 = 21932261930451111902915077091070067066
ip6 = IPAddress::IPv6::parse_u128 u128
ip6.prefix = 64
- ip6.to_s
+ ip6.to_string
#=> "1080::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_s
+ ip6.to_string
#=> "2001:db8::8:800:200c:417a/64"
-== Special IPv6 addresses
+=== 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 builtin
support for unspecified, loopback and mapped IPv6 addresses.
-=== Unspecified address
+==== 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
@@ -719,12 +753,12 @@
With IPAddress, create a new unspecified IPv6 address using its own
subclass:
ip = IPAddress::IPv6::Unspecified.new
- ip.to_s
- #=> => "::/128"
+ ip.to_string
+ #=> "::/128"
You can easily check if an IPv6 object is an unspecified address by
using the IPv6#unspecified? method
ip.unspecified?
@@ -741,11 +775,11 @@
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
+==== 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.
@@ -760,29 +794,29 @@
As for the unspecified addresses, IPv6 loopbacks can be created with
IPAddress calling their own class:
ip = IPAddress::IPv6::Loopback.new
- ip.to_s
+ ip.to_string
#=> "::1/128"
or by using the wrapper:
ip = IPAddress "::1"
- ip.to_s
+ 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
+==== 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
@@ -807,12 +841,12 @@
Let's check it's really a mapped address:
ip6.mapped?
#=> true
- ip6.to_s
- #=> "::FFFF:172.16.10.1/128"
+ 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
@@ -834,32 +868,32 @@
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_s
+ ip6.to_string
=> "::ffff:172.16.10.1/128"
making it a mapped IPv6 compatible address.
-= Future versions:
+== Community
-Some new features we'd like to add in the future versions:
+Want to join the community?
-* support for wildmasks
-* network design methods for IPv6
-* parameter to IPv4#subnet to select where to fill the space
- (beginning or ending)
-* method to check if a network is private
+* {IPAddress google group}[http://groups.google.com/group/ruby-ipaddress]
-Stay tuned!
+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
-Thanks to Luca Russo (vargolo) for all the support and technical
-review.
+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 and Steve Rawlinson for
+their support, feedback and bug reports.
-= Copyright
+== Copyright
Copyright (c) 2009-2010 Marco Ceresa. See LICENSE for details.
\ No newline at end of file