Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get SPF records from a Domain

Tags:

c#

asp.net

spf

What are the ways to Check SPF records on a domain?

There is a website where i can do it manually using - http://www.mxtoolbox.com/SuperTool.aspx

How can i do it via ASP.NET and C#? Basically i want to verify/check SPF records on a domain if its supporting out own mail web server.

like image 586
nimi Avatar asked Aug 07 '12 13:08

nimi


People also ask

What is SPF DNS lookup?

What is the SPF lookup for? With the SPF lookup you analyze the SPF record of a domain for errors, security risks and authorized IP addresses. Optionally, you can specify an IP address to check if it is authorized to send e-mail on behalf of the domain. The SPF lookup analyzes registered TXT records in real time.

Should all domains have an SPF record?

All domains, regardless if they send email, should include a Sender Policy Framework (SPF) record. SPF is a widely adopted mechanism that identifies legitimate sending IP addresses and is taken into account by mailbox providers when treating received email.


2 Answers

I have the same problem, and managed to find two three solutions:

The nslookup solution

You can get the SPF by typing the following command in the command line:

nslookup -type=TXT <hostname>

You can automate this in C# using System.Diagonstics.Process, as described in this blog post.

The DNS.NET Resolver project

I found this CodeProject article about DNS resolution. It comes with demo project. I ran the project and got the following result for stackexchange.com:

DNS Dig screeenshot

Note: Make sure that the QType field is set to TXT before you press the Send button

The section highlighted in yellow represents the SPF record. I haven't yet dug into the code to see how it's done, but this seems like a good alternative to the nslookup solution above.

[Update] The ARSoft.Tools.Net project

If all you need to do is check whether a domain supports a mail server, you can use the ARSoft.Tools.Net library (also available as a NuGet Package).

After installing the package, I managed to perform the SPF check with this code:

var spfValidator = new ARSoft.Tools.Net.Spf.SpfValidator();

var mailIpAddress = IPAddress.Parse("X.X.X.X");
var domain = "example.com";
var senderAddress = "[email protected]";

ARSoft.Tools.Net.Spf.SpfQualifier result = 
    spfValidator.CheckHost(mailIpAddress, domain, senderAddress);
like image 55
Cristian Lupascu Avatar answered Sep 22 '22 10:09

Cristian Lupascu


Even though .NET has a lot of support for networking including doing host name to address mapping it lacks a general way to query DNS.

However, you can use P/Invoke to call the DnsQuery function directly. The API is somewhat cumbersome but it is not impossible to create the correct P/Invoke signature for your requirement.

A SPF record is stored as a TXT record in DNS. The corresponding structure you will have to work with is the DNS_TXT_DATA structure. If you can find an example of querying a MX record you can reuse the code and use DNS_TYPE_TEXT for the query type and unmarshal the data to a DNS_TXT_DATA structure.

Or you could just use this code:

using System.ComponentModel;
using System.Runtime.InteropServices;

public String DnsGetTxtRecord(String name) {
  const Int16 DNS_TYPE_TEXT = 0x0010;
  const Int32 DNS_QUERY_STANDARD = 0x00000000;
  const Int32 DNS_ERROR_RCODE_NAME_ERROR = 9003;
  const Int32 DNS_INFO_NO_RECORDS = 9501;
  var queryResultsSet = IntPtr.Zero;
  try {
    var dnsStatus = DnsQuery(
      name,
      DNS_TYPE_TEXT,
      DNS_QUERY_STANDARD,
      IntPtr.Zero,
      ref queryResultsSet,
      IntPtr.Zero
    );
    if (dnsStatus == DNS_ERROR_RCODE_NAME_ERROR || dnsStatus == DNS_INFO_NO_RECORDS)
      return null;
    if (dnsStatus != 0)
      throw new Win32Exception(dnsStatus);
    DnsRecordTxt dnsRecord;
    for (var pointer = queryResultsSet; pointer != IntPtr.Zero; pointer = dnsRecord.pNext) {
      dnsRecord = (DnsRecordTxt) Marshal.PtrToStructure(pointer, typeof(DnsRecordTxt));
      if (dnsRecord.wType == DNS_TYPE_TEXT) {
        var lines = new List<String>();
        var stringArrayPointer = pointer
          + Marshal.OffsetOf(typeof(DnsRecordTxt), "pStringArray").ToInt32();
        for (var i = 0; i < dnsRecord.dwStringCount; ++i) {
          var stringPointer = (IntPtr) Marshal.PtrToStructure(stringArrayPointer, typeof(IntPtr));
          lines.Add(Marshal.PtrToStringUni(stringPointer));
          stringArrayPointer += IntPtr.Size;
        }
        return String.Join(Environment.NewLine, lines);
      }
    }
    return null;
  }
  finally {
    const Int32 DnsFreeRecordList = 1;
    if (queryResultsSet != IntPtr.Zero)
      DnsRecordListFree(queryResultsSet, DnsFreeRecordList);
  }
}

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

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

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct DnsRecordTxt {
  public IntPtr pNext;
  public String pName;
  public Int16 wType;
  public Int16 wDataLength;
  public Int32 flags;
  public Int32 dwTtl;
  public Int32 dwReserved;
  public Int32 dwStringCount;
  public String pStringArray;
}
like image 21
Martin Liversage Avatar answered Sep 24 '22 10:09

Martin Liversage