gethostbyaddr

IP アドレスからホスト名を取得する

構文

解説

gethostbyaddr は、ADDR に指定された IP アドレス、および、 ADDRTYPE に指定されたアドレスタイプ(アドレスファミリー)から、 システムに対してホスト情報を要求します。 スカラーコンテキストなら、gethostbyaddr はホスト名 (FQDN) を返します。 もしホスト名が見つからなければ undef を返します。

ADDR には、IP アドレスを文字列として指定するのではなく、バイナリーデータとして指定しなければいけません。 そして、Linux であれば、ADDR に指定する IP アドレスが IPv4 なら、ADDRTYPE には 2 を指定し、IPv6 なら 10 を指定します。

my $addr      = '8.8.8.8';                             # IPv4 アドレス
my $packed_ip = pack( "C4", split( /\./, $addr ) );    # IP アドレスをバイナリーに変換
my $name      = gethostbyaddr( $packed_ip, 2 );        # ホスト名を取得
if ( defined $name ) {
    print $name, "\n";                                 # dns.google
}

ADDR に指定する値は OS によって異なります。 たとえば Linux なら IPv4 には 2 が、IPv6 には 10 が割り当てられていますが、 Windows の場合は、IPv4 は同じですが、IPv6 には 23 が割り当てられています。 このような環境による違いを吸収するために、 標準モジュール Socket モジュールを使うことをお勧めします。

use Socket;
my $addr      = '8.8.8.8';                               # IPv4 アドレス
my $packed_ip = Socket::inet_pton( AF_INET, $addr );     # IP アドレスをバイナリーに変換
my $name      = gethostbyaddr( $packed_ip, AF_INET );    # ホスト名を取得
if ( defined $name ) {
    print $name, "\n";                                   # dns.google
}

IPv6 アドレスからホスト名を取得したいなら、次のようなコードになります。

use Socket;
my $addr      = '2001:4860:4860::6464';                   # IPv6 アドレス
my $packed_ip = Socket::inet_pton( AF_INET6, $addr );     # IP アドレスをバイナリーに変換
my $name      = gethostbyaddr( $packed_ip, AF_INET6 );    # ホスト名を取得
if ( defined $name ) {
    print $name, "\n";                                    # dns64.dns.google
}

gethostbyaddr はリストコンテキストなら次のようにホスト情報をリストで返します。

#    0      1         2          3        4
my ( $name, $aliases, $addrtype, $length, @addrs ) = gethostbyaddr( $packed_ip, AF_INET );
No. 変数 意味 実例
0 $name ホスト名 dns.google
1 $aliases エイリアス (別名)
2 $addrtype アドレスタイプ(アドレスファミリー)(Linux なら 2: IPv4, 10: IPv6) 2 (IPv4)
3 $length アドレスのバイト長 4
4 @addrs IP アドレスリスト (8.8.8.8) (各 IP アドレスはバイナリーデータ)

@addrs の IP アドレスリストの各 IP アドレスは、バイナリーデータで格納されます。 そのため、Socket モジュールの inet_ntoa 関数を使って文字列に変換すると良いでしょう。

use Socket;
my $addr      = '8.8.8.8';
my $packed_ip = Socket::inet_pton( AF_INET, $addr );
my ( $name, $aliases, $addrtype, $length, @addrs ) =  gethostbyaddr( $packed_ip, AF_INET );

print $name, ' (', join( ', ', map { inet_ntoa($_) } @addrs ), ")\n";

上記サンプルコードは次のような結果を出力します。

dns.google (8.8.8.8)

gethostbyaddr はシステムに対してホスト名を要求しますが、 システムは指定の IP アドレスに対するホスト名を知らなければ、 通常はシステムが参照している DNS に問い合わせ (DNS 逆引き) をします。 そのため、応答に時間がかかる場合があります。 大量の IP アドレスからホスト名を取得する場合や、アクセス数が多いサイトで都度 gethostbyaddr を呼び出す場合には、注意が必要です。