简体   繁体   中英

How do I read TXT records of a domain in C#?

I'm building a program and want to store the latest version number in a TXT record on a domain I own. After obtaining the text record I intend to compare it to the current version number.

I can do the string comparison part, but I am completely lost as to how you're supposed to read DNS records.

How do I do this in C#?

This repo: MichaCo/DnsClient.NET has the capability of reading TXT records in a DNS endpoint.

You can use a helper class to retrieve them by making a dns lookup. I've written a lil script that can help you achieve this:

using Util;
using System;

namespace DnsClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var Domain = "www.contoso.com";
            var RequiredRecord = "MS=ms47806392";
            var RequiredValue = "ms47806392";
            var RequiredKey = "MS";
            // Check without trying to split the TXT Record
            if (CheckDnsRecordExists(Domain, RequiredRecord))
                Console.WriteLine($"Found TXT Record: {RequiredRecord}! :)");
            else
                Console.WriteLine("Not Found! :(");

            // Check by trying to split the TXT Record and checking for it's value
            if (CheckDnsRecordExists(Domain, RequiredKey, RequiredValue))
                Console.WriteLine($"Found Version {RequiredValue} of RecordID: {RequiredValue}! :)");
            else
                Console.WriteLine("Not Found! :(");

            Console.ReadKey();
        }
        private static bool CheckDnsRecordExists(string Domain, string RequiredRecord)
        {
            var Records = DnsInterop.GetTxtRecords(Domain);
            foreach (var record in Records)
            {
                if (record == RequiredRecord)
                {
                    return true;
                }
            }
            return false;
        }

        private static bool CheckDnsRecordExists(string Domain, string RequiredKey, string RequiredValue, char Separator = '=')
        {
            var Records = DnsInterop.GetTxtRecords(Domain);
            foreach (var record in Records)
            {
                var keyPair = record.Split(Separator);
                if (keyPair[0] != null && keyPair[1] != null)
                {
                    if (keyPair[0] == RequiredKey && keyPair[1] == RequiredValue)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}

This example class by @gordonmleigh, based on this answer https://stackoverflow.com/a/11884174 by Martin Liversage can help you retrieve TXT records given a specific domain.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace Util
{
    /// <summary>
    /// Based on https://stackoverflow.com/a/11884174 (Martin Liversage)
    /// </summary>
    class DnsInterop
    {
        private const short DNS_TYPE_TEXT = 0x0010;
        private const int DNS_QUERY_STANDARD = 0x00000000;
        private const int DNS_ERROR_RCODE_NAME_ERROR = 9003;
        private const int DNS_INFO_NO_RECORDS = 9501;


        public static IEnumerable<string> GetTxtRecords(string domain)
        {
            var results = new List<string>();
            var queryResultsSet = IntPtr.Zero;
            DnsRecordTxt dnsRecord;

            try
            {
                // get all text records
                // pointer to results is returned in queryResultsSet
                var dnsStatus = DnsQuery(
                  domain,
                  DNS_TYPE_TEXT,
                  DNS_QUERY_STANDARD,
                  IntPtr.Zero,
                  ref queryResultsSet,
                  IntPtr.Zero
                );

                // return null if no records or DNS lookup failed
                if (dnsStatus == DNS_ERROR_RCODE_NAME_ERROR
                    || dnsStatus == DNS_INFO_NO_RECORDS)
                {
                    return null;
                }

                // throw an exception if other non success code
                if (dnsStatus != 0)
                    throw new Win32Exception(dnsStatus);

                // step through each result
                for (
                    var pointer = queryResultsSet; 
                    pointer != IntPtr.Zero; 
                    pointer = dnsRecord.pNext)
                {
                    dnsRecord = (DnsRecordTxt)
                        Marshal.PtrToStructure(pointer, typeof(DnsRecordTxt));

                    if (dnsRecord.wType == DNS_TYPE_TEXT)
                    {
                        var builder = new StringBuilder();

                        // pointer to array of pointers
                        // to each string that makes up the record
                        var stringArrayPointer = pointer + Marshal.OffsetOf(
                            typeof(DnsRecordTxt), "pStringArray").ToInt32();

                        // concatenate multiple strings in the case of long records
                        for (var i = 0; i < dnsRecord.dwStringCount; ++i)
                        {
                            var stringPointer = (IntPtr)Marshal.PtrToStructure(
                                stringArrayPointer, typeof(IntPtr));

                            builder.Append(Marshal.PtrToStringUni(stringPointer));
                            stringArrayPointer += IntPtr.Size;
                        }

                        results.Add(builder.ToString());
                    }
                }
            }
            finally
            {
                if (queryResultsSet != IntPtr.Zero)
                {
                    DnsRecordListFree(queryResultsSet, 
                        (int)DNS_FREE_TYPE.DnsFreeRecordList);
                }
            }

            return results;
        }


        [DllImport("Dnsapi.dll", EntryPoint = "DnsQuery_W", 
            ExactSpelling = true, CharSet = CharSet.Unicode, 
            SetLastError = true)]
        static extern int DnsQuery(string lpstrName, short wType, int options, 
            IntPtr pExtra, ref IntPtr ppQueryResultsSet, IntPtr pReserved);


        [DllImport("Dnsapi.dll")]
        static extern void DnsRecordListFree(IntPtr pRecordList, int freeType);


        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct DnsRecordTxt
        {
            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 string pStringArray;
        }


        enum DNS_FREE_TYPE
        {
            DnsFreeFlat = 0,
            DnsFreeRecordList = 1,
            DnsFreeParsedMessageFields = 2
        }
    }
}

Hope it helps!

Based on DnsDig project I created a DLL which can be used on any .net (vb, c#, forms, web. etc..) project

https://devselz.com/software/devselz_dnsdig_dns-txt-etc-query-domain-register.zip

Download the DLL, unzip, and Add as reference to your project (if website place on root/bin folder):

DnsDig.dll

nunit.framework.dll

(126KB in total)

Then use this example as for an ASP.Net website (vb.net code)

Imports DnsDig
Imports Heijden.DNS
Partial Class lib_u_l_Default
    Inherits System.Web.UI.Page
    Public Resolver As Resolver
    Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
        Resolver = New Resolver
        Dim SW As New System.Diagnostics.Stopwatch
        SW.Start()
        Dim DNSResponse As Heijden.DNS.Response = Resolver.Query(Request.QueryString("d"), QType.TXT, QClass.ANY)
        SW.Stop()
        If DNSResponse.header.ANCOUNT > 0 Then
            For Each answerRR As AnswerRR In DNSResponse.Answers
                Response.Write("<br/>" & answerRR.ToString)
            Next
        End If
    End Sub

End Class

RESULTS: https://yourwebsiteusingabovedlls.com/anyplacewhereabovecode/?d=goodyes.com

will write

goodyes.com. 3535 IN TXT "google-site-verification=IMw-tL0VWgMJbtcRgt_bu5UaVwpbNb94dvcOSObooa4" goodyes.com. 3535 IN TXT "v=spf1 include:_spf.buzondecorreo.com ~all"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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