2using System.Collections.Generic;
4using System.Threading.Tasks;
33 public static Task<KeyValuePair<SpfResult, string>>
CheckHost(IPAddress Address,
string DomainName,
string Sender,
34 string HelloDomain,
string HostDomain, params
SpfExpression[] SpfExpressions)
36 Term Term =
new Term(Sender, DomainName, Address, HelloDomain, HostDomain);
51 Exp Explanation =
null;
52 string[] TermStrings =
null;
59 foreach (
string Row
in TXT)
63 if (s.Length > 1 && s[0] ==
'"' && s[s.Length - 1] ==
'"')
64 s = s.Substring(1, s.Length - 2);
66 if (!s.StartsWith(
"v=spf1"))
69 if (!(TermStrings is
null))
70 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple SPF records found for " +
Term.domain +
".");
72 TermStrings = s.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
80 if (TermStrings is
null)
82 if (!(SpfExpressions is
null))
88 if (Expression.
Spf.StartsWith(
"v=spf1"))
90 TermStrings = Expression.
Spf.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
97 if (TermStrings is
null)
98 return new KeyValuePair<SpfResult, string>(
SpfResult.None,
"No SPF records found " +
Term.domain +
".");
103 int c = TermStrings.Length;
104 LinkedList<Mechanism> Mechanisms =
new LinkedList<Mechanism>();
110 for (i = 0; i < c; i++)
115 Term.SkipWhiteSpace();
117 switch (
Term.PeekNextChar())
144 switch (
Term.NextLabel().ToLower())
147 Mechanisms.AddLast(
new All(
Term, Qualifier));
151 Mechanisms.AddLast(
new Include(
Term, Qualifier, SpfExpressions));
155 Mechanisms.AddLast(
new A(
Term, Qualifier));
159 Mechanisms.AddLast(
new Mx(
Term, Qualifier));
163 Mechanisms.AddLast(
new Ptr(
Term, Qualifier));
167 Mechanisms.AddLast(
new Ip4(
Term, Qualifier));
171 Mechanisms.AddLast(
new Ip6(
Term, Qualifier));
175 Mechanisms.AddLast(
new Exists(
Term, Qualifier));
180 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple redirect modifiers foundin SPF record.");
186 if (!(Explanation is
null))
187 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple exp modifiers foundin SPF record.");
189 Explanation =
new Exp(
Term, Qualifier);
193 throw new Exception(
"Syntax error.");
209 case SpfQualifier.Fail:
return new KeyValuePair<SpfResult, string>(
SpfResult.Fail, Explanation is
null ?
null : await Explanation.
Evaluate());
211 case SpfQualifier.SoftFail:
return new KeyValuePair<SpfResult, string>(
SpfResult.SoftFail, Explanation is
null ?
null : await Explanation.
Evaluate());
216 return new KeyValuePair<SpfResult, string>(
SpfResult.TemporaryError, Explanation is
null ?
null : await Explanation.
Evaluate());
220 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError, Explanation is
null ?
null : await Explanation.
Evaluate());
228 string Bak =
Term.domain;
235 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError, Explanation is
null ?
null : await Explanation.
Evaluate());
237 string.IsNullOrEmpty(Result.Value))
239 return new KeyValuePair<SpfResult, string>(Result.Key, Explanation is
null ?
null : await Explanation.
Evaluate());
253 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Unable to evaluate SPF record: " + FirstRow(ex.Message));
256 return new KeyValuePair<SpfResult, string>(
SpfResult.Neutral,
null);
259 private static string FirstRow(
string s)
261 int i = s.IndexOfAny(CRLF);
265 return s.Substring(0, i);
268 private static readonly
char[] space =
new char[] {
' ' };
269 private static readonly
char[] CRLF =
new char[] {
'\r',
'\n' };
DNS resolver, as defined in:
static async Task< string[]> LookupText(string Name)
Looks up text (TXT) records for a name.
This mechanism matches if <ip> is one of the <target-name>'s IP addresses.For clarity,...
The "all" mechanism is a test that always matches. It is used as the rightmost mechanism in a record ...
This mechanism is used to construct an arbitrary domain name that is used for a DNS A record query....
If check_host() results in a "fail" due to a mechanism match (such as "-all"), and the "exp" modifier...
async Task< string > Evaluate()
Evaluates the explanation.
The "include" mechanism triggers a recursive evaluation of check_host().
This mechanisms tests whether <ip> is contained within a given IP4 network.
This mechanisms tests whether <ip> is contained within a given IP6 network.
string Domain
Domain specification
override async Task Expand()
Expands any macros in the domain specification.
Abstract base class for SPF Mechanisms.
virtual Task Expand()
Expands any macros in the domain specification.
abstract Task< SpfResult > Matches()
Checks if the mechamism matches the current request.
SpfQualifier Qualifier
Mechanism qualifier
This mechanism tests whether the DNS reverse-mapping for <ip> exists and correctly points to a domain...
The "redirect" modifier is intended for consolidating both authorizations and policy into a common se...
Contains information about a SPF string.
bool IsApplicable(string Domain)
Checks if the expression is applicable to a given domain.
string Spf
SPF expression.
Resolves a SPF string, as defined in:
static Task< KeyValuePair< SpfResult, string > > CheckHost(IPAddress Address, string DomainName, string Sender, string HelloDomain, string HostDomain, params SpfExpression[] SpfExpressions)
Fetches SPF records, parses them, and evaluates them to determine whether a particular host is or is ...
void Reset(string String)
Resets the string representation of the term.
SpfQualifier
SPF Mechanism qualifier
SpfResult
Result of a SPF (Sender Policy Framework) evaluation.