简体   繁体   English

C#新手:如何修复此代码以进行DNS查找?

[英]C# Newbie: How do I fix this code to do a DNS lookup?

This is my first time using C#, so I'm very much out of my element. 这是我第一次使用C#,所以我非常偏离我的元素。 But I have faith that the wonderful people here at Stack Overflow can help me out! 但我相信Stack Overflow的优秀人才可以帮助我! I've come up with the following code (below) based on some other pieces of code I found floating around on the internet. 我基于我在互联网上发现的其他一些代码片段,提出了以下代码(下面)。 What I am trying to do is to look up all the "text" DNS records (TXT) of a given domain. 我想要做的是查找给定域的所有“文本”DNS记录(TXT)。 I've started out simple, with a Console Application in Visual C# 2008 Express looking up the records for google.com. 我开始时很简单,在Visual C#2008 Express中使用控制台应用程序查找google.com的记录。 I'll worry about customizing the domain based on command line parameters later; 我担心以后会根据命令行参数自定义域名; for now I'd just like to get this working. 现在我只想让这个工作。 Any DNS lookup tools can tell you that google.com has this DNS text record in their DNS: 任何DNS查找工具都可以告诉您google.com在其DNS中具有此DNS文本记录:
v=spf1 include:_netblocks.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all
But unfortunately that's not what I'm getting. 但不幸的是,这不是我得到的。 Here's my code: 这是我的代码:

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();
        }
    }
}

When I run this code, it prints Value: ? 当我运行此代码时,它会打印Value: ? . Now I'm hoping that this means it actually did the DNS query and got the results as expected, but I just screwed something up in the part where it tries to convert an IntPtr to an array of strings (because I'm guessing it's harder to debug the former). 现在我希望这意味着它实际上做了DNS查询并得到了预期的结果,但我只是在试图将IntPtr转换为字符串数组的部分搞砸了(因为我猜它更难调试前者)。 Anyways, have any suggestions? 无论如何,有什么建议吗? Can anyone see where I went awry? 谁能看到我出错的地方? Thanks in advance. 提前致谢。

This line looks a bit off to me: 这条线看起来有点偏离我:

IntPtr addressCharArray = Marshal.ReadIntPtr(recTxt.pStringArray, i * 4);

It looks like you'd be reading the first 4 bytes of the first string entry of the TXT record as an IntPtr. 看起来你正在读取TXT记录的第一个字符串条目的前4个字节作为IntPtr。 I think something like: 我想是这样的:

string s = Marshal.PtrToStringAuto(recTxt.pStringArray);

would get you the first entry. 会给你第一个条目。 After that, I think something like: 在那之后,我想像:

IntPtr p = new IntPtr(recTxt.pStringArray.ToInt32() + sizeof(uint) * i);
string s = Marshal.PtrToStringAuto(p);

would get the remainders. 会得到剩余的。

As a simpler alternative you could avoid dealing with all the COM interop by creating a new nslookup process and parsing the StandardOuput to grab what you need. 作为一种更简单的替代方法,您可以通过创建新的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();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM