C # جديد: كيف يمكنني إصلاح هذا الرمز إلى القيام بحث DNS؟

StackOverflow https://stackoverflow.com/questions/1441902

سؤال

وهذه هي المرة الأولى باستخدام C #، لذلك أنا كثيرا من عنصر بلدي. ولكن لدي ثقة بأن شعب رائع هنا في تجاوز المكدس يستطيع مساعدتي! جئت مع التعليمات البرمجية التالية (أدناه) استنادا إلى بعض الأجزاء الأخرى من التعليمات البرمجية وجدت تطوف على شبكة الانترنت. ما أحاول القيام به هو للبحث عن كل "نص" سجلات DNS (TXT) في مجال معين. لقد بدأت بسيطة، مع تطبيق وحدة التحكم في Visual C # 2008 إكسبريس تبحث عن سجلات للنطاق 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);

ويبدو أنك تريد ان تكون قراءة 4 بايت الأولى من إدخال سلسلة الأول من السجل TXT باعتبارها IntPtr. أعتقد أن شيئا مثل:

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

وسوف تحصل على أول دخول. بعد ذلك، وأعتقد أن شيئا مثل:

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

وسيحصل على البقايا.

نصائح أخرى

وكبديل أكثر بساطة يمكن تجنب التعامل مع كل إمكانية التشغيل المتداخل COM عن طريق إنشاء عملية NSLOOKUP جديدة وتحليل StandardOuput للاستيلاء على ما تحتاجه.

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 مع الإسناد
لا تنتمي إلى StackOverflow
scroll top