Esempio n. 1
0
        public void ResolveKnownGoodHostFromDefaultLocalDnsServerAndReturnIpAddress()
        {
            const string host = "host1";
            const string shimAddress = "127.0.0.1";

            using (ShimsContext.Create())
            {
                ShimDnsClient.AllInstances.ResolveStringRecordTypeRecordClass = (dnsClient, s, arg3, arg4) => new DnsMessage
                {
                    IsEDnsEnabled = true,
                    IsRecursionAllowed = true,
                    IsRecursionDesired = true,
                    ReturnCode = ReturnCode.NoError,
                    AnswerRecords = new List<DnsRecordBase>
                    {
                        new ARecord(host, 60, IPAddress.Parse(shimAddress))
                    }
                };

                var client = new DnsResolver();
                var address = client.Resolve(host);

                var expectedResults = IPAddress.Parse(shimAddress);

                Assert.AreEqual(expectedResults, address);
            }
        }
Esempio n. 2
0
        public void ResolveBadHsotFromLocalDnsServerAndReturnNull()
        {
            const string host = "host1.notadomain.com";

            using (ShimsContext.Create())
            {
                ShimDnsClient.AllInstances.ResolveStringRecordTypeRecordClass = (dnsClient, s, arg3, arg4) => new DnsMessage
                {
                    IsEDnsEnabled = true,
                    IsRecursionAllowed = true,
                    IsRecursionDesired = true,
                    ReturnCode = ReturnCode.NxDomain,
                    AnswerRecords = new List<DnsRecordBase>()
                };

                var client = new DnsResolver();
                var address = client.Resolve(host);

                Assert.IsNull(address);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Evaluates the function.
        /// </summary>
        /// <param name="Arguments">Function arguments.</param>
        /// <param name="Variables">Variables collection.</param>
        /// <returns>Function result.</returns>
        public override IElement Evaluate(IElement[] Arguments, Variables Variables)
        {
            string Name = Arguments[0].AssociatedObjectValue?.ToString() ?? string.Empty;
            string s;
            object Obj;
            QTYPE  TYPE;
            QCLASS CLASS;
            int    c = Arguments.Length;

            if (c < 2)
            {
                TYPE = QTYPE.A;
            }
            else
            {
                Obj = Arguments[1].AssociatedObjectValue;
                if (Obj is QTYPE Type2)
                {
                    TYPE = Type2;
                }
                else
                {
                    s = Obj?.ToString() ?? string.Empty;
                    if (!Enum.TryParse <QTYPE>(s, out TYPE))
                    {
                        throw new ScriptRuntimeException("Invalid QTYPE: " + s, this);
                    }
                }
            }

            if (c < 3)
            {
                CLASS = QCLASS.IN;
            }
            else
            {
                Obj = Arguments[2].AssociatedObjectValue;
                if (Obj is QCLASS Class2)
                {
                    CLASS = Class2;
                }
                else
                {
                    s = Obj?.ToString() ?? string.Empty;
                    if (!Enum.TryParse <QCLASS>(s, out CLASS))
                    {
                        throw new ScriptRuntimeException("Invalid QCLASS: " + s, this);
                    }
                }
            }

            ResourceRecord[] Records = DnsResolver.Resolve(Name, TYPE, CLASS).Result;

            if (Records.Length == 0)
            {
                throw new ScriptRuntimeException("Unable to resolve name.", this);
            }
            else if (Records.Length == 1)
            {
                return(new ObjectValue(Records[0]));
            }
            else
            {
                return(new ObjectVector(Records));
            }
        }
Esempio n. 4
0
        public void DynDnsHandler_Udp_CNAME()
        {
            // Start a Dynamic DNS service handler and a client, register CNAME
            // records and confirm that CNAME queries return the proper results.

            DynDnsClientSettings clientSettings;
            DynDnsHandler        handler = null;
            DynDnsClient         client  = null;
            DnsResponse          response;
            CNAME_RR             record;

            try
            {
                handler = new DynDnsHandler();
                handler.Start(router, null, null, null);

                clientSettings = new DynDnsClientSettings()
                {
                    Mode                = DynDnsMode.Udp,
                    NameServers         = new NetworkBinding[] { new NetworkBinding("127.0.0.1:DYNAMIC-DNS") },
                    UdpRegisterInterval = TimeSpan.FromSeconds(1)
                };

                client = new DynDnsClient();
                client.Register(new DynDnsHostEntry("test1.com,server.test1.com,1000,CNAME"));
                client.Register(new DynDnsHostEntry("test2.com,server.test2.com,2000,CNAME"));
                client.Open(router, clientSettings);

                // Wait for everything to spin up.

                Thread.Sleep(3000);

                // Verify the single result for a CNAME query on test1.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2));

                Assert.AreEqual("test1.com.", response.QName);
                Assert.AreEqual(DnsQType.CNAME, response.QType);
                Assert.AreEqual(1, response.Answers.Count);

                record = (CNAME_RR)response.Answers[0];
                Assert.AreEqual("test1.com.", record.RName);
                Assert.AreEqual("server.test1.com.", record.CName);
                Assert.AreEqual(1000, record.TTL);
                Thread.Sleep(2000);

                // Verify the single result for a CNAME query on test2.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test2.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2));

                Assert.AreEqual("test2.com.", response.QName);
                Assert.AreEqual(DnsQType.CNAME, response.QType);
                Assert.AreEqual(1, response.Answers.Count);

                record = (CNAME_RR)response.Answers[0];
                Assert.AreEqual("test2.com.", record.RName);
                Assert.AreEqual("server.test2.com.", record.CName);
                Assert.AreEqual(2000, record.TTL);
            }
            finally
            {
                if (client != null)
                {
                    client.Close();
                }

                if (handler != null)
                {
                    handler.Stop();
                }
            }
        }
Esempio n. 5
0
        public void DynDnsHandler_Udp_ADDRESS()
        {
            // Start a Dynamic DNS service handler and a client, register two ADDRESS
            // records for TEST1.COM and confirm that A queries load balance across the two entries.
            // I'm also going to add an ADDRESS record for TEST2.COM and verify that this address
            // is never returned.

            DynDnsClientSettings clientSettings;
            DynDnsHandler        handler = null;
            DynDnsClient         client  = null;
            DnsResponse          response;
            A_RR record;
            bool found1;
            bool found2;

            try
            {
                handler = new DynDnsHandler();
                handler.Start(router, null, null, null);

                clientSettings = new DynDnsClientSettings()
                {
                    Mode                = DynDnsMode.Udp,
                    NameServers         = new NetworkBinding[] { new NetworkBinding("127.0.0.1:DYNAMIC-DNS") },
                    UdpRegisterInterval = TimeSpan.FromSeconds(1)
                };

                client = new DynDnsClient();
                client.Register(new DynDnsHostEntry("test1.com,10.0.0.1,1000,ADDRESS"));
                client.Register(new DynDnsHostEntry("test1.com,10.0.0.2,1000,ADDRESS"));
                client.Register(new DynDnsHostEntry("test2.com,10.0.0.3,1000,ADDRESS"));
                client.Open(router, clientSettings);

                // Wait for everything to spin up.

                Thread.Sleep(3000);

                // Loop 1000 times or until we got responses for both entry IP addresses.  Note
                // that there's a 1000:1 chance that this could be working properly and the test
                // still fail.

                found1 = false;
                found2 = false;

                for (int i = 0; i < 1000; i++)
                {
                    response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.A), TimeSpan.FromSeconds(2));

                    Assert.AreEqual("test1.com.", response.QName);
                    Assert.AreEqual(DnsQType.A, response.QType);
                    Assert.AreEqual(1, response.Answers.Count);

                    record = (A_RR)response.Answers[0];
                    Assert.AreNotEqual(IPAddress.Parse("10.0.0.3"), record.Address);

                    if (IPAddress.Parse("10.0.0.1").Equals(record.Address))
                    {
                        found1 = true;
                    }
                    else if (IPAddress.Parse("10.0.0.2").Equals(record.Address))
                    {
                        found2 = true;
                    }
                    else
                    {
                        Assert.Fail();
                    }

                    if (found1 && found2)
                    {
                        break;
                    }
                }

                Assert.IsTrue(found1);
                Assert.IsTrue(found2);
            }
            finally
            {
                if (client != null)
                {
                    client.Close();
                }

                if (handler != null)
                {
                    handler.Stop();
                }
            }
        }
Esempio n. 6
0
        public void DynDnsHandler_Cluster_MX()
        {
            // Start a Dynamic DNS service handler and a client, register MX
            // records and confirm that MX queries return the proper results.

            DynDnsHandler handler = null;
            DynDnsClient  client  = null;
            DnsResponse   response;
            MX_RR         record;

            try
            {
                handler = new DynDnsHandler();
                handler.Start(router, null, null, null);

                client = new DynDnsClient();
                client.Register(new DynDnsHostEntry("test1.com,mail1.test1.com,1000,MX"));
                client.Register(new DynDnsHostEntry("test2.com,mail1.test2.com,2000,MX"));
                client.Register(new DynDnsHostEntry("test2.com,mail2.test2.com,3000,MX"));
                client.Open(router, new DynDnsClientSettings("DynDnsClient"));

                // Wait for all cluster members to come online and for
                // the host registrations to be replicated.

                WaitForOnline(handler.Cluster, waitTime);
                WaitForOnline(client.Cluster, waitTime);
                Thread.Sleep(2000);

                // Verify the single result for a MX query on test1.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.MX), TimeSpan.FromSeconds(2));

                Assert.AreEqual("test1.com.", response.QName);
                Assert.AreEqual(DnsQType.MX, response.QType);
                Assert.AreEqual(1, response.Answers.Count);

                record = (MX_RR)response.Answers[0];
                Assert.AreEqual("test1.com.", record.RName);
                Assert.AreEqual("mail1.test1.com.", record.Exchange);
                Assert.AreEqual(0, record.Preference);
                Assert.AreEqual(1000, record.TTL);
                Thread.Sleep(2000);

                // Verify the two results for a MX query on test2.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test2.com.", DnsQType.MX), TimeSpan.FromSeconds(2));

                Assert.AreEqual("test2.com.", response.QName);
                Assert.AreEqual(DnsQType.MX, response.QType);
                Assert.AreEqual(2, response.Answers.Count);

                record = (MX_RR)response.Answers.Single(r => ((MX_RR)r).Exchange == "mail1.test2.com.");
                Assert.AreEqual("test2.com.", record.RName);
                Assert.AreEqual("mail1.test2.com.", record.Exchange);
                Assert.AreEqual(0, record.Preference);
                Assert.AreEqual(2000, record.TTL);

                record = (MX_RR)response.Answers.Single(r => ((MX_RR)r).Exchange == "mail2.test2.com.");
                Assert.AreEqual("test2.com.", record.RName);
                Assert.AreEqual("mail2.test2.com.", record.Exchange);
                Assert.AreEqual(0, record.Preference);
                Assert.AreEqual(3000, record.TTL);
            }
            finally
            {
                if (client != null)
                {
                    client.Close();
                }

                if (handler != null)
                {
                    handler.Stop();
                }
            }
        }
Esempio n. 7
0
        public void DynDnsHandler_AddressCache()
        {
            // Verify that the server properly maintains a cache of specified hosts.

            DynDnsHandler handler = null;

            try
            {
                handler = new DynDnsHandler();
                handler.Start(router, "LillTek.Datacenter.DynDNS.AddressCache", null, null);

                // Wait for everything to spin up.

                Thread.Sleep(10000);

                // Verify that we have cached addresses for www.lilltek.com and www.google.com.

                var  addressCache = handler.GetCachedAddresses();
                bool foundLillTek = false;
                bool foundGoogle  = false;

                foreach (var entry in addressCache)
                {
                    switch (entry.HostName.ToLower())
                    {
                    case "www.lilltek.com.":

                        foundLillTek = entry.Addresses != null && entry.Addresses.Length > 0;
                        break;

                    case "www.google.com.":

                        foundGoogle = entry.Addresses != null && entry.Addresses.Length > 0;
                        break;
                    }
                }

                Assert.IsTrue(foundLillTek);
                Assert.IsTrue(foundGoogle);

                // Now verify that CNAME lookups that alias to these hosts include A records.

                DnsResponse response;
                bool        hasARecords;

                // test1.lilltek.com is an alias for www.lilltek.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.lilltek.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2));

                hasARecords = false;
                foreach (var record in response.Additional)
                {
                    if (record.RRType == DnsRRType.A)
                    {
                        hasARecords = true;
                        break;
                    }
                }

                Assert.IsTrue(hasARecords);

                // test1.lilltek.com is an alias for www.google.com

                response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test2.lilltek.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2));

                hasARecords = false;
                foreach (var record in response.Additional)
                {
                    if (record.RRType == DnsRRType.A)
                    {
                        hasARecords = true;
                        break;
                    }
                }

                Assert.IsTrue(hasARecords);
            }
            finally
            {
                if (handler != null)
                {
                    handler.Stop();
                }
            }
        }
        private void ProcessLocalConnection(object state)
        {
            var connection = (ConnectionInfo)state;
            var buffer     = new byte[BufferSize];
            int bytesRead;

            try
            {
                bytesRead = connection.LocalSocket.Receive(buffer);
                if (bytesRead < 1 || buffer[0] != Protocol.Socks4.Version)
                {
                    connection.LocalSocket.Close();
                    return;
                }

                OnLogMessage?.Invoke(this, $"LocalSocket.Receive {bytesRead}");
            }
            catch (SocketException ex)
            {
                OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode.ToString()}");
            }

            try
            {
                switch (buffer[1])
                {
                case Protocol.Socks4.CommandStreamConnection:
                {
                    var portBuffer = new[] { buffer[2], buffer[3] };
                    var port       = (ushort)(portBuffer[0] << 8 | portBuffer[1]);

                    var ipBuffer = new[] { buffer[4], buffer[5], buffer[6], buffer[7] };
                    var ip       = new IPAddress(ipBuffer);

                    var destinationEndPoint = new IPEndPoint(ip, port);
                    if (IsSocks4AProtocol(ipBuffer))
                    {
                        var hostBuffer = new byte[256];
                        Buffer.BlockCopy(buffer, 9, hostBuffer, 0, 100);

                        // Resolve hostname, fallback to remote proxy dns resolution
                        var hostname      = Encoding.ASCII.GetString(hostBuffer).TrimEnd((char)0);
                        var destinationIp = ResolveHostnamesRemotely ? null : DnsResolver.TryResolve(hostname);

                        connection.RemoteSocket = Socks5Client.Connect(
                            RemotEndPoint.Address.ToString(),
                            RemotEndPoint.Port, destinationIp == null ? hostname : destinationIp.ToString(),
                            port,
                            Username,
                            Password,
                            SendTimeout,
                            ReceiveTimeout
                            );

                        OnRemoteConnect?.Invoke(this, destinationEndPoint);
                    }
                    else
                    {
                        destinationEndPoint     = new IPEndPoint(new IPAddress(ipBuffer), port);
                        connection.RemoteSocket = Socks5Client.Connect(
                            RemotEndPoint.Address.ToString(),
                            RemotEndPoint.Port,
                            destinationEndPoint.Address.ToString(),
                            port,
                            Username,
                            Password,
                            SendTimeout,
                            ReceiveTimeout
                            );

                        OnRemoteConnect?.Invoke(this, destinationEndPoint);
                    }

                    if (connection.RemoteSocket.Connected)
                    {
                        SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestGranted, ipBuffer, portBuffer);

                        // Create the thread for the receives.
                        connection.RemoteThread = new Thread(ProcessRemoteConnection)
                        {
                            IsBackground = true
                        };
                        connection.RemoteThread.Start(connection);
                    }
                    else
                    {
                        OnLogMessage?.Invoke(this, "RemoteSocket connection failed");
                        SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer);
                        connection.LocalSocket.Close();
                    }

                    break;
                }

                case Protocol.Socks4.CommandBindingConnection:
                {
                    var portBuffer = new[] { buffer[2], buffer[3] };
                    var ipBuffer   = new[] { buffer[4], buffer[5], buffer[6], buffer[7] };

                    // TCP/IP port binding not supported
                    SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer);
                    connection.LocalSocket.Close();
                    break;
                }

                default:
                    OnLogMessage?.Invoke(this, "Unknown protocol on LocalSocket");
                    connection.LocalSocket.Close();
                    break;
                }

                // start receiving actual data if the socket still open
                while (true)
                {
                    if (!connection.LocalSocket.Connected || !connection.RemoteSocket.Connected)
                    {
                        break;
                    }

                    bytesRead = connection.LocalSocket.Receive(buffer);
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    if (connection.RemoteSocket.Connected)
                    {
                        connection.RemoteSocket.Send(buffer, bytesRead, SocketFlags.None);
                        OnLogMessage?.Invoke(this, $"Forwarded {bytesRead} bytes from LocalSocket to RemoteSocket");
                    }
                }
            }
            catch (SocketException ex)
            {
                OnLogMessage?.Invoke(this, $"Caught SocketException in ProcessLocalConnection with error code {ex.SocketErrorCode.ToString()}");
            }
            catch (Socks5Exception ex)
            {
                var portBuffer = new[] { buffer[2], buffer[3] };
                var ipBuffer   = new[] { buffer[4], buffer[5], buffer[6], buffer[7] };

                SendSocks4Reply(connection.LocalSocket, Protocol.Socks4.StatusRequestFailed, ipBuffer, portBuffer);
                connection.LocalSocket.Close();

                OnLogMessage?.Invoke(this, $"Caught Socks5Exception in ProcessLocalConnection with message {ex.Message}");
            }

            if (connection.LocalSocket.Connected)
            {
                OnLogMessage?.Invoke(this, "Closing LocalSocket");
                connection.LocalSocket.Close();
            }

            lock (_connections)
            {
                _connections.Remove(connection);
            }
        }
Esempio n. 9
0
        public void start()
        {
            foreach (string item in F_main.diclist)
            {
                ThreadPool.QueueUserWorkItem(_ =>
                {
                    if (F_main.isrun)
                    {
                        string openPort = "";
                        count          += 1;
                        F_main.FM.lbl_state.BeginInvoke(new Action(() =>
                        {
                            F_main.FM.lbl_state.Text = "状态:枚举模式," + "已发现" + F_main.FM.LV_result.Items.Count + "个域名,进度" + count + "/" + F_main.diclist.Length + "  当前" + item + "." + ReqDns.Domain;
                        }));

                        DnsResolver Dns = new DnsResolver(item + "." + ReqDns.Domain, ReqDns.DnsServer, ReqDns.TimeOut);
                        if (Dns.IsSuccess && F_main.blackIp.Contains(Dns.Record[0]) == false)
                        {
                            //避免接口查询的和枚举的重复
                            if (!F_main.DomainList.Contains(item + "." + ReqDns.Domain))
                            {
                                F_main.DomainList.Add(item + "." + ReqDns.Domain);

                                //加入到ListView
                                ListViewItem list = new ListViewItem(item + "." + ReqDns.Domain);

                                if (Dns.Record.Count > 1)
                                {
                                    list.SubItems.Add(string.Join(",", Dns.Record.ToArray()));
                                }
                                else
                                {
                                    list.SubItems.Add(string.Join(",", Dns.Record[0]));
                                }

                                if (F_main.isGetPorts)
                                {
                                    //扫描开放端口
                                    openPort = Tools.ScanPort(Dns.Record[0], ReqDns.Ports);
                                }

                                if (openPort != "")
                                {
                                    list.SubItems.Add(openPort);
                                }
                                else
                                {
                                    list.SubItems.Add("-");
                                }
                                list.SubItems.Add("暴力枚举");

                                F_main.FM.LV_result.BeginInvoke(new Action(() =>
                                {
                                    F_main.FM.LV_result.Items.Add(list);
                                }));
                            }
                        }
                    }
                    F_main.handler.Signal();
                });
            }
        }
Esempio n. 10
0
 public void Cleanup()
 {
     DnsResolver.Bind();
     NetTrace.Stop();
 }
Esempio n. 11
0
        public void DnsResolver_Multiple_Lookup_Bind()
        {
            // This test repeats the A_Multiple test, but this time
            // after binding the DnsResolver to 5 client side sockets.

            IPAddress dns = GetDns();

            string[] gtld = new string[] {
                "a.gtld-servers.net.",
                "b.gtld-servers.net.",
                "c.gtld-servers.net.",
                "d.gtld-servers.net.",
                "e.gtld-servers.net.",
                "f.gtld-servers.net.",
                "g.gtld-servers.net.",
                "h.gtld-servers.net.",
                "i.gtld-servers.net.",
                "j.gtld-servers.net.",
                "k.gtld-servers.net.",
                "l.gtld-servers.net.",
                "m.gtld-servers.net.",
            };

            DnsRequest[]   requests  = new DnsRequest[gtld.Length];
            DnsResponse[]  responses = new DnsResponse[gtld.Length];
            IAsyncResult[] rgAR      = new IAsyncResult[gtld.Length];
            IPEndPoint[]   clientEPs;

            clientEPs = new IPEndPoint[10];
            for (int i = 0; i < clientEPs.Length; i++)
            {
                clientEPs[i] = new IPEndPoint(IPAddress.Any, 0);
            }

            DnsResolver.Bind(clientEPs, 128 * 1024, 128 * 1024);

            try
            {
                for (int j = 0; j < 10; j++)
                {
                    // Repeat the test 10 times just for fun

                    for (int i = 0; i < gtld.Length; i++)
                    {
                        requests[i] = new DnsRequest(DnsFlag.RD, gtld[i], DnsQType.A);
                    }

                    for (int i = 0; i < gtld.Length; i++)
                    {
                        rgAR[i] = DnsResolver.BeginQuery(dns, requests[i], timeout, null, null);
                    }

                    for (int i = 0; i < gtld.Length; i++)
                    {
                        responses[i] = DnsResolver.EndQuery(rgAR[i]);
                    }

                    for (int i = 0; i < gtld.Length; i++)
                    {
                        Assert.AreEqual(requests[i].QID, responses[i].QID);
                        Assert.AreEqual(requests[i].QName, responses[i].QName);
                    }
                }
            }
            finally
            {
                DnsResolver.Bind();
            }
        }
Esempio n. 12
0
 /// <summary>
 /// Creates a new DnsResolver and tells it to start
 /// listening for traffic.
 /// </summary>
 /// <returns></returns>
 public async static Task CreateAndStartDnsResolver()
 {
     DnsResolver dnsResolver = new DnsResolver();
     await dnsResolver.Listen();
 }
Esempio n. 13
0
        /// <summary>
        /// Fetches SPF records, parses them, and
        /// evaluates them to determine whether a particular host is or is not
        /// permitted to send mail with a given identity.
        /// </summary>
        /// <param name="Term">Information about current query.</param>
        /// <param name="SpfExpressions">SPF Expressions that can be used, in case a domain lacks SPF records in the DNS.</param>
        /// <returns>Result of SPF evaluation, together with an optional explanation string,
        /// if one exists, and if the result indicates a failure.</returns>
        internal static async Task <KeyValuePair <SpfResult, string> > CheckHost(Term Term, SpfExpression[] SpfExpressions)
        {
            Exp Explanation = null;

            string[] TermStrings = null;
            string   s;

            try
            {
                string[] TXT = await DnsResolver.LookupText(Term.domain);

                foreach (string Row in TXT)
                {
                    s = Row.Trim();

                    if (s.Length > 1 && s[0] == '"' && s[s.Length - 1] == '"')
                    {
                        s = s.Substring(1, s.Length - 2);
                    }

                    if (!s.StartsWith("v=spf1"))
                    {
                        continue;
                    }

                    if (!(TermStrings is null))
                    {
                        return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, "Multiple SPF records found for " + Term.domain + "."));
                    }

                    TermStrings = s.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
                }
            }
            catch (Exception)
            {
                TermStrings = null;
            }

            if (TermStrings is null)
            {
                if (!(SpfExpressions is null))
                {
                    foreach (SpfExpression Expression in SpfExpressions)
                    {
                        if (Expression.IsApplicable(Term.domain))
                        {
                            if (Expression.Spf.StartsWith("v=spf1"))
                            {
                                TermStrings = Expression.Spf.Substring(6).Trim().Split(space, StringSplitOptions.RemoveEmptyEntries);
                                break;
                            }
                        }
                    }
                }

                if (TermStrings is null)
                {
                    return(new KeyValuePair <SpfResult, string>(SpfResult.None, "No SPF records found " + Term.domain + "."));
                }
            }

            // Syntax evaluation first, §4.6

            int c = TermStrings.Length;
            LinkedList <Mechanism> Mechanisms = new LinkedList <Mechanism>();
            Redirect Redirect = null;
            int      i;

            try
            {
                for (i = 0; i < c; i++)
                {
                    SpfQualifier Qualifier;

                    Term.Reset(TermStrings[i]);
                    Term.SkipWhiteSpace();

                    switch (Term.PeekNextChar())
                    {
                    case '+':
                        Term.pos++;
                        Qualifier = SpfQualifier.Pass;
                        break;

                    case '-':
                        Term.pos++;
                        Qualifier = SpfQualifier.Fail;
                        break;

                    case '~':
                        Term.pos++;
                        Qualifier = SpfQualifier.SoftFail;
                        break;

                    case '?':
                        Term.pos++;
                        Qualifier = SpfQualifier.Neutral;
                        break;

                    default:
                        Qualifier = SpfQualifier.Pass;
                        break;
                    }

                    switch (Term.NextLabel().ToLower())
                    {
                    case "all":
                        Mechanisms.AddLast(new All(Term, Qualifier));
                        break;

                    case "include":
                        Mechanisms.AddLast(new Include(Term, Qualifier, SpfExpressions));
                        break;

                    case "a":
                        Mechanisms.AddLast(new A(Term, Qualifier));
                        break;

                    case "mx":
                        Mechanisms.AddLast(new Mx(Term, Qualifier));
                        break;

                    case "ptr":
                        Mechanisms.AddLast(new Ptr(Term, Qualifier));
                        break;

                    case "ip4":
                        Mechanisms.AddLast(new Ip4(Term, Qualifier));
                        break;

                    case "ip6":
                        Mechanisms.AddLast(new Ip6(Term, Qualifier));
                        break;

                    case "exists":
                        Mechanisms.AddLast(new Exists(Term, Qualifier));
                        break;

                    case "redirect":
                        if (!(Redirect is null))
                        {
                            return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, "Multiple redirect modifiers foundin SPF record."));
                        }

                        Redirect = new Redirect(Term, Qualifier);
                        break;

                    case "exp":
                        if (!(Explanation is null))
                        {
                            return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, "Multiple exp modifiers foundin SPF record."));
                        }

                        Explanation = new Exp(Term, Qualifier);
                        break;

                    default:
                        throw new Exception("Syntax error.");
                    }
                }

                foreach (Mechanism Mechanism in Mechanisms)
                {
                    await Mechanism.Expand();

                    SpfResult Result = await Mechanism.Matches();

                    switch (Result)
                    {
                    case SpfResult.Pass:
                        switch (Mechanism.Qualifier)
                        {
                        case SpfQualifier.Pass: return(new KeyValuePair <SpfResult, string>(SpfResult.Pass, null));

                        case SpfQualifier.Fail: return(new KeyValuePair <SpfResult, string>(SpfResult.Fail, Explanation == null ? null : await Explanation.Evaluate()));

                        case SpfQualifier.Neutral: return(new KeyValuePair <SpfResult, string>(SpfResult.Neutral, null));

                        case SpfQualifier.SoftFail: return(new KeyValuePair <SpfResult, string>(SpfResult.SoftFail, Explanation == null ? null : await Explanation.Evaluate()));
                        }
                        break;

                    case SpfResult.TemporaryError:
                        return(new KeyValuePair <SpfResult, string>(SpfResult.TemporaryError, Explanation == null ? null : await Explanation.Evaluate()));

                    case SpfResult.None:
                    case SpfResult.PermanentError:
                        return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, Explanation == null ? null : await Explanation.Evaluate()));
                    }
                }

                if (!(Redirect is null))
                {
                    await Redirect.Expand();

                    string Bak = Term.domain;
                    Term.domain = Redirect.Domain;
                    try
                    {
                        KeyValuePair <SpfResult, string> Result = await SpfResolver.CheckHost(Term, SpfExpressions);

                        if (Result.Key == SpfResult.None)
                        {
                            return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, Explanation == null ? null : await Explanation.Evaluate()));
                        }
                        else if (Result.Key != SpfResult.Pass && Result.Key != SpfResult.Neutral &&
                                 string.IsNullOrEmpty(Result.Value))
                        {
                            return(new KeyValuePair <SpfResult, string>(Result.Key, Explanation == null ? null : await Explanation.Evaluate()));
                        }
                        else
                        {
                            return(Result);
                        }
                    }
                    finally
                    {
                        Term.domain = Bak;
                    }
                }
            }
            catch (Exception ex)
            {
                return(new KeyValuePair <SpfResult, string>(SpfResult.PermanentError, "Unable to evaluate SPF record: " + FirstRow(ex.Message)));
            }

            return(new KeyValuePair <SpfResult, string>(SpfResult.Neutral, null));
        }
Esempio n. 14
0
        /// <summary>
        /// Expands any macros in the domain specification.
        /// </summary>
        public override async Task Expand()
        {
            if (this.expanded)
            {
                return;
            }

            this.expanded = true;
            this.term.Reset(this.domain);

            StringBuilder sb = new StringBuilder();
            char          ch;

            while ((ch = this.term.PeekNextChar()) > ' ')
            {
                this.term.pos++;

                if (ch == '%')
                {
                    switch (ch = this.term.PeekNextChar())
                    {
                    case (char)0:
                        sb.Append('%');
                        break;

                    case '%':
                        this.term.pos++;
                        sb.Append('%');
                        break;

                    case '_':
                        this.term.pos++;
                        sb.Append(' ');
                        break;

                    case '-':
                        this.term.pos++;
                        sb.Append("%20");
                        break;

                    case '{':
                        this.term.pos++;

                        char MacroLetter = char.ToLower(this.term.NextChar());
                        int? Digit;
                        bool Reverse;

                        if (char.IsDigit(this.term.PeekNextChar()))
                        {
                            Digit = this.term.NextInteger();

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

                        if (char.ToLower(this.term.PeekNextChar()) == 'r')
                        {
                            this.term.pos++;
                            Reverse = true;
                        }
                        else
                        {
                            Reverse = false;
                        }

                        int Start = this.term.pos;
                        while ((ch = this.term.PeekNextChar()) == '.' || ch == '-' || ch == '+' ||
                               ch == ',' || ch == '/' || ch == '_' || ch == '=')
                        {
                            this.term.pos++;
                        }

                        string Delimiter = this.term.s.Substring(Start, this.term.pos - Start);

                        ch = this.term.NextChar();
                        if (ch != '}')
                        {
                            throw new Exception("Expected }");
                        }

                        string s;

                        switch (MacroLetter)
                        {
                        case 's':                                           // sender
                            s = this.term.sender;
                            break;

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

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

                        case 'd':                                           // domain
                            s = this.term.domain;
                            break;

                        case 'i':
                            switch (this.term.ip.AddressFamily)
                            {
                            case AddressFamily.InterNetwork:
                                s = this.term.ip.ToString();
                                break;

                            case AddressFamily.InterNetworkV6:
                                byte[] Bin = this.term.ip.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 (this.term.dnsLookupsLeft-- <= 0)
                                {
                                    throw new Exception("DNS Lookup maximum reached.");
                                }

                                string[] DomainNames = await DnsResolver.LookupDomainName(this.term.ip);

                                // First check if domain is found.

                                s = null;
                                foreach (string DomainName in DomainNames)
                                {
                                    if (string.Compare(DomainName, this.term.domain, true) == 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("." + this.term.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 (this.term.ip.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 = this.term.helloDomain;
                            break;

                        case 'c':
                            this.AssertExp();
                            s = this.term.ip.ToString();
                            break;

                        case 'r':
                            this.AssertExp();
                            s = this.term.hostDomain;
                            break;

                        case 't':
                            this.AssertExp();
                            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:
                        this.term.pos++;
                        sb.Append('%');
                        sb.Append(ch);
                        break;
                    }
                }
                else
                {
                    sb.Append(ch);
                }
            }

            this.domain = sb.ToString();
        }