/// <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;
			}
		}
Exemple #2
0
        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);
        }