C#初心者:DNSルックアップを行うためにこのコードを修正するにはどうすればよいですか?
-
10-07-2019 - |
質問
C#を使用するのは今回が初めてなので、自分の要素からはかなり離れています。しかし、Stack Overflowの素晴らしい人々が私を助けてくれると信じています!私は、インターネット上で浮かんでいる他のいくつかのコードに基づいて、次のコード(以下)を思いつきました。私がやろうとしているのは、すべての「テキスト」を調べることです。特定のドメインのDNSレコード(TXT)。 Visual C#2008 Expressのコンソールアプリケーションでgoogle.comのレコードを検索することから始めました。後でコマンドラインパラメーターに基づいてドメインをカスタマイズすることについて心配します。今のところ、これを機能させたいだけです。 DNSルックアップツールを使用すると、google.comのDNSに次のDNSテキストレコードがあることがわかります。
v = spf1 include:_netblocks.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31〜all
しかし、残念ながらそれは私が得ているものではありません。これが私のコードです:
namespace DnsUtils
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
public class DnsTxt
{
[DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)]ref string pszName, QueryTypes wType, QueryOptions options, int aipServers, ref IntPtr ppQueryResults, int pReserved);
[DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)]
private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType);
public static string[] GetTXTRecords(string domain)
{
IntPtr ptr1 = IntPtr.Zero;
IntPtr ptr2 = IntPtr.Zero;
TXTRecord recTxt;
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
throw new NotSupportedException();
}
ArrayList list1 = new ArrayList();
UnicodeEncoding encoding = new UnicodeEncoding();
int num1 = DnsTxt.DnsQuery(ref domain, QueryTypes.DNS_TYPE_TEXT, QueryOptions.DNS_QUERY_BYPASS_CACHE, 0, ref ptr1, 0);
if (num1 != 0)
{
throw new Win32Exception(num1);
}
for (ptr2 = ptr1; !ptr2.Equals(IntPtr.Zero); ptr2 = recTxt.pNext)
{
recTxt = (TXTRecord)Marshal.PtrToStructure(ptr2, typeof(TXTRecord));
if (recTxt.wType == 16)
{
IntPtr pointerToAddressStringArray = Marshal.AllocHGlobal(IntPtr.Size);
IntPtr addressStringArray = Marshal.ReadIntPtr(pointerToAddressStringArray);
for (int i = 0; i < recTxt.dwStringCount; i++)
{
IntPtr addressCharArray = Marshal.ReadIntPtr(recTxt.pStringArray, i * 4);
int offset = 0;
ArrayList bytesList = new ArrayList();
byte newByte = Marshal.ReadByte(addressCharArray, offset++);
while (newByte != 0)
{
bytesList.Add(newByte);
newByte = Marshal.ReadByte(addressCharArray, offset++);
}
byte[] bytesArray = new byte[offset];
bytesList.CopyTo(bytesArray);
string textValue = encoding.GetString(bytesArray);
list1.Add(textValue);
}
Marshal.FreeHGlobal(pointerToAddressStringArray);
}
}
DnsTxt.DnsRecordListFree(ptr2, 0);
return (string[])list1.ToArray(typeof(string));
}
private enum QueryOptions
{
DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1,
DNS_QUERY_BYPASS_CACHE = 8,
DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000,
DNS_QUERY_NO_HOSTS_FILE = 0x40,
DNS_QUERY_NO_LOCAL_NAME = 0x20,
DNS_QUERY_NO_NETBT = 0x80,
DNS_QUERY_NO_RECURSION = 4,
DNS_QUERY_NO_WIRE_QUERY = 0x10,
DNS_QUERY_RESERVED = -16777216,
DNS_QUERY_RETURN_MESSAGE = 0x200,
DNS_QUERY_STANDARD = 0,
DNS_QUERY_TREAT_AS_FQDN = 0x1000,
DNS_QUERY_USE_TCP_ONLY = 2,
DNS_QUERY_WIRE_ONLY = 0x100
}
private enum QueryTypes
{
DNS_TYPE_TEXT = 16
}
[StructLayout(LayoutKind.Sequential)]
private struct TXTRecord
{
public IntPtr pNext;
public string pName;
public short wType;
public short wDataLength;
public int flags;
public int dwTtl;
public int dwReserved;
public int dwStringCount;
public IntPtr pStringArray;
}
static void Main(string[] args)
{
try
{
string[] s = DnsUtils.DnsTxt.GetTXTRecords("google.com");
foreach (string st in s)
{
Console.WriteLine("Value: {0}", st);
}
}
catch (Win32Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
}
}
このコードを実行すると、 Value:?
が出力されます。今、私はこれが実際にDNSクエリを実行し、期待どおりの結果を得たことを望んでいますが、IntPtrを文字列の配列に変換しようとする部分で何かを台無しにしました(私はそれが難しいと推測しているため)前者をデバッグするには)。とにかく、何か提案がありますか?私がどこに行ったのか誰にもわかりませんか?事前に感謝します。
解決
この行は、私には少し見えます:
IntPtr addressCharArray = Marshal.ReadIntPtr(recTxt.pStringArray, i * 4);
TXTレコードの最初の文字列エントリの最初の4バイトをIntPtrとして読み取るように見えます。次のようなものだと思います:
string s = Marshal.PtrToStringAuto(recTxt.pStringArray);
最初のエントリが取得されます。その後、次のように思います:
IntPtr p = new IntPtr(recTxt.pStringArray.ToInt32() + sizeof(uint) * i);
string s = Marshal.PtrToStringAuto(p);
残りを取得します。
他のヒント
より簡単な代替手段として、新しいnslookupプロセスを作成し、StandardOuputを解析して必要なものを取得することにより、すべてのCOM相互運用を回避できます。
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var startInfo = new ProcessStartInfo("nslookup");
startInfo.Arguments = "-type=TXT google.com";
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
using (var cmd = Process.Start(startInfo))
{
// This is where you grab the output from nslookup.
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
}
Console.Read();
}
}
}