あなたはin-addr.arpaドメインを照会することによって、かなり失敗したルックアップの速度を向上させることができます。たとえば、IPアドレスA.B.C.Dの逆IPルックアップを実行するには、DNSにドメインD.C.B.A.in-addr.arpaを照会する必要があります。逆引きが可能な場合は、ホスト名のPTRレコードが返されます。
残念ながら、.NETにはDNSを照会するための一般的なAPIはありません。しかし、P/Invokeを使用すると、DNS APIを呼び出して目的の結果を得ることができます(逆引きが失敗した場合、関数はnull
を返します)。
using System;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
public static String ReverseIPLookup(IPAddress ipAddress) {
if (ipAddress.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("IP address is not IPv4.", "ipAddress");
var domain = String.Join(
".", ipAddress.GetAddressBytes().Reverse().Select(b => b.ToString())
) + ".in-addr.arpa";
return DnsGetPtrRecord(domain);
}
static String DnsGetPtrRecord(String domain) {
const Int16 DNS_TYPE_PTR = 0x000C;
const Int32 DNS_QUERY_STANDARD = 0x00000000;
const Int32 DNS_ERROR_RCODE_NAME_ERROR = 9003;
IntPtr queryResultSet = IntPtr.Zero;
try {
var dnsStatus = DnsQuery(
domain,
DNS_TYPE_PTR,
DNS_QUERY_STANDARD,
IntPtr.Zero,
ref queryResultSet,
IntPtr.Zero
);
if (dnsStatus == DNS_ERROR_RCODE_NAME_ERROR)
return null;
if (dnsStatus != 0)
throw new Win32Exception(dnsStatus);
DnsRecordPtr dnsRecordPtr;
for (var pointer = queryResultSet; pointer != IntPtr.Zero; pointer = dnsRecordPtr.pNext) {
dnsRecordPtr = (DnsRecordPtr) Marshal.PtrToStructure(pointer, typeof(DnsRecordPtr));
if (dnsRecordPtr.wType == DNS_TYPE_PTR)
return Marshal.PtrToStringUni(dnsRecordPtr.pNameHost);
}
return null;
}
finally {
const Int32 DnsFreeRecordList = 1;
if (queryResultSet != IntPtr.Zero)
DnsRecordListFree(queryResultSet, DnsFreeRecordList);
}
}
[DllImport("Dnsapi.dll", EntryPoint = "DnsQuery_W", ExactSpelling=true, CharSet = CharSet.Unicode, SetLastError = true)]
static extern Int32 DnsQuery(String lpstrName, Int16 wType, Int32 options, IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved);
[DllImport("Dnsapi.dll", SetLastError = true)]
static extern void DnsRecordListFree(IntPtr pRecordList, Int32 freeType);
[StructLayout(LayoutKind.Sequential)]
struct DnsRecordPtr {
public IntPtr pNext;
public String pName;
public Int16 wType;
public Int16 wDataLength;
public Int32 flags;
public Int32 dwTtl;
public Int32 dwReserved;
public IntPtr pNameHost;
}
私は実際にそのバージョンを使い始めました。時間切れの問題を効果的に回避します。私の問題は、タイムアウトがなければならないということです。 nslookupを実行するか、いくつかのランダムなIPでコマンドラインを掘ります。通常、1秒以内に "*** server.pf.localが見つからない42.23.1.42:存在しないドメイン"(またはNXDOMAIN、 digの場合) - 私はなぜGetHostEntry()が同じように動作しないのだろうかと思います。 – gregmac
私はあなたがP/Invokeを使って、getnameinfoのデフォルトとは異なるフラグを使って、あなたが望むものを達成できると信じています。私の編集を参照してください。 –