ipaddress.rb
Heads up: This description was created by AI and might not be 100% accurate.
このRubyスクリプトは、IPアドレスとサブネットマスクを扱うためのユーティリティ関数群です。それぞれの関数は、IPアドレスやサブネットマスクの検証、CIDR表記からマスク表記への変換、マスク表記からCIDR表記への変換などの処理を行います。
1. mask_to_cidr(mask)
- 特徴: IPアドレスのマスク文字列(例: “255.255.255.0”)を受け取り、そのマスクが表すCIDR値(プレフィックス長)を計算します。
- アルゴリズム:
- 入力文字列
maskをドットで分割し、各部分文字列(バイト)を数値に変換します。 - 各バイトを2進数に変換し、’1’ の個数をカウントします。
- すべてのバイトの ‘1’ の個数の合計を計算し、結果をCIDR値として返します。
- 入力文字列
2. cidr_to_mask(cidr)
- 特徴: CIDR表記(プレフィックス長)を受け取り、そのプレフィックス長に対応するIPマスク文字列を生成します。
- アルゴリズム:
cidrの値に基づいて、’1’ をcidr回連結した文字列を作成します。- 残りのビット(32 -
cidr)を ‘0’ で連結します。 - 連結された文字列を8ビット(1バイト)のチャンクに分割し、各チャンクを2進数に変換して10進数に変換します。
- 各チャンクをドットで連結してIPマスク文字列を生成し、返します。
3. ip_address?(ip)
- 特徴: 文字列として与えられたIPアドレスが有効な形式であるかどうかを検証します。
- アルゴリズム:
- 入力文字列
ipをドットで分割し、各部分文字列が4つあるかを確認します。 - 各部分文字列が正の整数であり、255を超えないかを確認します。
- 各部分文字列に先頭ゼロが含まれていないかを確認します。
- すべての条件を満たす場合、有効なIPアドレスと判定します。
- 入力文字列
4. subnet_mask?(mask)
- 特徴: 文字列として与えられたマスク文字列が有効なサブネットマスクであるかどうかを検証します。
- アルゴリズム:
- 入力文字列
maskをドットで分割し、各部分文字列が4つあるかを確認します。 - 各部分文字列が正の整数であり、255を超えないかを確認します。
- 各部分文字列の32進数表現を生成します。
- 32進数表現が’01’を含まないか、つまり、全0または全1であるかを確認します。
- すべての条件を満たす場合、有効なサブネットマスクと判定します。
- 入力文字列
5. network_address?(ip, mask)
- 特徴: IPアドレスとサブネットマスクが有効なネットワークアドレスを構成するかどうかを検証します。
- アルゴリズム:
ip_address?関数を使用して、IPアドレスが有効な形式であるかを確認します。subnet_mask?関数を使用して、サブネットマスクが有効な形式であるかを確認します。- IPアドレスとサブネットマスクをそれぞれ構成要素に分割します。
- IPアドレスの各ビットとサブネットマスクの対応するビットをAND演算(ビット単位の論理積)します。
- 結果が0でない場合、ネットワークアドレスの条件を満たさないため、falseを返します。
- すべてのビットに対して0でないAND演算が成功した場合、ネットワークアドレスの条件を満たしているため、trueを返します。
Ruby code snippet
# frozen_string_literal: true
#=> nil
def mask_to_cidr(mask)
# count num of 1.
mask.split('.').sum { it.to_i.to_s(2).count('1') }
end
#=> :mask_to_cidr
p mask_to_cidr('255.255.255.0')
24
#=> 24
def cidr_to_mask(cidr)
# Repeat '1' cidr times and then pad with '0's to make 32 bits.
bits = '1' * cidr + '0' * (32 - cidr)
# split into chunks of 8 characters.
bits.scan(/.{8}/).map { it.to_i(2) }.join('.')
end
#=> :cidr_to_mask
p cidr_to_mask(24)
"255.255.255.0"
#=> "255.255.255.0"
def ip_address?(ip)
parts = ip.split('.')
return false unless parts.size == 4
parts.all? do |p|
return false unless p =~ /^\d+$/
num = p.to_i
return false if num.negative? || num > 255
return false if p != num.to_s # 先頭ゼロ防止
true
end
end
#=> :ip_address?
p ip_address?('127.0.0.1')
true
#=> true
def subnet_mask?(mask)
parts = mask.split('.')
return false unless parts.size == 4
binary = ''
parts.each do |p|
return false unless p =~ /^\d+$/
num = p.to_i
return false if num.negative? || num > 255
binary += num.to_s(2).rjust(8, '0')
end
# 1の後に0が続く形式のみ許可
return false if binary.include?('01')
# 全0 or 全1は除外
return false if binary == '0' * 32 || binary == '1' * 32
true
end
#=> :subnet_mask?
p subnet_mask?('255.0.0.0')
true
#=> true
def network_address?(ip, mask)
return false unless ip_address?(ip)
return false unless subnet_mask?(mask)
ip_parts = ip.split('.').map(&:to_i)
mask_parts = mask.split('.').map(&:to_i)
4.times do |i|
# ホスト部が0かチェック
return false if (ip_parts[i] & (~mask_parts[i] & 0xFF)) != 0
end
true
end
#=> :network_address?
p network_address?('10.0.0.0', cidr_to_mask(16))
true
#=> true
Executed with Ruby 3.4.9.