Fork me on GitHub

Project Notes

#240 Addresses with Ruby

All about dissecting IPv4 addresses with ruby including networks, netmasks and CIDR

Notes

IP addresses are understood for routing purposes according to the Classless Inter-Domain Routing (CIDR) strategy as specified in RFC1519.

While this also applies to IPv6 addresses, I’ll just consider IPv4 addresses here.

CIDR with IPv4

A given IPv4 addresses (e.g. 12.13.14.15) has two parts:

  • network prefix: defined by the most significant bits. This identifies a whole network or subnet.
  • host identifier: defined by the least significant bits. This specifies a particular interface of a host on that network.

The subnet mask defines the boundary between network prefix and host identifier.

For example:

  • 198.51.100.14/24 is CIDR notation meaning
    • IP address = 198.51.100.14
    • and 24 bits of network prefix
  • 24 bits of network prefix is ofter written as the equivalent subnet netmask 255.255.255.0
  • that leaves 8 bits for host identifiers within the network
    • i.e. 256 host identifiers / IP addresses
  • the first IP in the network is sometimes referred to as the “network address”
    • i.e. 198.51.100.0 in this case
  • the last IP in the network is used as a broadcast address for the network
    • i.e. 198.51.100.255 in this case
  • that leaves 254 addresses to actually be used for host interfaces in the network

The Subnet Calculator site is an easy way to test/check IP addresses

Dissecting an IPv4 Address with Ruby

The IPAddr standard library provides the basic tools for dissecting and IPv4 address (with a bit of finagling).

The ipv4info.rb script provides an example of how to parse and use an IPv4 address. Some example runs..

Given a network address and CIDR mask, it correctly extracts the network and host information:

$ ./ipv4info.rb 198.51.100.14/24
Given: 198.51.100.14/24, inspected using the IPAddr stdlib..

               IPv4? : true
            Private? : false
                CIDR : 24
         Subnet mask : 255.255.255.0
     Network address : 198.51.100.0
Addresses in network : 256
    Hosts in network : 254

It recognises private (unquotable) addresses:

$ ./ipv4info.rb 192.168.10.10/28
Given: 192.168.10.10/28, inspected using the IPAddr stdlib..

               IPv4? : true
            Private? : true
                CIDR : 28
         Subnet mask : 255.255.255.240
     Network address : 192.168.10.0
Addresses in network : 16
    Hosts in network : 14

Adjusting the CIDR mask resizes the network accordingly:

$ ./ipv4info.rb 192.168.10.10/30
Given: 192.168.10.10/30, inspected using the IPAddr stdlib..

               IPv4? : true
            Private? : true
                CIDR : 30
         Subnet mask : 255.255.255.252
     Network address : 192.168.10.8
Addresses in network : 4
    Hosts in network : 2

And if no CIDR mask is provided, the address is treated as a “network of 1 host”:

$ ./ipv4info.rb 192.168.10.10
Given: 192.168.10.10, inspected using the IPAddr stdlib..

               IPv4? : true
            Private? : true
                CIDR : 32
         Subnet mask : 255.255.255.255
     Network address : 192.168.10.10
Addresses in network : 1
    Hosts in network : 1

PS: there’s a test suite for the script:

$ ./test_ipv4info.rb
Run options: --seed 51973

# Running:

.....................

Finished in 0.002686s, 7818.3173 runs/s, 7818.3173 assertions/s.

21 runs, 21 assertions, 0 failures, 0 errors, 0 skips

netaddr gem

The IPAddr library has some limitations:

  • netmask is not directly provided, but can be generated with IPAddr e.g. IPAddr.new('255.255.255.255').mask(cidr).to_s
  • host and address counts are not directly provided, so need to be calculated

The netaddr gem is a Ruby library for performing calculations on IPv4 and IPv6 subnets. It handles makes most of the IPAddr limitations, with the exception of the private address detection.

See ipv4info_netaddr.rb for a rewrite of the script but using the netaddr gem. It behaves the same, bu needs a bundle first to make sure the gem is installed:

$ bundle install
$ ./ipv4info_netaddr.rb 198.51.100.14/24
Given: 198.51.100.14/24, inspected using the NetAddr gem:

               IPv4? : true
            Private? : false
                CIDR : 24
         Subnet mask : 255.255.255.0
     Network address : 198.51.100.0
Addresses in network : 256
    Hosts in network : 254

PS: there’s also a test suite:

$ ./test_ipv4info_netaddr.rb
Run options: --seed 6405

# Running:

.....................

Finished in 0.002640s, 7954.5452 runs/s, 7954.5452 assertions/s.

21 runs, 21 assertions, 0 failures, 0 errors, 0 skips

Credits and References

About LCK#240 ruby
Project Source on GitHub Return to the Project Catalog

LittleCodingKata is my collection of programming exercises, research and code toys broadly spanning things that relate to programming and software development (languages, frameworks and tools).

These range from the trivial to the complex and serious. Many are inspired by existing work and I'll note credits and references where applicable. The focus is quite scattered, as I variously work on things new and important in the moment, or go back to revisit things from the past.

This is primarily a personal collection for my own edification and learning, but anyone who stumbles by is welcome to borrow, steal or reference the work here. And if you spot errors or issues I'd really appreciate some feedback - create an issue, send me an email or even send a pull-request.

LittleArduinoProjects LittleModelArt More on my blog