3using System.Net.Sockets;
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.");
203 foreach (
string DomainName
in DomainNames)
205 if (
string.Compare(DomainName, this.
term.domain,
true) == 0 &&
206 await
this.MatchReverseIp(DomainName))
217 foreach (
string DomainName
in DomainNames)
219 if (DomainName.EndsWith(
"." +
this.term.domain, StringComparison.CurrentCultureIgnoreCase) &&
220 await
this.MatchReverseIp(DomainName))
229 if (DomainNames.Length == 0)
236 catch (ArgumentException)
240 catch (TimeoutException)
247 switch (this.
term.ip.AddressFamily)
249 case AddressFamily.InterNetwork:
253 case AddressFamily.InterNetworkV6:
258 throw new Exception(
"Invalid client address.");
263 s = this.
term.helloDomain;
268 s = this.
term.ip.ToString();
273 s = this.
term.hostDomain;
278 int Seconds = (int)Math.Round((DateTime.UtcNow -
UnixEpoch).TotalSeconds);
279 s = Seconds.ToString();
283 throw new Exception(
"Unknown macro.");
286 if (Reverse || Digit.HasValue || !
string.IsNullOrEmpty(Delimiter))
288 if (
string.IsNullOrEmpty(Delimiter))
291 string[] Parts = s.Split(
new string[] { Delimiter }, StringSplitOptions.None);
292 int i = Parts.Length;
295 Array.Reverse(Parts);
297 if (Digit.HasValue && Digit.Value < i)
301 int j = Parts.Length - i;
310 sb.Append(Parts[j++]);
328 this.domain = sb.ToString();
331 internal async Task<bool> MatchReverseIp(
string DomainName)
333 if (this.
term.dnsLookupsLeft-- <= 0)
334 throw new Exception(
"DNS Lookup maximum reached.");
336 IPAddress[] Addresses;
338 switch (this.
term.ip.AddressFamily)
340 case AddressFamily.InterNetwork:
344 case AddressFamily.InterNetworkV6:
349 throw new Exception(
"Invalid client address.");
352 string Temp = this.
term.ip.ToString();
354 foreach (IPAddress Addr
in Addresses)
356 if (
string.Compare(Addr.ToString(), Temp,
true) == 0)
366 public static readonly DateTime
UnixEpoch =
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
368 private void AssertExp()
371 throw new Exception(
"Macro only available in exp");
392 public string TargetDomain =>
string.IsNullOrEmpty(this.domain) ? this.term.domain : this.domain;
DNS resolver, as defined in:
static async Task< string[]> LookupDomainName(IPAddress Address)
Looks up the domain name pointing to a specific IP address.
static async Task< IPAddress[]> LookupIP6Addresses(string DomainName)
Looks up the IPv6 addresses related to a given domain name.
static async Task< IPAddress[]> LookupIP4Addresses(string DomainName)
Looks up the IPv4 addresses related to a given domain name.
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