12

ドメインの SPF レコードを確認する方法は何ですか?

http://www.mxtoolbox.com/SuperTool.aspxを使用して手動で実行できる Web サイトがあります。

ASP.NET と C# 経由で行うにはどうすればよいですか? 基本的に、独自のメール Web サーバーをサポートしている場合、ドメインの SPF レコードを確認/確認したいと考えています。

4

8 に答える 8

15

私は同じ問題を抱えており、2つの3つの解決策を見つけることができまし

解決nslookup

コマンドラインで次のコマンドを入力すると、SPFを取得できます。

nslookup -type=TXT <hostname>

このブログ投稿System.Diagonstics.Processで説明されているように、を使用してC#でこれを自動化できます。

DNS.NETリゾルバープロジェクト

DNS解決に関するこのCodeProjectの記事を見つけました。デモプロジェクトが付属しています。プロジェクトを実行したところ、次の結果が得られましたstackexchange.com

DNS Digscreeenshot

注: [送信]ボタンを押す前に、 [QType]フィールドがTXTに設定されていることを確認して

黄色で強調表示されているセクションは、SPFレコードを表しています。私はまだコードを掘り下げてそれがどのように行われるかを確認していませんが、これはnslookup上記の解決策の良い代替案のようです。

[更新]ARSoft.Tools.Netプロジェクト

ドメインがメールサーバーをサポートしているかどうかを確認するだけの場合は、ARSoft.Tools.Netライブラリ( NuGetパッケージとしても利用可能)を使用できます。

パッケージをインストールした後、私はこのコードでSPFチェックを実行することができました:

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

var mailIpAddress = IPAddress.Parse("X.X.X.X");
var domain = "example.com";
var senderAddress = "sender@example.com";

ARSoft.Tools.Net.Spf.SpfQualifier result = 
    spfValidator.CheckHost(mailIpAddress, domain, senderAddress);
于 2012-08-09T13:03:26.157 に答える
6

.NET は、ホスト名からアドレスへのマッピングなど、ネットワーキングを多数サポートしていますが、DNS を照会する一般的な方法がありません。

ただし、P/Invoke を使用してDnsQuery 関数を直接呼び出すことができます。API はやや面倒ですが、要件に合った正しい P/Invoke 署名を作成することは不可能ではありません。

SPF レコードは、DNS に TXT レコードとして保存されます。作業する必要がある対応する構造は、DNS_TXT_DATA 構造です。MX レコードのクエリの例を見つけることができれば、コードを再利用してクエリ タイプに使用し、データを構造体DNS_TYPE_TEXTにアンマーシャリングできます。DNS_TXT_DATA

または、次のコードを使用することもできます。

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;
}
于 2012-08-09T13:08:21.847 に答える
1

Martin Liversage による回答に基づいて、何が起こっているかを説明するコメントをいくつか追加し、複数のレコードが存在する場合はそれらを返すように調整しました。

この例では、改行で区切るのではなく、複数の文字列を TXT レコードに連結しています。

if (dnsRecord.wType == DNS_TYPE_TEXT)制約が関数の引数にあることを考えると、その行が本当に必要かどうかはわかりませんが、DnsQueryとにかくマーティンの答えからそれを保存しました。

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
        }
    }
}
于 2016-07-04T09:23:43.643 に答える
0

基本的に、ドメインの MX/SPF レコードを要求する DNS 要求を行う必要があります。C# でこれを行う例がいくつかあります。http://mailsystem.codeplex.com/にライブラリがあり、これを行うための便利なValidatorクラスGetMxRecordsがあります。

于 2012-08-07T17:01:24.980 に答える
0

価値があるのは、MailBee の .NET オブジェクトもこれをサポートしていることです。これは、このコンポーネントを既に所有していて、何か他のものを実装しようとしていたときに、このグッズがすでに私たちが持っていたものに組み込まれていることを発見したためです。

http://www.afterlogic.com/mailbee-net/docs/filter_spam_with_dns.html

于 2014-02-25T01:25:20.850 に答える
-1

すべてのウェブサイトがこれを間違っているのはおかしい

SPF は TXT ではありません

SPF なしの txt レコードと TXT なしの SPF を持つことができるため、TXT ルックアップは SPF を表示しません。

于 2014-07-09T10:55:59.293 に答える