小池啓仁 ヒロヒト応援ブログ By はてな

小池啓仁(コイケヒロヒト)の動画など。

小池啓仁 ヒロヒト応援ブログ By はてな

ネットワークアドレスを求める!

たとえば、IPアドレスIPv4)は32ビットで、32ビット内がネットワークアドレスとマシンアドレスになっています。
そして、IPアドレスサブネットマスクするとネットワークアドレスが求まりますね。
つまり、任意のマシンが、どのネットワークアドレスに属するかは、IPアドレスサブネットマスク論理積すれば、分かるのです。

  • '1'の文字は16進では『31』で2進数では『00110001』です。
  • '0'の文字は16進では『30』で2進数では『00110000』です。
  • 文字1『00110001』と文字0『00110000』の論理積は、文字0『00110000』になります。
  • 文字1『00110001』と文字1『00110001』の論理積は、文字1『00110001』になります。


一方、Perlではビット演算子論理積『&』がありますね。
1と0の文字の論理積の場合は、文字列でもビット演算子論理積『&』が使えるのです!


たとえば、サブネットマスク255.255.255.0のIPアドレス172.11.22.33のネットワークアドレスは、172.11.22.0ですね。
これをPerlで計算すると以下の感じになります。

use strict;
use warnings;

# IPアドレスのドットアドレスをビット列の文字列へ変換
print dec2bin4IP('255.255.255.0'), "\n";

# IPアドレスのビット列の文字列をドットアドレスへ変換
print bin2dec4IP(dec2bin4IP('255.255.255.0')), "\n";

# マスクしてネットワークアドレスを求める
print bin2dec4IP(dec2bin4IP('255.255.255.0') & dec2bin4IP('172.11.22.33')), "\n";

sub dec2bin4IP {
    my ($ip) = @_;
    my @aaa = split(/\./, $ip);
    my $bin = '';
    for (my $i = 0; $i < 4; $i++) {
        $bin .= unpack("B8",  pack("C", $aaa[$i]));
    }
    return $bin;
}


sub bin2dec4IP {
    my ($ip) = @_;
    $ip =~ /(........)(........)(........)(........)/;
    my $num1 = unpack("C",  pack("B8",$1));    
    my $num2 = unpack("C",  pack("B8",$2));    
    my $num3 = unpack("C",  pack("B8",$3));    
    my $num4 = unpack("C",  pack("B8",$4)); 
    return "$num1.$num2.$num3.$num4";
}   
   
  • dec2bin4IPは、IPアドレスのドットアドレスをビット列の文字列へ変換します。
  • bin2dec4IPは、IPアドレスのビット列の文字列をドットアドレスへ変換します。

上記は、サブネットマスクIPアドレスをビット列の文字列へ変換して、その論理積をとって、ネットワークアドレスを取得し、ビット列の文字列からドットアドレスへ変換しています。
そして、その変換値、つまり、ネットワークアドレス 172.11.22.0 を表示しています。


尚、packは、引数をバイナリ値に変換し、unpackは、バイナリ値から元の値に変換します。

  • pack("C", 文字列)は、文字列をバイナリ値に変換
  • unpack("B8", バイナリ値)は、バイナリ値をビット8文字の文字列に変換
  • pack("B8", ビット8文字の文字列)は、ビット8文字の文字列をバイナリ値に変換
  • unpack("C", バイナリ値)は、バイナリ値を文字列に変換

追記

kitsさんから、もっとスマートな方法を教えて頂きました(ブックマークで…)。

my $ip = '255.255.255.0';
my $bin = sprintf "%08b"x4, split /\./, $ip;
print $bin, "\n";
print join '.', map {oct "0b$_"} $bin=~/(\d{8})(\d{8})(\d{8})(\d{8})/;

『$bin=~/(\d{8})(\d{8})(\d{8})(\d{8})/』は、カッコを使った記憶がリストで返る(知らなかったです。得した気分です)。
それを"0b$_"で文字連結して、octで10進数にしてjoinする。


できれば、本ブログの応援クリック も、よろしくお願い致します。