예제 #1
0
파일: Explanation.cs 프로젝트: large/NetSPF
        public async Task <string> Evaluate()
        {
            try
            {
                await Expand();

                StringBuilder sb = new StringBuilder();

                foreach (string text in await DnsResolver.LookupText(Domain))
                {
                    sb.Append(text); // No white-space delimiter
                }
                SpfStatement.Reset("=" + sb.ToString());
                Explanation explanation = new Explanation(SpfStatement, Qualifier);

                await explanation.Expand();

                return(explanation.Domain);
            }
            catch (Exception)
            {
                return(null);
            }
        }
예제 #2
0
        public override async Task Expand()
        {
            if (_expanded)
            {
                return;
            }

            _expanded = true;
            SpfStatement.Reset(Domain);

            StringBuilder sb = new StringBuilder();
            char          ch;

            while ((ch = SpfStatement.PeekNextCharacter()) > ' ')
            {
                SpfStatement.Position++;

                if (ch == '%')
                {
                    switch (ch = SpfStatement.PeekNextCharacter())
                    {
                    case (char)0:
                        sb.Append('%');
                        break;

                    case '%':
                        SpfStatement.Position++;
                        sb.Append('%');
                        break;

                    case '_':
                        SpfStatement.Position++;
                        sb.Append(' ');
                        break;

                    case '-':
                        SpfStatement.Position++;
                        sb.Append("%20");
                        break;

                    case '{':
                        SpfStatement.Position++;

                        char macroLetter = char.ToLower(SpfStatement.NextCharacter());
                        int? digit;
                        bool reverse;

                        if (char.IsDigit(SpfStatement.PeekNextCharacter()))
                        {
                            digit = SpfStatement.NextInteger();

                            if (digit == 0)
                            {
                                throw new Exception("Invalid number of digits.");
                            }
                        }
                        else
                        {
                            digit = null;
                        }

                        if (char.ToLower(SpfStatement.PeekNextCharacter()) == 'r')
                        {
                            SpfStatement.Position++;
                            reverse = true;
                        }
                        else
                        {
                            reverse = false;
                        }

                        int start = SpfStatement.Position;
                        while ((ch = SpfStatement.PeekNextCharacter()) == '.' || ch == '-' || ch == '+' ||
                               ch == ',' || ch == '/' || ch == '_' || ch == '=')
                        {
                            SpfStatement.Position++;
                        }

                        string delimiter =
                            SpfStatement.Statement.Substring(start, SpfStatement.Position - start);

                        ch = SpfStatement.NextCharacter();
                        if (ch != '}')
                        {
                            throw new Exception("Expected }");
                        }

                        string s;

                        switch (macroLetter)
                        {
                        case 's':         // sender
                            s = SpfStatement.Sender;
                            break;

                        case 'l':         // local-part of sender
                            s = SpfStatement.Sender;
                            int i = s.IndexOf('@');
                            if (i < 0)
                            {
                                s = string.Empty;
                            }
                            else
                            {
                                s = s.Substring(0, i);
                            }
                            break;

                        case 'o':         // domain of sender
                            s = SpfStatement.Sender;
                            i = s.IndexOf('@');
                            if (i >= 0)
                            {
                                s = s.Substring(i + 1);
                            }
                            break;

                        case 'd':         // domain
                            s = SpfStatement.Domain;
                            break;

                        case 'i':
                            switch (SpfStatement.IpAddress.AddressFamily)
                            {
                            case AddressFamily.InterNetwork:
                                s = SpfStatement.IpAddress.ToString();
                                break;

                            case AddressFamily.InterNetworkV6:
                                byte[] bin = SpfStatement.IpAddress.GetAddressBytes();

                                StringBuilder sb2 = new StringBuilder();
                                byte          b, b2;

                                for (i = 0; i < 16; i++)
                                {
                                    b = bin[i];

                                    b2 = (byte)(b >> 4);
                                    if (b2 < 10)
                                    {
                                        sb2.Append((char)('0' + b2));
                                    }
                                    else
                                    {
                                        sb2.Append((char)('a' + b2 - 10));
                                    }

                                    sb2.Append('.');

                                    b2 = (byte)(b & 15);
                                    if (b2 < 10)
                                    {
                                        sb2.Append((char)('0' + b2));
                                    }
                                    else
                                    {
                                        sb2.Append((char)('a' + b2 - 10));
                                    }

                                    if (i < 15)
                                    {
                                        sb2.Append('.');
                                    }
                                }

                                s = sb2.ToString();
                                break;

                            default:
                                throw new Exception("Invalid client address.");
                            }

                            break;

                        case 'p':
                            try
                            {
                                if (SpfStatement.RemainingQueries-- <= 0)
                                {
                                    throw new Exception("DNS Lookup maximum reached.");
                                }

                                string[] domainNames =
                                    await DnsResolver.LookupDomainName(SpfStatement.IpAddress);

                                // First check if domain is found.

                                s = null;
                                foreach (string domainName in domainNames)
                                {
                                    if (String.Compare(domainName, SpfStatement.Domain,
                                                       StringComparison.OrdinalIgnoreCase) == 0 &&
                                        await this.MatchReverseIp(domainName))
                                    {
                                        s = domainName;
                                        break;
                                    }
                                }

                                if (s is null)
                                {
                                    // Second, check if sub-domain is found.

                                    foreach (string domainName in domainNames)
                                    {
                                        if (domainName.EndsWith("." + SpfStatement.Domain,
                                                                StringComparison.CurrentCultureIgnoreCase) &&
                                            await this.MatchReverseIp(domainName))
                                        {
                                            s = domainName;
                                            break;
                                        }
                                    }

                                    if (s is null)
                                    {
                                        if (domainNames.Length == 0)
                                        {
                                            s = "unknown";
                                        }
                                        else
                                        {
                                            s = domainNames[DnsResolver.Next(domainNames.Length)];
                                        }
                                    }
                                }
                            }
                            catch (ArgumentException)
                            {
                                s = "unknown";
                            }
                            catch (TimeoutException)
                            {
                                s = "unknown";
                            }

                            break;

                        case 'v':
                            switch (SpfStatement.IpAddress.AddressFamily)
                            {
                            case AddressFamily.InterNetwork:
                                s = "in-addr";
                                break;

                            case AddressFamily.InterNetworkV6:
                                s = "ip6";
                                break;

                            default:
                                throw new Exception("Invalid client address.");
                            }

                            break;

                        case 'h':
                            s = SpfStatement.HeloDomain;
                            break;

                        case 'c':
                            this.AssertExplanation();
                            s = SpfStatement.IpAddress.ToString();
                            break;

                        case 'r':
                            this.AssertExplanation();
                            s = SpfStatement.HostDomain;
                            break;

                        case 't':
                            this.AssertExplanation();
                            int seconds = (int)Math.Round((DateTime.UtcNow - UnixEpoch).TotalSeconds);
                            s = seconds.ToString();
                            break;

                        default:
                            throw new Exception("Unknown macro.");
                        }

                        if (reverse || digit.HasValue || !string.IsNullOrEmpty(delimiter))
                        {
                            if (string.IsNullOrEmpty(delimiter))
                            {
                                delimiter = ".";
                            }

                            string[] parts = s.Split(new string[] { delimiter }, StringSplitOptions.None);
                            int      i     = parts.Length;

                            if (reverse)
                            {
                                Array.Reverse(parts);
                            }

                            if (digit.HasValue && digit.Value < i)
                            {
                                i = digit.Value;
                            }

                            bool first = true;
                            int  j     = parts.Length - i;

                            while (i-- > 0)
                            {
                                if (first)
                                {
                                    first = false;
                                }
                                else
                                {
                                    sb.Append('.');
                                }

                                sb.Append(parts[j++]);
                            }
                        }
                        else
                        {
                            sb.Append(s);
                        }

                        break;

                    default:
                        SpfStatement.Position++;
                        sb.Append('%');
                        sb.Append(ch);
                        break;
                    }
                }
                else
                {
                    sb.Append(ch);
                }
            }

            Domain = sb.ToString();
        }