ネットワークアドレスの秘密

こんにちは、幅広い視野を持つエンジニアを目指しています田中と申します。

今日はネットワークアドレスの扱い方を見ていきます。

目的

特定のIPアドレスが、特定のネットワークの範囲内にあるかどうか調べたい。また、サブネットマスクやブロードキャストアドレスなどの算出や検証も併せて行いたい、何か良い方法はないか調べる

やってみた事

IPアドレスを整数(32bit unsigned int)0 ~ 4,294,967,295)に変換して値の範囲を調べる

きっかけ

疎通確認などでよく使うpingコマンドですが、

ping [IPアドレス]

のように使いますが、私はある日誤って以下のように入力してしまいました。

ping [正の整数]

結果は以下のようになります。

10進数ドット区切りのIPアドレス以外をパラメータとして与えてもエラーにはなりませんでした。上記はWindowsのpingコマンドの結果ですが、Linuxなどのpingコマンドでも同様の結果となります。

以上のことから、pingコマンドは32bitのIPアドレスを10進数として解釈して処理しているのではないかと考え、自分のプログラムやスクリプトにも応用できるのではないかと考えました。

IPアドレスを10進数32bit unsigned intに変換してpingに与えてみた

それでは、Google Public DNSの"8.8.8.8"を10進数の32ビットの符号なし整数に変えてpingにパラメータとして与えてみます。

10進数のint型0を32bitで表すと以下のようになります。

10進数のint型8を2進数で表すと1000なので"8.8.8.8"は以下であると考えました。

これを10進数に直します。

2^27 + 2^19 + 2^11 + 2^3
= 134217728 + 524288 + 2048 + 8
= 134744072

これをpingのパラメータに与えてみます。

予想通りの結果となりました。

IPアドレスを10進数32bit unsigned intに変換して処理してみた

pingコマンドを真似てIPアドレスを32bit unsigned intとして扱い、TCP/IPネットワークの情報を算出してみます。

IPアドレスを32bit値に変換

IPアドレスの各オクテット(8bit)をint型の数字と見なし、4つ並べます。

これを第一オクテットから順に、24ビット左シフト、第二オクテットを16ビット左シフト、第三オクテットを8ビット左シフトしてORをとります。

IPアドレスが正しいかどうか

10進数に変換したIPアドレスの範囲が0~4294967295の範囲に含まれるかどうか

CIDR(プレフィックス長)を32bitIPアドレスにする

2^((32 - プレフィックス長) - 1)を2進数にしたものと、0xFFFFFFFFでXORをとる

例: 24

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

2進数に変換したIPアドレスとプレフィックス長付きアドレス(CIDR)を2進数にしたもののANDをとる(ホスト部のビットをすべて0にする)

例: 192.168.0.1 , サブネットマスク255.255.255.0(192.168.0.1/24)

ブロードキャストアドレスを求める

プレフィックス長付きアドレス(CIDR)をネットワークアドレスを論理否定(NOT)したものとXORをとる(ホスト部のビットをすべて1にする)

例: 192.168.0.1, サブネットマスク255.255.255.0(192.168.0.1/24)

bashなどNOT演算ができない場合は以下で代用する(プレフィックス長付きアドレス(CIDR)と0xFFFFFFFFでXORをとったものとIPアドレスでORをとる)

連続したIPアドレスを求める

IPアドレスを32bit unsigned intにしてインクリメントするだけ、オクテット境界は考える必要なし

あるIP アドレスが特定のネットワークの範囲にあるか調べる

IPアドレスがネットワークアドレスとブロードキャストアドレスの間にあるか調べればよい

例: 192.168.0.200がデフォルトサブネットマスク255.255.255.0で192.168.0.1の範囲に所属するか

192.168.0.255 => 3232235775
192.168.0.1       => 3232235521
192.168.0.200 => 3232235720

3232235521 < 3232235720 < 3232235775 よって所属する

実際のコード例

実行例

IPアドレスを10進数32bit unsigned intとしてIPアドレスの範囲を調べることができました!

pingのソースコードを読んでみた

Linuxのpingのソースコードが見つからなかったのでFreeBSDのソースコードを読んでみます。

https://svnweb.freebsd.org/base/head/sbin/ping/ping.c

inet_ntoa()とinet_aton()が32bit数値とASCII文字列(10進数ドット区切りIPアドレス)の変換をしていそうです。

オンラインマニュアルのinet(3)にありました。

マニュアルによると16進数でも解釈できるとのことなのでやってみます。

16進数でもできました!

参考にさせていただいたサイト様(TCP/IP情報取得シェルスクリプトをそのまま使わせて頂いています)

http://qiita.com/harasou/items/5c14c335388f70e178f5

記事は以上になります。

このたびはご覧戴き、ありがとうございました。

 

投稿者プロフィール

スカイブロガー