Pregunta

Esta es la primera vez que uso C #, así que estoy muy fuera de mi elemento. ¡Pero tengo fe en que las personas maravillosas aquí en Stack Overflow pueden ayudarme! Se me ocurrió el siguiente código (a continuación) basado en algunas otras piezas de código que encontré flotando en Internet. Lo que estoy tratando de hacer es buscar todo el "texto". Registros DNS (TXT) de un dominio dado. Comencé de manera simple, con una aplicación de consola en Visual C # 2008 Express buscando los registros de google.com. Me preocuparé de personalizar el dominio en función de los parámetros de la línea de comandos más adelante; por ahora solo me gustaría que esto funcione. Cualquier herramienta de búsqueda de DNS puede decirle que google.com tiene este registro de texto DNS en su DNS:
v = spf1 incluye: _netblocks.google.com ip4: 216.73.93.70/31 ip4: 216.73.93.72/31 ~ todos
Pero desafortunadamente eso no es lo que estoy obteniendo. Aquí está mi código:

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

Cuando ejecuto este código, imprime Valor:? . Ahora espero que esto signifique que en realidad hizo la consulta DNS y obtuvo los resultados como se esperaba, pero simplemente arruiné algo en la parte donde intenta convertir un IntPtr en una matriz de cadenas (porque supongo que es más difícil) para depurar el primero). De todos modos, ¿tienes alguna sugerencia? ¿Alguien puede ver dónde fui mal? Gracias de antemano.

¿Fue útil?

Solución

Esta línea me parece un poco extraña:

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

Parece que estaría leyendo los primeros 4 bytes de la primera entrada de cadena del registro TXT como IntPtr. Creo que algo como:

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

te daría la primera entrada. Después de eso, pienso algo como:

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

obtendría el resto.

Otros consejos

Como alternativa más simple, puede evitar tratar con toda la interoperabilidad COM creando un nuevo proceso nslookup y analizando StandardOuput para obtener lo que necesita.

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();
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top