Rubyとipaddressライブラリで、ネットワークエンジニアがよく使うIPアドレスの計算する方法を簡単に解説します。
より詳細なドキュメントはライブラリのドキュメントを参照してください。
ライブラリはIPv4アドレスとIPv6アドレスに対応していますが、今回はIPv4アドレスのみ取り扱います。
試した環境は下記のとおりです。RubyGemsでライブラリをインストールして使用します。
- Ruby 2.3.1
- ipaddress 0.8.3
Gemfile
source "https://rubygems.org"
gem 'ipaddress'
ちなみに、標準ライブラリのipaddrでは、ネットワークアドレスやブロードキャストアドレスを直接求められないため、ネットワークエンジニアが利用するにはちょっと向きません。
ipaddressの基本的な機能
色々なIPアドレスの読み込み
require 'ipaddress'
# プレフィックス長を指定したIPアドレス
ipaddr = IPAddress('192.168.1.124/24')
ipaddr.to_string
=> "192.168.1.124/24"
# プレフィックス長を省略すると/32になる
ipaddr = IPAddress('192.168.1.124')
ipaddr.to_string
=> "192.168.1.124/32"
# サブネットマスクで指定も可能
ipaddr = IPAddress('192.168.1.124/255.255.255.0')
ipaddr.to_string
=> "192.168.1.124/24"
# 10進数からIPアドレスに変換
ipaddr = IPAddress(0)
ipaddr.to_string
=> "0.0.0.0/32"
# 16進数からIPアドレスに変換
ipaddr = IPAddress(0xffffffff)
ipaddr.to_string
=> "255.255.255.255/32"
よく使うIPアドレスの表現
require 'ipaddress'
ipaddr = IPAddress('192.168.1.124/24')
=> #<IPAddress::IPv4:0x0055c4134bccb0
@address="192.168.1.124",
@octets=[192, 168, 1, 124],
@prefix=24,
@u32=3232235900>
# プレフィックス表記
ipaddr.to_string
=> "192.168.1.124/24"
# ホストアドレス
ipaddr.to_s
=> "192.168.1.124"
ipaddr.address
=> "192.168.1.124"
# サブネットマスク
ipaddr.netmask
=> "255.255.255.0"
# ネットワークアドレス
ipaddr.network.to_s
=> "192.168.1.0"
# ブロードキャストアドレス
ipaddr.broadcast.to_s
=> "192.168.1.255"
IPAddress("0.0.0.0/0").broadcast.to_s
=> "255.255.255.255"
# プレフィックス長
ipaddr.prefix
=> 24
# ワイルドカードマスク
netmask = IPAddress(ipaddr.netmask)
wildmask = IPAddress(2**32 - netmask.to_u32 - 1)
=> #<IPAddress::IPv4:0x0055c412d1b470
@address="0.0.0.255",
@octets=[0, 0, 0, 255],
@prefix=32,
@u32=255>
wildmask.to_s
=> "0.0.0.255"
# サブネットマスク(プレフィックス)を指定
ipaddr = IPAddress(0)
=> #<IPAddress::IPv4:0x0055afb75b7478
@address="0.0.0.0",
@octets=[0, 0, 0, 0],
@prefix=32,
@u32=0>
ipaddr.to_string
=> "0.0.0.0/32"
ipaddr.prefix = 0
=> 0
ipaddr.to_string
=> "0.0.0.0/0"
IPアドレスの分割と集約
require 'ipaddress'
# 計算対象のIPアドレス
ipaddr = IPAddress('192.168.0.0/16')
=> #<IPAddress::IPv4:0x0055c412eff778
@address="192.168.0.0",
@octets=[192, 168, 0, 0],
@prefix=16,
@u32=3232235520>
# /16を2分割
## 192.168.0.0/16
## => 192.168.0.0/17, 192.168.128.0/17
subnets = ipaddr.split(2)
=> [#<IPAddress::IPv4:0x0055c412a73010
@address="192.168.0.0",
@octets=[192, 168, 0, 0],
@prefix=17,
@u32=3232235520>,
#<IPAddress::IPv4:0x0055c412a72958
@address="192.168.128.0",
@octets=[192, 168, 128, 0],
@prefix=17,
@u32=3232268288>]
# subnets配列を集約(サマライズ)する
## 192.168.0.0/17
## 192.168.128.0/17
## => 192.168.0.0/16
IPAddress::IPv4.summarize(*subnets)
=> [#<IPAddress::IPv4:0x0055c4133ce7e0
@address="192.168.0.0",
@octets=[192, 168, 0, 0],
@prefix=16,
@u32=3232235520>]
# ipaddrs配列を可能な限り集約(サマライズ)する
## 192.168.0.0/24
## 192.168.1.0/24
## 192.168.2.0/24
## 192.168.3.0/24
## 192.168.4.0/24
## => 192.168.0.0/22, 192.168.4.0/24
ipaddrs = %w|192.168.0.0/24 192.168.1.0/24 192.168.2.0/24 192.168.3.0/24 192.168.4.0/24|
=> ["192.168.0.0/24", "192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24", "192.168.4.0/24"]
ipaddrs = ipaddrs.map{|ipaddr| IPAddress(ipaddr)}
=> [#<IPAddress::IPv4:0x0055c412b9cf40
@address="192.168.0.0",
@octets=[192, 168, 0, 0],
@prefix=24,
@u32=3232235520>,
#<IPAddress::IPv4:0x0055c412b9ca40
@address="192.168.1.0",
@octets=[192, 168, 1, 0],
@prefix=24,
@u32=3232235776>,
#<IPAddress::IPv4:0x0055c412b9c590
@address="192.168.2.0",
@octets=[192, 168, 2, 0],
@prefix=24,
@u32=3232236032>,
#<IPAddress::IPv4:0x0055c412b9c0e0
@address="192.168.3.0",
@octets=[192, 168, 3, 0],
@prefix=24,
@u32=3232236288>,
#<IPAddress::IPv4:0x0055c412b7bbd8
@address="192.168.4.0",
@octets=[192, 168, 4, 0],
@prefix=24,
@u32=3232236544>]
supernets = IPAddress::IPv4.summarize(*ipaddrs)
=> [#<IPAddress::IPv4:0x0055c4125bf9d8
@address="192.168.0.0",
@octets=[192, 168, 0, 0],
@prefix=22,
@u32=3232235520>,
#<IPAddress::IPv4:0x0055c4125beb78
@address="192.168.4.0",
@octets=[192, 168, 4, 0],
@prefix=24,
@u32=3232236544>]
supernets.map(&:to_string)
=> ["192.168.0.0/22", "192.168.4.0/24"]
# 集約アドレスを指定のプレフィックス長で分割する
## /24を/26に分割する
ipaddr = IPAddress('192.168.1.0/24')
=> #<IPAddress::IPv4:0x0055afb8324de0
@address="192.168.1.0",
@octets=[192, 168, 1, 0],
@prefix=24,
@u32=3232235776>
subnets = ipaddr.subnet(26)
=> [#<IPAddress::IPv4:0x0055afb84032e8
@address="192.168.1.0",
@octets=[192, 168, 1, 0],
@prefix=26,
@u32=3232235776>,
#<IPAddress::IPv4:0x0055afb8402c30
@address="192.168.1.64",
@octets=[192, 168, 1, 64],
@prefix=26,
@u32=3232235840>,
#<IPAddress::IPv4:0x0055afb84025c8
@address="192.168.1.128",
@octets=[192, 168, 1, 128],
@prefix=26,
@u32=3232235904>,
#<IPAddress::IPv4:0x0055afb8401f60
@address="192.168.1.192",
@octets=[192, 168, 1, 192],
@prefix=26,
@u32=3232235968>]
> subnets.size
=> 4
その他の表記
require 'ipaddress'
# オクテット配列
ipaddr.octets
=> [192, 168, 1, 124]
# 2進数
ipaddr.bits
=> "11000000101010000000000101111100"
# 10進数
ipaddr.to_u32
=> 3232235900
ipaddr.u32
=> 3232235900
ipaddr.to_i
=> 3232235900
# 16進数
ipaddr.hex
=> "c0a8017c"
# DNS逆引きレコード
ipaddr.reverse
=> "124.1.168.192.in-addr.arpa"
# ホストアドレスの配列(ネットワークアドレスとブロードキャストを除く)
ipaddr.hosts
=> [#<IPAddress::IPv4:0x0055c412b92ef0
@address="192.168.1.1",
@octets=[192, 168, 1, 1],
@prefix=24,
@u32=3232235777>,
#<IPAddress::IPv4:0x0055c412b92860
@address="192.168.1.2",
@octets=[192, 168, 1, 2],
@prefix=24,
@u32=3232235778>,
〜略〜
#<IPAddress::IPv4:0x0055c411ea6660
@address="192.168.1.254",
@octets=[192, 168, 1, 254],
@prefix=24,
@u32=3232236030>]
よくある例
複数のIPアドレスから集約アドレスを計算する
summarize.rb
require 'ipaddress'
# サマライズ対象のIPアドレス(重複しててもOK)
networks = <<EOL.lines
192.168.0.0/25
192.168.0.128/25
192.168.1.0/24
192.168.3.0/24
192.168.4.0/24
192.168.5.0/26
192.168.128.0/22
192.168.132.0/22
192.168.128.0/21
EOL
# サマライズ計算
ipaddresses = networks.map{|net| IPAddress(net)}
summarized_networks = IPAddress::IPv4.summarize(*ipaddresses)
# サマライズ結果を出力
puts summarized_networks.map(&:to_string)
実行結果
$ ruby summarize.rb
192.168.0.0/23
192.168.3.0/24
192.168.4.0/24
192.168.5.0/26
192.168.128.0/21
シスコルータでよくあるコンフィグ生成の例
シスコルータのインタフェースにIPアドレスを割り振り、OSPFを有効化する例です。
config.rb
require 'ipaddress'
# IPアドレスからワイルドカードマスクを計算
def wildmask(ipaddr)
netmask = IPAddress(ipaddr.netmask)
IPAddress(2**32 - netmask.to_u32 - 1)
end
# パラメータ
interface = 'FastEthernet0'
ipaddr = IPAddress('192.168.1.124/24')
# コンフィグ生成
puts <<EOL
interface #{interface}
ip address #{ipaddr} #{ipaddr.netmask}
no shutdown
router ospf 1
no passive-interface #{interface}
network #{ipaddr.network} #{wildmask(ipaddr)}
EOL
出力結果
$ ruby config.rb
interface FastEthernet0
ip address 192.168.1.124 255.255.255.0
no shutdown
router ospf 1
no passive-interface FastEthernet0
network 192.168.1.0 0.0.0.255