/// <summary> /// Tries to parse the textual representation of a SPF string /// </summary> /// <param name="s"> Textual representation to check </param> /// <param name="value"> Parsed spf record in case of successful parsing </param> /// <returns> true in case of successful parsing </returns> public static bool TryParse(string s, out SpfRecord value) { if (!IsSpfRecord(s)) { value = null; return false; } string[] terms = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); List<SpfTerm> parsedTerms; if (TryParseTerms(terms, out parsedTerms)) { value = new SpfRecord { Terms = parsedTerms }; return true; } else { value = null; return false; } }
internal SpfQualifier CheckHost(SpfCheckHostParameter parameters) { DnsMessage dnsMessage; SpfMechanism spfMechanism = this as SpfMechanism; if (spfMechanism != null) { switch (spfMechanism.Type) { case SpfMechanismType.All: return(spfMechanism.Qualifier); case SpfMechanismType.A: bool?isAMatch = IsIpMatch(String.IsNullOrEmpty(spfMechanism.Domain) ? parameters.CurrentDomain : spfMechanism.Domain, parameters.ClientAddress, spfMechanism.Prefix, spfMechanism.Prefix6); if (!isAMatch.HasValue) { return(SpfQualifier.TempError); } if (isAMatch.Value) { return(spfMechanism.Qualifier); } break; case SpfMechanismType.Mx: dnsMessage = DnsClient.Default.Resolve(ExpandDomain(String.IsNullOrEmpty(spfMechanism.Domain) ? parameters.CurrentDomain : spfMechanism.Domain, parameters), RecordType.Mx); if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain))) { return(SpfQualifier.TempError); } int mxCheckedCount = 0; foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords) { MxRecord mxRecord = dnsRecord as MxRecord; if (mxRecord != null) { if (++mxCheckedCount == 10) { break; } bool?isMxMatch = IsIpMatch(mxRecord.ExchangeDomainName, parameters.ClientAddress, spfMechanism.Prefix, spfMechanism.Prefix6); if (!isMxMatch.HasValue) { return(SpfQualifier.TempError); } if (isMxMatch.Value) { return(spfMechanism.Qualifier); } } } break; case SpfMechanismType.Ip4: case SpfMechanismType.Ip6: IPAddress compareAddress; if (IPAddress.TryParse(spfMechanism.Domain, out compareAddress)) { if (spfMechanism.Prefix.HasValue) { if (parameters.ClientAddress.GetNetworkAddress(spfMechanism.Prefix.Value).Equals(compareAddress.GetNetworkAddress(spfMechanism.Prefix.Value))) { return(spfMechanism.Qualifier); } } else if (parameters.ClientAddress.Equals(compareAddress)) { return(spfMechanism.Qualifier); } } else { return(SpfQualifier.PermError); } break; case SpfMechanismType.Ptr: dnsMessage = DnsClient.Default.Resolve(parameters.ClientAddress.GetReverseLookupAddress(), RecordType.Ptr); if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain))) { return(SpfQualifier.TempError); } string ptrCompareName = String.IsNullOrEmpty(spfMechanism.Domain) ? parameters.CurrentDomain : spfMechanism.Domain; int ptrCheckedCount = 0; if ((from ptrRecord in dnsMessage.AnswerRecords.OfType <PtrRecord>().TakeWhile(ptrRecord => ++ ptrCheckedCount != 10) let isPtrMatch = IsIpMatch(ptrRecord.PointerDomainName, parameters.ClientAddress, 0, 0) where isPtrMatch.HasValue && isPtrMatch.Value select ptrRecord).Any(ptrRecord => ptrRecord.PointerDomainName.Equals(ptrCompareName, StringComparison.InvariantCultureIgnoreCase) || (ptrRecord.PointerDomainName.EndsWith("." + ptrCompareName, StringComparison.InvariantCultureIgnoreCase)))) { return(spfMechanism.Qualifier); } break; case SpfMechanismType.Exist: if (String.IsNullOrEmpty(spfMechanism.Domain)) { return(SpfQualifier.PermError); } dnsMessage = DnsClient.Default.Resolve(ExpandDomain(spfMechanism.Domain, parameters), RecordType.A); if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain))) { return(SpfQualifier.TempError); } if (dnsMessage.AnswerRecords.Count(record => (record.RecordType == RecordType.A)) > 0) { return(spfMechanism.Qualifier); } break; case SpfMechanismType.Include: if (String.IsNullOrEmpty(spfMechanism.Domain)) { return(SpfQualifier.PermError); } string includeDomain = ExpandDomain(spfMechanism.Domain, parameters); switch (SpfRecord.CheckHost(includeDomain, new SpfCheckHostParameter(includeDomain, parameters))) { case SpfQualifier.Pass: return(spfMechanism.Qualifier); case SpfQualifier.Fail: case SpfQualifier.SoftFail: case SpfQualifier.Neutral: return(SpfQualifier.None); case SpfQualifier.TempError: return(SpfQualifier.TempError); case SpfQualifier.PermError: case SpfQualifier.None: return(SpfQualifier.PermError); } break; default: return(SpfQualifier.PermError); } } SpfModifier spfModifier = this as SpfModifier; if (spfModifier != null) { switch (spfModifier.Type) { case SpfModifierType.Redirect: if (String.IsNullOrEmpty(spfModifier.Domain)) { return(SpfQualifier.PermError); } string redirectDomain = ExpandDomain(spfModifier.Domain, parameters); return(SpfRecord.CheckHost(redirectDomain, new SpfCheckHostParameter(redirectDomain, parameters))); case SpfModifierType.Exp: break; default: return(SpfQualifier.PermError); } } return(SpfQualifier.None); }