5using System.Threading.Tasks;
15 private string domain;
16 private bool expanded =
false;
26 if (
Term.PeekNextChar() ==
this.Separator)
33 while ((ch =
Term.PeekNextChar()) >
' ' && ch !=
'/')
36 this.domain =
Term.s.Substring(Start,
Term.pos - Start);
39 throw new Exception(this.
Separator +
" expected.");
53 StringBuilder sb =
new StringBuilder();
56 while ((ch = this.
term.PeekNextChar()) >
' ')
62 switch (ch = this.
term.PeekNextChar())
86 char MacroLetter =
char.ToLower(this.
term.NextChar());
90 if (
char.IsDigit(this.
term.PeekNextChar()))
92 Digit = this.
term.NextInteger();
95 throw new Exception(
"Invalid number of digits.");
100 if (
char.ToLower(this.
term.PeekNextChar()) ==
'r')
108 int Start = this.
term.pos;
109 while ((ch = this.
term.PeekNextChar()) ==
'.' || ch ==
'-' || ch ==
'+' ||
110 ch ==
',' || ch ==
'/' || ch ==
'_' || ch ==
'=')
115 string Delimiter = this.
term.s.Substring(Start, this.
term.pos - Start);
117 ch = this.
term.NextChar();
119 throw new Exception(
"Expected }");
126 s = this.
term.sender;
130 s = this.
term.sender;
131 int i = s.IndexOf(
'@');
135 s = s.Substring(0, i);
139 s = this.
term.sender;
142 s = s.Substring(i + 1);
146 s = this.
term.domain;
150 switch (this.
term.ip.AddressFamily)
152 case AddressFamily.InterNetwork:
153 s = this.
term.ip.ToString();
156 case AddressFamily.InterNetworkV6:
157 byte[] Bin = this.
term.ip.GetAddressBytes();
159 StringBuilder sb2 =
new StringBuilder();
162 for (i = 0; i < 16; i++)
168 sb2.Append((
char)(
'0' + b2));
170 sb2.Append((
char)(
'a' + b2 - 10));
176 sb2.Append((
char)(
'0' + b2));
178 sb2.Append((
char)(
'a' + b2 - 10));
188 throw new Exception(
"Invalid client address.");
195 if (this.
term.dnsLookupsLeft-- <= 0)
196 throw new Exception(
"DNS Lookup maximum reached.");
200 if (DomainNames is
null)
207 foreach (
string DomainName
in DomainNames)
209 if (
string.Compare(DomainName, this.
term.domain,
true) == 0 &&
210 await
this.MatchReverseIp(DomainName))
221 foreach (
string DomainName
in DomainNames)
223 if (DomainName.EndsWith(
"." +
this.term.domain, StringComparison.CurrentCultureIgnoreCase) &&
224 await
this.MatchReverseIp(DomainName))
233 if (DomainNames.Length == 0)
241 catch (ArgumentException)
245 catch (TimeoutException)
252 switch (this.
term.ip.AddressFamily)
254 case AddressFamily.InterNetwork:
258 case AddressFamily.InterNetworkV6:
263 throw new Exception(
"Invalid client address.");
268 s = this.
term.helloDomain;
273 s = this.
term.ip.ToString();
278 s = this.
term.hostDomain;
283 int Seconds = (int)Math.Round((DateTime.UtcNow -
UnixEpoch).TotalSeconds);
284 s = Seconds.ToString();
288 throw new Exception(
"Unknown macro.");
291 if (Reverse || Digit.HasValue || !
string.IsNullOrEmpty(Delimiter))
293 if (
string.IsNullOrEmpty(Delimiter))
296 string[] Parts = s.Split(
new string[] { Delimiter }, StringSplitOptions.None);
297 int i = Parts.Length;
300 Array.Reverse(Parts);
302 if (Digit.HasValue && Digit.Value < i)
306 int j = Parts.Length - i;
315 sb.Append(Parts[j++]);
333 this.domain = sb.ToString();
336 internal async Task<bool> MatchReverseIp(
string DomainName)
338 if (this.
term.dnsLookupsLeft-- <= 0)
339 throw new Exception(
"DNS Lookup maximum reached.");
341 IPAddress[] Addresses;
343 switch (this.
term.ip.AddressFamily)
345 case AddressFamily.InterNetwork:
349 case AddressFamily.InterNetworkV6:
354 throw new Exception(
"Invalid client address.");
357 if (Addresses is
null)
360 string Temp = this.
term.ip.ToString();
362 foreach (IPAddress Addr
in Addresses)
364 if (
string.Compare(Addr.ToString(), Temp,
true) == 0)
374 public static readonly DateTime
UnixEpoch =
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
376 private void AssertExp()
379 throw new Exception(
"Macro only available in exp");
400 public string TargetDomain =>
string.IsNullOrEmpty(this.domain) ? this.term.domain : this.domain;
DNS resolver, as defined in:
static Task< IPAddress[]> TryLookupIP4Addresses(string DomainName)
Tries to look up the IPv4 addresses related to a given domain name.
static Task< IPAddress[]> TryLookupIP6Addresses(string DomainName)
Tries to look up the IPv6 addresses related to a given domain name.
static Task< string[]> TryLookupDomainName(IPAddress Address)
Tries to look up the domain name pointing to a specific IP address.
static int Next(int MaxValue)
Returns a non-negative random integer that is less than the specified maximum.
If check_host() results in a "fail" due to a mechanism match (such as "-all"), and the "exp" modifier...
Abstract base class for SPF mechanisms with a domain specification.
string Domain
Domain specification
MechanismDomainSpec(Term Term, SpfQualifier Qualifier)
Abstract base class for SPF mechanisms with a domain specification.
virtual char Separator
Mechanism separator
string TargetDomain
Target domain.
override async Task Expand()
Expands any macros in the domain specification.
static readonly DateTime UnixEpoch
UNIX Epoch, started at 1970-01-01, 00:00:00 (GMT)
virtual bool DomainRequired
If the domain specification is required.
Abstract base class for SPF Mechanisms.
readonly Term term
Current request.
SpfQualifier Qualifier
Mechanism qualifier
void Reset(string String)
Resets the string representation of the term.
SpfQualifier
SPF Mechanism qualifier