Domanda

Questa è la prima volta che utilizzo C #, quindi sono decisamente fuori dal mio elemento. Ma credo che le persone meravigliose qui a Stack Overflow possano aiutarmi! Ho escogitato il seguente codice (sotto) basato su alcuni altri pezzi di codice che ho trovato fluttuante su Internet. Quello che sto cercando di fare è cercare tutto il "testo" Record DNS (TXT) di un determinato dominio. Ho iniziato in modo semplice, con un'applicazione console in Visual C # 2008 Express che cercava i record per google.com. Mi preoccuperò di personalizzare il dominio in base ai parametri della riga di comando in seguito; per ora mi piacerebbe solo farlo funzionare. Qualsiasi strumento di ricerca DNS può dirti che google.com ha questo record di testo DNS nel proprio DNS:
v = spf1 include: _netblocks.google.com ip4: 216.73.93.70/31 ip4: 216.73.93.72/31 ~ tutto
Ma sfortunatamente non è quello che sto ottenendo. Ecco il mio codice:

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

Quando eseguo questo codice, stampa Valore:? . Ora spero che questo significhi che ha effettivamente eseguito la query DNS e ottenuto i risultati come previsto, ma ho appena rovinato qualcosa nella parte in cui tenta di convertire un IntPtr in un array di stringhe (perché immagino sia più difficile per eseguire il debug del primo). Comunque, hai qualche suggerimento? Qualcuno può vedere dove sono andato storto? Grazie in anticipo.

È stato utile?

Soluzione

Questa riga mi sembra un po 'diversa:

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

Sembra che dovresti leggere i primi 4 byte della prima voce di stringa del record TXT come IntPtr. Penso a qualcosa del tipo:

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

ti darebbe la prima voce. Dopodiché, penso a qualcosa del tipo:

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

otterrebbe i resti.

Altri suggerimenti

Come alternativa più semplice potresti evitare di gestire tutte le interoperazioni COM creando un nuovo processo nslookup e analizzando StandardOuput per afferrare ciò di cui hai bisogno.

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();
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top