ドメインの SPF レコードを確認する方法は何ですか?
http://www.mxtoolbox.com/SuperTool.aspxを使用して手動で実行できる Web サイトがあります。
ASP.NET と C# 経由で行うにはどうすればよいですか? 基本的に、独自のメール Web サーバーをサポートしている場合、ドメインの SPF レコードを確認/確認したいと考えています。
ドメインの SPF レコードを確認する方法は何ですか?
http://www.mxtoolbox.com/SuperTool.aspxを使用して手動で実行できる Web サイトがあります。
ASP.NET と C# 経由で行うにはどうすればよいですか? 基本的に、独自のメール Web サーバーをサポートしている場合、ドメインの SPF レコードを確認/確認したいと考えています。
私は同じ問題を抱えており、2つの3つの解決策を見つけることができました:
nslookup
策コマンドラインで次のコマンドを入力すると、SPFを取得できます。
nslookup -type=TXT <hostname>
このブログ投稿System.Diagonstics.Process
で説明されているように、を使用してC#でこれを自動化できます。
DNS解決に関するこのCodeProjectの記事を見つけました。デモプロジェクトが付属しています。プロジェクトを実行したところ、次の結果が得られましたstackexchange.com
。
注: [送信]ボタンを押す前に、 [QType]フィールドがTXTに設定されていることを確認して
黄色で強調表示されているセクションは、SPFレコードを表しています。私はまだコードを掘り下げてそれがどのように行われるかを確認していませんが、これはnslookup
上記の解決策の良い代替案のようです。
ドメインがメールサーバーをサポートしているかどうかを確認するだけの場合は、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);
.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;
}
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
}
}
}
基本的に、ドメインの MX/SPF レコードを要求する DNS 要求を行う必要があります。C# でこれを行う例がいくつかあります。http://mailsystem.codeplex.com/にライブラリがあり、これを行うための便利なValidator
クラスGetMxRecords
があります。
価値があるのは、MailBee の .NET オブジェクトもこれをサポートしていることです。これは、このコンポーネントを既に所有していて、何か他のものを実装しようとしていたときに、このグッズがすでに私たちが持っていたものに組み込まれていることを発見したためです。
http://www.afterlogic.com/mailbee-net/docs/filter_spam_with_dns.html
すべてのウェブサイトがこれを間違っているのはおかしい
SPF は TXT ではありません
SPF なしの txt レコードと TXT なしの SPF を持つことができるため、TXT ルックアップは SPF を表示しません。