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;
62 foreach (
string Row
in TXT)
66 if (s.Length > 1 && s[0] ==
'"' && s[s.Length - 1] ==
'"')
67 s = s.Substring(1, s.Length - 2);
69 if (!s.StartsWith(
"v=spf1"))
72 if (!(TermStrings is
null))
73 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple SPF records found for " +
Term.domain +
".");
75 TermStrings = s.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
84 if (TermStrings is
null)
86 if (!(SpfExpressions is
null))
92 if (Expression.
Spf.StartsWith(
"v=spf1"))
94 TermStrings = Expression.
Spf.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
101 if (TermStrings is
null)
102 return new KeyValuePair<SpfResult, string>(
SpfResult.None,
"No SPF records found " +
Term.domain +
".");
107 int c = TermStrings.Length;
108 LinkedList<Mechanism> Mechanisms =
new LinkedList<Mechanism>();
114 for (i = 0; i < c; i++)
119 Term.SkipWhiteSpace();
121 switch (
Term.PeekNextChar())
148 switch (
Term.NextLabel().ToLower())
151 Mechanisms.AddLast(
new All(
Term, Qualifier));
155 Mechanisms.AddLast(
new Include(
Term, Qualifier, SpfExpressions));
159 Mechanisms.AddLast(
new A(
Term, Qualifier));
163 Mechanisms.AddLast(
new Mx(
Term, Qualifier));
167 Mechanisms.AddLast(
new Ptr(
Term, Qualifier));
171 Mechanisms.AddLast(
new Ip4(
Term, Qualifier));
175 Mechanisms.AddLast(
new Ip6(
Term, Qualifier));
179 Mechanisms.AddLast(
new Exists(
Term, Qualifier));
184 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple redirect modifiers foundin SPF record.");
190 if (!(Explanation is
null))
191 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Multiple exp modifiers foundin SPF record.");
193 Explanation =
new Exp(
Term, Qualifier);
197 throw new Exception(
"Syntax error.");
213 case SpfQualifier.Fail:
return new KeyValuePair<SpfResult, string>(
SpfResult.Fail, Explanation is
null ?
null : await Explanation.
Evaluate());
215 case SpfQualifier.SoftFail:
return new KeyValuePair<SpfResult, string>(
SpfResult.SoftFail, Explanation is
null ?
null : await Explanation.
Evaluate());
220 return new KeyValuePair<SpfResult, string>(
SpfResult.TemporaryError, Explanation is
null ?
null : await Explanation.
Evaluate());
224 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError, Explanation is
null ?
null : await Explanation.
Evaluate());
232 string Bak =
Term.domain;
239 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError, Explanation is
null ?
null : await Explanation.
Evaluate());
241 string.IsNullOrEmpty(Result.Value))
243 return new KeyValuePair<SpfResult, string>(Result.Key, Explanation is
null ?
null : await Explanation.
Evaluate());
257 return new KeyValuePair<SpfResult, string>(
SpfResult.PermanentError,
"Unable to evaluate SPF record: " + FirstRow(ex.Message));
260 return new KeyValuePair<SpfResult, string>(
SpfResult.Neutral,
null);
263 private static string FirstRow(
string s)
265 int i = s.IndexOfAny(CRLF);
269 return s.Substring(0, i);
272 private static readonly
char[] space =
new char[] {
' ' };
273 private static readonly
char[] CRLF =
new char[] {
'\r',
'\n' };
DNS resolver, as defined in:
static Task< string[]> TryLookupText(string Name)
Tries to look 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.