Example #1
0
        internal SpfQualifier CheckHost(SpfCheckHostParameter parameters)
        {
            if (String.IsNullOrEmpty(parameters.Sender))
            {
                return(SpfQualifier.PermError);
            }

            if (!parameters.Sender.Contains('@'))
            {
                parameters.Sender = "postmaster@" + parameters.Sender;
            }

            if (parameters.LoopCount > 15)
            {
                return(SpfQualifier.PermError);
            }

            if ((Terms == null) || (Terms.Count == 0))
            {
                return(SpfQualifier.Neutral);
            }

            foreach (SpfTerm term in Terms)
            {
                SpfQualifier qualifier = term.CheckHost(parameters);

                if (qualifier != SpfQualifier.None)
                {
                    return(qualifier);
                }
            }

            return(SpfQualifier.Neutral);
        }
Example #2
0
 public SpfCheckHostParameter(string newDomain, SpfCheckHostParameter oldParameters)
 {
     LoopCount     = oldParameters.LoopCount + 1;
     ClientAddress = oldParameters.ClientAddress;
     ClientName    = oldParameters.ClientName;
     HeloName      = oldParameters.HeloName;
     CurrentDomain = newDomain;
     Sender        = oldParameters.Sender;
 }
 public SpfCheckHostParameter(string newDomain, SpfCheckHostParameter oldParameters)
 {
     LoopCount = oldParameters.LoopCount + 1;
     ClientAddress = oldParameters.ClientAddress;
     ClientName = oldParameters.ClientName;
     HeloName = oldParameters.HeloName;
     CurrentDomain = newDomain;
     Sender = oldParameters.Sender;
 }
Example #4
0
        internal static SpfQualifier CheckHost(string spfDomain, SpfCheckHostParameter parameters)
        {
            #region First try "real" spf records
            List <SpfRecord> spfRecords = GetValidSpfRecords(spfDomain, RecordType.Spf);
            if (spfRecords == null)
            {
                return(SpfQualifier.TempError);
            }
            else if (spfRecords.Count > 1)
            {
                return(SpfQualifier.PermError);
            }
            else if (spfRecords.Count == 1)
            {
                return(spfRecords[0].CheckHost(parameters));
            }
            #endregion

            #region Then fallback to TXT records
            spfRecords = GetValidSpfRecords(spfDomain, RecordType.Txt);
            if (spfRecords == null)
            {
                return(SpfQualifier.TempError);
            }
            else if (spfRecords.Count > 1)
            {
                return(SpfQualifier.PermError);
            }
            else if (spfRecords.Count == 1)
            {
                return(spfRecords[0].CheckHost(parameters));
            }
            else
            {
                return(SpfQualifier.None);
            }
            #endregion
        }
        internal static SpfQualifier CheckHost(string spfDomain, SpfCheckHostParameter parameters)
        {
            #region First try "real" spf records
            List<SpfRecord> spfRecords = GetValidSpfRecords(spfDomain, RecordType.Spf);
            if (spfRecords == null)
            {
                return SpfQualifier.TempError;
            }
            else if (spfRecords.Count > 1)
            {
                return SpfQualifier.PermError;
            }
            else if (spfRecords.Count == 1)
            {
                return spfRecords[0].CheckHost(parameters);
            }
            #endregion

            #region Then fallback to TXT records
            spfRecords = GetValidSpfRecords(spfDomain, RecordType.Txt);
            if (spfRecords == null)
            {
                return SpfQualifier.TempError;
            }
            else if (spfRecords.Count > 1)
            {
                return SpfQualifier.PermError;
            }
            else if (spfRecords.Count == 1)
            {
                return spfRecords[0].CheckHost(parameters);
            }
            else
            {
                return SpfQualifier.None;
            }
            #endregion
        }
        internal SpfQualifier CheckHost(SpfCheckHostParameter parameters)
        {
            if (String.IsNullOrEmpty(parameters.Sender))
                return SpfQualifier.PermError;

            if (!parameters.Sender.Contains('@'))
                parameters.Sender = "postmaster@" + parameters.Sender;

            if (parameters.LoopCount > 15)
                return SpfQualifier.PermError;

            if ((Terms == null) || (Terms.Count == 0))
                return SpfQualifier.Neutral;

            foreach (SpfTerm term in Terms)
            {
                SpfQualifier qualifier = term.CheckHost(parameters);

                if (qualifier != SpfQualifier.None)
                    return qualifier;
            }

            return SpfQualifier.Neutral;
        }
Example #7
0
        private static string ExpandMacro(Match pattern, SpfCheckHostParameter parameters)
        {
            switch (pattern.Value)
            {
            case "%%":
                return("%");

            case "%_":
                return("_");

            case "%-":
                return("-");

            default:
                string letter;
                switch (pattern.Groups["letter"].Value)
                {
                case "s":
                    letter = parameters.Sender;
                    break;

                case "l":
                    // no boundary check needed, sender is validated on start of CheckHost
                    letter = parameters.Sender.Split('@')[0];
                    break;

                case "o":
                    // no boundary check needed, sender is validated on start of CheckHost
                    letter = parameters.Sender.Split('@')[1];
                    break;

                case "d":
                    letter = parameters.CurrentDomain;
                    break;

                case "i":
                    letter = String.Join(".", parameters.ClientAddress.GetAddressBytes().Select(b => b.ToString()).ToArray());
                    break;

                case "p":
                    letter = parameters.ClientName;
                    break;

                case "v":
                    letter = (parameters.ClientAddress.AddressFamily == AddressFamily.InterNetworkV6) ? "ip6" : "in-addr";
                    break;

                case "h":
                    letter = parameters.HeloName;
                    break;

                case "c":
                    letter = parameters.ClientAddress.ToString();
                    break;

                case "r":
                    letter = System.Net.Dns.GetHostName();
                    break;

                case "t":
                    letter = ((int)(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) - DateTime.Now).TotalSeconds).ToString();
                    break;

                default:
                    return(null);
                }

                // only letter
                if (pattern.Value.Length == 4)
                {
                    return(letter);
                }

                char[] delimiters = pattern.Groups["delimiter"].Value.ToCharArray();
                if (delimiters.Length == 0)
                {
                    delimiters = new char[] { '.' }
                }
                ;

                string[] parts = letter.Split(delimiters);

                if (pattern.Groups["reverse"].Value == "r")
                {
                    parts = parts.Reverse().ToArray();
                }

                int count = Int32.MaxValue;
                if (!String.IsNullOrEmpty(pattern.Groups["count"].Value))
                {
                    count = Int32.Parse(pattern.Groups["count"].Value);
                }

                if (count < 1)
                {
                    return(null);
                }

                count = Math.Min(count, parts.Length);

                return(String.Join(".", parts, (parts.Length - count), count));
            }
        }
Example #8
0
        private static string ExpandDomain(string pattern, SpfCheckHostParameter parameters)
        {
            Regex regex = new Regex(@"(%%|%_|%-|%\{(?<letter>[slodiphcrtv])(?<count>\d*)(?<reverse>r?)(?<delimiter>[\.\-+,/=]*)})", RegexOptions.Compiled);

            return(regex.Replace(pattern, match => ExpandMacro(match, parameters)));
        }
Example #9
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);
        }
Example #10
0
        private static string ExpandMacro(Match pattern, SpfCheckHostParameter parameters)
        {
            switch (pattern.Value)
            {
                case "%%":
                    return "%";
                case "%_":
                    return "_";
                case "%-":
                    return "-";

                default:
                    string letter;
                    switch (pattern.Groups["letter"].Value)
                    {
                        case "s":
                            letter = parameters.Sender;
                            break;
                        case "l":
                            // no boundary check needed, sender is validated on start of CheckHost
                            letter = parameters.Sender.Split('@')[0];
                            break;
                        case "o":
                            // no boundary check needed, sender is validated on start of CheckHost
                            letter = parameters.Sender.Split('@')[1];
                            break;
                        case "d":
                            letter = parameters.CurrentDomain;
                            break;
                        case "i":
                            letter = String.Join(".", parameters.ClientAddress.GetAddressBytes().Select(b => b.ToString()).ToArray());
                            break;
                        case "p":
                            letter = parameters.ClientName;
                            break;
                        case "v":
                            letter = (parameters.ClientAddress.AddressFamily == AddressFamily.InterNetworkV6) ? "ip6" : "in-addr";
                            break;
                        case "h":
                            letter = parameters.HeloName;
                            break;
                        case "c":
                            letter = parameters.ClientAddress.ToString();
                            break;
                        case "r":
                            letter = System.Net.Dns.GetHostName();
                            break;
                        case "t":
                            letter = ((int) (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) - DateTime.Now).TotalSeconds).ToString();
                            break;
                        default:
                            return null;
                    }

                    // only letter
                    if (pattern.Value.Length == 4)
                        return letter;

                    char[] delimiters = pattern.Groups["delimiter"].Value.ToCharArray();
                    if (delimiters.Length == 0)
                        delimiters = new char[] { '.' };

                    string[] parts = letter.Split(delimiters);

                    if (pattern.Groups["reverse"].Value == "r")
                        parts = parts.Reverse().ToArray();

                    int count = Int32.MaxValue;
                    if (!String.IsNullOrEmpty(pattern.Groups["count"].Value))
                    {
                        count = Int32.Parse(pattern.Groups["count"].Value);
                    }

                    if (count < 1)
                        return null;

                    count = Math.Min(count, parts.Length);

                    return String.Join(".", parts, (parts.Length - count), count);
            }
        }
Example #11
0
        private static string ExpandDomain(string pattern, SpfCheckHostParameter parameters)
        {
            Regex regex = new Regex(@"(%%|%_|%-|%\{(?<letter>[slodiphcrtv])(?<count>\d*)(?<reverse>r?)(?<delimiter>[\.\-+,/=]*)})", RegexOptions.Compiled);

            return regex.Replace(pattern, match => ExpandMacro(match, parameters));
        }
Example #12
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;
        }