Low commit activity in last 3 years
Parse and classify IPv4/IPv6 addresses with private, loopback, and multicast detection. Supports CIDR range operations including size calculation, membership testing, and enumeration. Built on Ruby stdlib ipaddr.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-ip_addr

Tests Gem Version Last updated

Enhanced IP address library with CIDR, classification, and range operations

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-ip_addr"

Or install directly:

gem install philiprehberger-ip_addr

Usage

require "philiprehberger/ip_addr"

ip = Philiprehberger::IpAddr.parse('192.168.1.1')
ip.v4?      # => true
ip.private? # => true
ip.to_i     # => 3232235777
ip.to_s     # => "192.168.1.1"

Classification

ip = Philiprehberger::IpAddr.parse('127.0.0.1')
ip.loopback?  # => true

ip = Philiprehberger::IpAddr.parse('224.0.0.1')
ip.multicast? # => true

ip = Philiprehberger::IpAddr.parse('::1')
ip.v6?      # => true
ip.loopback? # => true

ip = Philiprehberger::IpAddr.parse('169.254.1.1')
ip.link_local? # => true

ip = Philiprehberger::IpAddr.parse('10.0.0.1')
ip.reserved?   # => true (private, loopback, multicast, or link-local)

ip = Philiprehberger::IpAddr.parse('8.8.8.8')
ip.reserved?   # => false

Comparison and Arithmetic

a = Philiprehberger::IpAddr.parse('10.0.0.1')
b = Philiprehberger::IpAddr.parse('10.0.0.5')
a < b       # => true
a.succ.to_s # => "10.0.0.2"
b.pred.to_s # => "10.0.0.4"

[b, a].sort.map(&:to_s) # => ["10.0.0.1", "10.0.0.5"]

CIDR Ranges

range = Philiprehberger::IpAddr.range('10.0.0.0/24')
range.size                    # => 256
range.include?('10.0.0.42')   # => true
range.include?('10.0.1.1')    # => false

range = Philiprehberger::IpAddr.range('10.0.0.0/30')
range.each { |ip| puts ip }
range.to_a.map(&:to_s)  # => ["10.0.0.0", "10.0.0.1", "10.0.0.2", "10.0.0.3"]

Subnet Operations

range = Philiprehberger::IpAddr.range('192.168.1.0/24')
range.network.to_s   # => "192.168.1.0"
range.broadcast.to_s # => "192.168.1.255"
range.netmask        # => "255.255.255.0"
range.prefix         # => 24

other = Philiprehberger::IpAddr.range('192.168.1.128/25')
range.overlap?(other) # => true

Subnet splitting

range = Philiprehberger::IpAddr.range('10.0.0.0/24')
range.subnets(prefix: 26).map(&:to_s)
# => ["10.0.0.0/26", "10.0.0.64/26", "10.0.0.128/26", "10.0.0.192/26"]

range.subnets(prefix: 26).first.size # => 64

v6 = Philiprehberger::IpAddr.range('2001:db8::/32')
v6.subnets(prefix: 34).count # => 4

range.subnets(prefix: 26) # => #<Enumerator: ...> when called without a block

Bytes

addr = Philiprehberger::IpAddr.parse("192.168.0.1")
addr.to_bytes # => [192, 168, 0, 1]

Reverse DNS PTR

Philiprehberger::IpAddr.parse("192.0.2.5").to_ptr
# => "5.2.0.192.in-addr.arpa"

Philiprehberger::IpAddr.parse("2001:db8::1").to_ptr
# => "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"

API

Method Description
IpAddr.parse(str) Parse an IP address string into an Address
IpAddr.range(cidr) Create a CIDR range object
Address#v4? True if IPv4
Address#v6? True if IPv6
Address#private? True if private/ULA address
Address#loopback? True if loopback address
Address#multicast? True if multicast address
Address#link_local? True if link-local address
Address#reserved? True if private, loopback, multicast, or link-local
Address#to_i Numeric representation
Address#to_s String representation
Address#to_bytes Octets (4 for IPv4, 16 for IPv6)
Address#to_ptr Reverse-DNS PTR record name (*.in-addr.arpa or *.ip6.arpa)
Address#<=>(other) Compare addresses for sorting
Address#succ Next IP address
Address#pred Previous IP address
Range#size Number of addresses in range
Range#include?(ip) Check if address is in range
Range#each Iterate over all addresses
Range#to_a Array of all addresses
Range#network Network address of the CIDR block
Range#broadcast Broadcast/last address of the CIDR block
Range#prefix CIDR prefix length
Range#netmask Subnet mask (dotted-decimal for IPv4)
Range#overlap?(other) Check if two ranges share addresses
Range#subnets(prefix:) Yield equal-size child subnets at the given prefix length

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT