トップ > Tech > CSharp > System.Net.Dnsクラスを使った名前解決の問題

System.Net.Dnsクラスを使った名前解決の問題

はじめに

.NET 2.0 以降でホスト名の名前解決を行うには System.Net.Dns クラスにある GetHostEntry メソッドを用いる。

パラメータにホスト名を渡すと DNS サーバーにクエリが送られ、AddressList プロパティに IP アドレスのリストが格納される(ホスト名と IP アドレスは 1 対 1 とは限らない)。通常は最初のアドレスを使えばよいので、下記のようにすれば、ホスト名から IP アドレスを得られる。

string host = "hogehoge";
IPAddress address = Dns.GetHostEntry(host).AddressList[0];

IP アドレスを渡した場合は?

ところでこの GetHostEntry の第 1 パラメータは hostNameOrAddress という名前になっている。 つまりホスト名でも IP アドレスでも渡して OK という仕様になっているのだ。 では、この第 1 パラメータに IP アドレスを渡したらどうなるだろうか。普通はそのままの IP アドレスを返してほしいところだ。 つまり、下記のようなコードを書けば、address には "192.168.1.3" が返ってほしいわけである。

string host = "192.168.1.3";
IPAddress address = Dns.GetHostEntry(host).AddressList[0];

実際、このメソッドはこういう仕様になっていて、上のコードでは address に "192.168.1.3" が返るようになっている。

問題点

ただし、一つクセがある。これがうまくいくのは同セグメントかつ、DNS サーバーが適切に設定されている場合のみである。

つまり、実行したパソコンの IP アドレスが 192.168.1.1/24 だとして、GetHostEntry に渡すアドレスが 192.168.1.3/24 の場合はうまくいくのだが、192.168.2.3/24 の場合にはうまくいかない。SocketException として "そのようなホストは存在しません。" と言われる。

おそらく別セグメントの場合は DNS サーバーに問い合わせに行くのだが、 DNS サーバーが名前解決をできずに例外となるのだろう。なお、この問題は 192.168.2.3 が DNS サーバーに登録されている場合は発生しない。

また、この症状が見られるのは Vista 以降のみで、XP の場合は発生しなかった。IPv6 が追加された影響だと思うが、詳しくは詰め切れていない。

ともかくも最初に示したコードでは、別セグメントの IP アドレスが渡されたときに通信ができない事態があり得る。

解決策

これは IP アドレスかどうかを事前に判断してやることで回避できる。

IPAddress address;
if (!IPAddress.TryParse(host, out address))
{
    address = Dns.GetHostEntry(host).AddressList[0];
}

IPAddress.TryParse は渡した文字列を IPAddress クラスのインスタンスに変換するメソッドである(名前解決はしない)。このメソッドは int.TryParse などと同じように変換の可否を bool で返すので、失敗した場合(ホスト名の場合)は、Dns.GetHostEntry メソッドによって、名前解決してやればよい。

これで address には無事、希望の IP アドレスが得られるはずである。もっともこれぐらいの処理をしてくれるメソッドが用意されていてもいいと思うのだが…。

(2010/03/25 17:26:25)
14613
プロフィール

Kenz Yamada(山田研二)。1984年生。大阪。ちょっとずつ好きなプログラム作ってます。 好きなものはカメラと旅行。ガジェットや身の回り、ちょっとこだわります。 詳しくは Web mixi で。

Bookmark and Share