Exemple #1
0
        private static DNSQuestion ReadQuestion(byte[] data, DataReader reader)
        {
            DNSQuestion q = new DNSQuestion();

            q.QName  = ReadString(data, reader);
            q.QType  = (DNSType)reader.ReadUInt16(false);
            q.QClass = (DNSClass)reader.ReadUInt16(false);

            return(q);
        }
Exemple #2
0
        /// <summary>
        /// Create from an array
        /// </summary>
        /// <param name="data">The data</param>
        /// <returns>The parsed DNS packet</returns>
        public static DNSPacket FromArray(byte[] data)
        {
            DataReader reader = new DataReader(new MemoryStream(data));

            DNSPacket ret = new DNSPacket();

            ret.Id = reader.ReadUInt16(false);

            ushort flags = reader.ReadUInt16(false);

            ret.Query              = GetBooleanFlag(flags, 0);
            ret.Opcode             = (DNSOpcode)GetFlagValue(flags, 1);
            ret.AuthoritiveAnswer  = GetBooleanFlag(flags, 5);
            ret.Truncation         = GetBooleanFlag(flags, 6);
            ret.RecursionDesired   = GetBooleanFlag(flags, 7);
            ret.RecursionAvailable = GetBooleanFlag(flags, 8);
            ret.ResponseCode       = (DNSRCode)GetFlagValue(flags, 12);

            ushort qdcount = reader.ReadUInt16(false);
            ushort ancount = reader.ReadUInt16(false);
            ushort nscount = reader.ReadUInt16(false);
            ushort arcount = reader.ReadUInt16(false);

            if (qdcount > 0)
            {
                DNSQuestion[] questions = new DNSQuestion[qdcount];

                for (int i = 0; i < qdcount; i++)
                {
                    questions[i] = ReadQuestion(data, reader);
                }

                ret.Questions = questions;
            }

            if (ancount > 0)
            {
                ret.Answers = ReadResourceRecords(data, reader, ancount);
            }

            if (nscount > 0)
            {
                ret.NameServers = ReadResourceRecords(data, reader, nscount);
            }

            if (arcount > 0)
            {
                ret.Additional = ReadResourceRecords(data, reader, arcount);
            }

            return(ret);
        }
Exemple #3
0
        public void TestStubResolverAcceptsSeveralAliasesForAAAARecords()
        {
            // Make sure that chains of aliases are supported
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.HOST_6ADDRESS,
                AddressClass.INTERNET);

            var expected_alias_answer_1 = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new CNAMEResource(new Domain("www.example.com")));

            var expected_alias_answer_2 = new DNSRecord(
                new Domain("www.example.com"), AddressClass.INTERNET, 42,
                new CNAMEResource(new Domain("web1.www.example.com")));

            var expected_addr_answer = new DNSRecord(
                new Domain("web1.www.example.com"), AddressClass.INTERNET, 42,
                new AAAAResource(IPv6Address.Parse("2001:cafe:beef::")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question },
                new DNSRecord[] { expected_alias_answer_1, expected_alias_answer_2, expected_addr_answer },
                new DNSRecord[0], new DNSRecord[0]);


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.HOST_6ADDRESS,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[] { expected_addr_answer };
            expected_result.aliases             = new DNSRecord[] { expected_alias_answer_1, expected_alias_answer_2 };
            expected_result.referrals           = new DNSRecord[0];
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #4
0
        public void TestStubResolverAcceptsSOARecords()
        {
            // The same as the previous test, but this makes sure that less common
            // record types are still recognized as answers for the appropriate queries
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.START_OF_AUTHORITY,
                AddressClass.INTERNET);

            var expected_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new SOAResource(
                    new Domain("ns.example.com"),
                    new Domain("hostmaster.example.com"),
                    0,
                    360,
                    360,
                    360,
                    360));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[] { expected_answer }, new DNSRecord[0], new DNSRecord[0]);


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.START_OF_AUTHORITY,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[] { expected_answer };
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[0];
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #5
0
        public void TestStubResolverReturnsRedirectionsWithAAAAResourceGlue()
        {
            // Make sure that any redirections are returned, even if there aren't any actual
            // results, along with their glue if provided
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.HOST_ADDRESS,
                AddressClass.INTERNET);

            var expected_ns_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new NSResource(new Domain("ns.example.com")));

            var expected_glue_answer = new DNSRecord(
                new Domain("ns.example.com"), AddressClass.INTERNET, 42,
                new AAAAResource(IPv6Address.Parse("2001:cafe:beef::")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[0], new DNSRecord[] { expected_ns_answer },
                new DNSRecord[] { expected_glue_answer });


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.HOST_ADDRESS,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[0];
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[] { expected_ns_answer };
            expected_result.referral_additional = new DNSRecord[] { expected_glue_answer };

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #6
0
        public void TestStubResolverSequenceOfRelays()
        {
            // Make sure that the resolver ignores failing resolvers, as long as at least one succeeds
            var good_relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);
            var bad_relay  = new IPEndPoint(IPAddress.Parse("192.168.0.2"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.HOST_ADDRESS,
                AddressClass.INTERNET);

            var expected_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new AResource(IPv4Address.Parse("192.168.0.1")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[] { expected_answer }, new DNSRecord[0], new DNSRecord[0]);

            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                if (target.Equals(bad_relay))
                {
                    throw new SocketException();
                }

                Assert.That(target, Is.EqualTo(good_relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.HOST_ADDRESS,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { bad_relay, good_relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[] { expected_answer };
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[0];
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #7
0
        public void TestStubResolverRejectsIrrelevantGlue()
        {
            // Make sure that any redirections are returned, but rejects any bad glue
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.HOST_ADDRESS,
                AddressClass.INTERNET);

            var expected_ns_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new NSResource(new Domain("ns.example.com")));

            var unexpected_glue_answer = new DNSRecord(
                new Domain("ns2.example.com"), AddressClass.INTERNET, 42,
                new AResource(IPv4Address.Parse("192.168.0.2")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[0], new DNSRecord[] { expected_ns_answer },
                new DNSRecord[] { unexpected_glue_answer });


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.HOST_ADDRESS,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[0];
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[] { expected_ns_answer };
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #8
0
        public void TestStubResolverAcceptsARecords()
        {
            // The idea behind this test is to make sure that direct answers to the question are accpted
            // (no CNAMEs, no referrals, etc.). A records are the most common query, so they are a good
            // starting point.
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.HOST_ADDRESS,
                AddressClass.INTERNET);

            var expected_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new AResource(IPv4Address.Parse("192.168.0.1")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[] { expected_answer }, new DNSRecord[0], new DNSRecord[0]);


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.HOST_ADDRESS,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[] { expected_answer };
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[0];
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #9
0
        public void TestStubResolverRecordsCNAMEAnswers()
        {
            // This ensures that any request for a CNAME to a paritcular domain ends up in the answers
            // list (and only the answers list) if we're asking for CNAMEs
            var relay = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 53);

            var expected_question = new DNSQuestion(
                new Domain("example.com"),
                ResourceRecordType.CANONICAL_NAME,
                AddressClass.INTERNET);

            var expected_answer = new DNSRecord(
                new Domain("example.com"), AddressClass.INTERNET, 42,
                new CNAMEResource(new Domain("www.example.com")));

            var expected_packet = new DNSPacket(
                42, false, QueryType.STANDARD_QUERY, false, false, true, true, ResponseType.NO_ERROR,
                new DNSQuestion[] { expected_question }, new DNSRecord[] { expected_answer }, new DNSRecord[0], new DNSRecord[0]);


            Func <EndPoint, DNSQuestion, bool, DNSPacket> gives_direct_answers = (target, question, is_recursive) =>
            {
                Assert.That(target, Is.EqualTo(relay));
                Assert.That(question, Is.EqualTo(expected_question));
                return(expected_packet);
            };

            var resolver = new StubResolver(new NoopCache(), gives_direct_answers);
            var result   = resolver.Resolve(new Domain("example.com"),
                                            ResourceRecordType.CANONICAL_NAME,
                                            AddressClass.INTERNET,
                                            new EndPoint[] { relay });

            var expected_result = new ResolverResult();

            expected_result.answers             = new DNSRecord[] { expected_answer };
            expected_result.aliases             = new DNSRecord[0];
            expected_result.referrals           = new DNSRecord[0];
            expected_result.referral_additional = new DNSRecord[0];

            Assert.That(result, Is.EqualTo(expected_result));
        }
Exemple #10
0
        /**
         * Sends a DNS query to the given server, and waits for a response.
         * Possibly times out with a SocketException if the response takes
         * too long.
         */
        public static DNSPacket SendQuery(EndPoint server, DNSQuestion question, bool recursive)
        {
            var rng       = new Random();
            var packet_id = (UInt16)rng.Next(0, (1 << 16) - 1);

            var to_send = new DNSPacket(
                packet_id, true, QueryType.STANDARD_QUERY,
                false, false, recursive, false, ResponseType.NO_ERROR,
                new DNSQuestion[] { question }, new DNSRecord[0], new DNSRecord[0], new DNSRecord[0]);

            var send_bytes = to_send.ToBytes();

            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                socket.ReceiveTimeout = 5 * 1000;
                socket.Bind(new IPEndPoint(IPAddress.Any, 0));

                logger.Trace("Sending packet {0} to {1}", packet_id, server);
                socket.SendTo(send_bytes, server);

                DNSPacket recv_packet = null;
                while (recv_packet == null)
                {
                    logger.Trace("Preparing to receive");
                    var      recv_bytes      = new byte[512];
                    EndPoint remote_endpoint = new IPEndPoint(IPAddress.Any, 0);
                    socket.ReceiveFrom(recv_bytes, ref remote_endpoint);

                    recv_packet = DNSPacket.FromBytes(recv_bytes);
                    if (recv_packet.Id != packet_id)
                    {
                        logger.Trace("Trashing bad packet");
                        recv_packet = null;
                    }
                }

                logger.Trace("Got response {0}", recv_packet);
                return(recv_packet);
            }
        }
Exemple #11
0
        /**
         * Tries to resolve a question against the cache, and possibly several
         * servers. Throws a ResolverException if both methods fail.
         */
        public DNSPacket QueryServers(Domain domain, ResourceRecordType record_kind, AddressClass addr_class, EndPoint[] servers)
        {
            var question = new DNSQuestion(domain, record_kind, addr_class);

            foreach (var server in servers)
            {
                try
                {
                    var response = send_query(server, question, true);
                    if (response.ResponseType == ResponseType.NO_ERROR)
                    {
                        logger.Trace("Accepting response {0} from {1}", response, server);
                        return(response);
                    }
                }
                catch (SocketException error)
                {
                    logger.Trace("Recoverable error: " + error);
                }
            }

            throw new ResolverException(question.Name, "Cannot resolve query " + question);
        }
Exemple #12
0
        /**
         * Resolves the given query, returning a QueryResult that contains
         * everything we found while doing the resolution.
         */
        public QueryResult Execute(Domain domain, ResourceRecordType rtype, AddressClass addr_class, bool recursive)
        {
            logger.Trace("Executing query on {0} for type {1} with recursion {2}",
                         domain, rtype, recursive);

            if (zone.IsAuthorityFor(domain))
            {
                var records = zone.Query(domain, rtype, addr_class).ToList();

                // It is possible that there is a CNAME that we should be aware of - in that case, check
                // it and see if we can find one.
                if (records.Count == 0)
                {
                    var cname_records = zone.Query(domain, ResourceRecordType.CANONICAL_NAME, addr_class).ToArray();

                    if (cname_records.Length != 0)
                    {
                        logger.Trace("Authoritative for CNAMEs, re-executing");

                        // In this case, try again with the alias
                        var alias         = ((CNAMEResource)cname_records[0].Resource).Alias;
                        var alias_results = Execute(alias, rtype, addr_class, recursive);

                        // The RFC directs us to return any intermediate CNAMEs, which we do
                        alias_results.Answers.InsertRange(0, cname_records);

                        return(alias_results);
                    }
                }

                var result = new QueryResult();
                result.IsAuthority = true;
                result.FoundAnswer = true;
                result.Answers     = new List <DNSRecord>();
                result.Authority   = new List <DNSRecord>();
                result.Additional  = new List <DNSRecord>();

                result.Answers.AddRange(records);
                result.Authority.Add(zone.StartOfAuthority);
                return(result);
            }
            else
            {
                var owning_subzone = zone.FindSubZone(domain);
                if (owning_subzone != null)
                {
                    logger.Trace("Subzone {0} is authoritative", owning_subzone);

                    // We can punt on the computation to our subzone delgation
                    var subzone_nameservers             = zone.Query(owning_subzone, ResourceRecordType.NAME_SERVER, addr_class);
                    var subzone_nameserver_addr_records = subzone_nameservers
                                                          .SelectMany(ns => zone.Query(ns.Name, ResourceRecordType.HOST_ADDRESS, addr_class));
                    var subzone_nameserver_addrs = subzone_nameserver_addr_records.Select(
                        record => new IPEndPoint(((AResource)record.Resource).Address, 53)
                        ).ToArray();

                    IEnumerable <DNSRecord> response = null;
                    try
                    {
                        var info = resolver.Resolve(domain, ResourceRecordType.HOST_ADDRESS, addr_class, subzone_nameserver_addrs);
                        response = info.aliases.Concat(info.answers).ToList();
                    }
                    catch (ResolverException err)
                    {
                        logger.Trace("Could not resolve from subzone: {0}", err);
                        response = new DNSRecord[] { };
                    }

                    var result = new QueryResult();
                    result.IsAuthority = false;
                    result.FoundAnswer = response.Count() > 0;
                    result.Answers     = new List <DNSRecord>(response);
                    result.Authority   = new List <DNSRecord>(subzone_nameservers);
                    result.Additional  = new List <DNSRecord>(subzone_nameserver_addr_records);
                    return(result);
                }
                else if (recursive)
                {
                    // We'll have to go outside our zone and use the general-purpose resolver
                    ResolverResult response;
                    logger.Trace("No authoritative server is local, executing recursive resolver");

                    try
                    {
                        response = resolver.Resolve(domain, rtype, addr_class, zone.Relays);
                    }
                    catch (ResolverException err)
                    {
                        logger.Trace("Could not resolve: {0}", err);

                        response                     = new ResolverResult();
                        response.answers             = new List <DNSRecord>();
                        response.aliases             = new List <DNSRecord>();
                        response.referrals           = new List <DNSRecord>();
                        response.referral_additional = new List <DNSRecord>();
                    }

                    var result = new QueryResult();
                    result.IsAuthority = false;
                    result.FoundAnswer = response.answers.Count() > 0;
                    result.Answers     = response.aliases.Concat(response.answers).ToList();
                    result.Authority   = response.referrals.ToList();
                    result.Additional  = response.referral_additional.ToList();
                    return(result);
                }
                else
                {
                    var cached_responses = cache.Query(domain, AddressClass.INTERNET, rtype);
                    if (cached_responses.Count > 0)
                    {
                        logger.Trace("Non-recursive search found {0} cached results", cached_responses.Count);

                        var cached_result = new QueryResult();
                        cached_result.IsAuthority = false;
                        cached_result.FoundAnswer = true;
                        cached_result.Answers     = cached_responses.ToList();
                        cached_result.Additional  = new List <DNSRecord>();
                        cached_result.Authority   = new List <DNSRecord>();
                        return(cached_result);
                    }

                    // If we can't recurse, and our cache knows nothing, then punt onto the forwarder
                    logger.Trace("Executing limited-case non-recursive resolver");

                    var question = new DNSQuestion(domain, rtype, AddressClass.INTERNET);

                    foreach (var forwarder in zone.Relays)
                    {
                        try
                        {
                            var forward_result = ResolverUtils.SendQuery(forwarder, question, false);

                            // If the server doesn't like our request, then pass it to something else
                            if (forward_result.ResponseType != ResponseType.NO_ERROR &&
                                forward_result.ResponseType != ResponseType.NAME_ERROR)
                            {
                                continue;
                            }

                            var forward_return = new QueryResult();
                            forward_return.FoundAnswer = forward_result.ResponseType == ResponseType.NO_ERROR;
                            forward_return.IsAuthority = false;
                            forward_return.Answers     = forward_result.Answers.ToList();
                            forward_return.Additional  = forward_result.AdditionalRecords.ToList();
                            forward_return.Authority   = forward_result.AuthoritativeAnswers.ToList();
                            return(forward_return);
                        }
                        catch (SocketException err)
                        {
                            // We can safely punt onto the next forwarder if one bails
                            logger.Trace("Could not request from {0}: {1}", forwarder, err);
                        }
                    }

                    // We can't do anything else here, so there is no such host, as far as we knot
                    var result = new QueryResult();
                    result.FoundAnswer = false;
                    result.IsAuthority = false;
                    result.Answers     = new List <DNSRecord>();
                    result.Authority   = new List <DNSRecord>();
                    result.Additional  = new List <DNSRecord>();
                    return(result);
                }
            }
        }
Exemple #13
0
            public bool AskDNS(string domain, string email)
            {
                var transactionID = (Int16)(new Random().Next(maxValue: Int16.MaxValue));

                var header = new DNSHeader
                {
                    transactionID           = transactionID,
                    flags                   = 0x0100, // Just a standard query
                    questionResourceCount   = 1,      // We have one question
                    answerResourceCount     = 0,
                    authorityResourceCount  = 0,
                    additionalResourceCount = 0
                };

                var question = new DNSQuestion(domain,
                                               DNSQuestion.Types.MailExchangeRecord);   // We want to know about mail server

                var    sizeDNSQuery = header.SizeOf() + question.SizeOf();
                var    arrDNSQuery  = new byte[sizeDNSQuery];
                IntPtr ptrHeader    = Marshal.AllocHGlobal(header.SizeOf());

                Marshal.StructureToPtr(header, ptrHeader, true);
                Marshal.Copy(ptrHeader, arrDNSQuery, 0, header.SizeOf());
                Marshal.FreeHGlobal(ptrHeader);

                // Copy char data, no need to worry about endianess for char
                question.name.CopyTo(arrDNSQuery, header.SizeOf());

                var arrQuestionType      = BitConverter.GetBytes(Endianess.toBigEndian(question.type));
                var arrQuestionClassType = BitConverter.GetBytes(Endianess.toBigEndian(question.classType));

                arrQuestionType.CopyTo(arrDNSQuery, header.SizeOf() + question.name.Length * sizeof(byte));
                arrQuestionClassType.CopyTo(arrDNSQuery, header.SizeOf() + question.name.Length * sizeof(byte) + arrQuestionType.Length);

                // Send datagram
                _dNSClient.Send(arrDNSQuery, arrDNSQuery.Length * sizeof(byte));

                // Get response
                do
                {
                    var result = _dNSClient.ReceiveAsync().Result;

                    // Make sure it is from correct domain
                    if (result.RemoteEndPoint.Address.Equals(_dNSServer))
                    {
                        // Make sure packet has valid size header
                        if (result.Buffer.Length > header.SizeOf())
                        {
                            // Convert to DNSHeader
                            ptrHeader = Marshal.AllocHGlobal(header.SizeOf());
                            Marshal.Copy(result.Buffer, 0, ptrHeader, header.SizeOf());
                            header = (DNSHeader)Marshal.PtrToStructure(ptrHeader, header.GetType());
                            Marshal.FreeHGlobal(ptrHeader);

                            // Check that this is the correct transaction packet response
                            if (header.transactionID == transactionID)
                            {
                                // Check that flags has no error and there is atleast one answer
                                if (((header.flags & 0xf) != 0) || header.answerResourceCount == 0)
                                {
                                    return(false);
                                }

                                // List of mail servers and their preferences
                                List <Tuple <int, string> > listMailServerAndPrefs = new List <Tuple <int, string> >();

                                // Determine the start index of Answers structure
                                int indexStartOfAnswer = arrDNSQuery.Length;

                                for (int i = 0; i < header.answerResourceCount; ++i)
                                {
                                    if ((result.Buffer[indexStartOfAnswer] & 0xC0) == 0)
                                    {
                                        throw new NotImplementedException("DNS answer name must be an offset");
                                    }

                                    // Convert from byte stream to answer structure
                                    IntPtr ptrAnswer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DNSResource)));
                                    Marshal.Copy(result.Buffer, indexStartOfAnswer, ptrAnswer, Marshal.SizeOf(typeof(DNSResource)));
                                    var answer = (DNSResource)Marshal.PtrToStructure(ptrAnswer, typeof(DNSResource));
                                    Marshal.FreeHGlobal(ptrAnswer);

                                    // Increment index ahead
                                    indexStartOfAnswer += answer.SizeOf();
                                    if (indexStartOfAnswer > result.Buffer.Length)
                                    {
                                        break;
                                    }

                                    // Read preference no, smaller number is more preferred server
                                    if (answer.dataLength < 2)
                                    {
                                        continue;
                                    }

                                    Int16 preferenceMailExchangeServer = BitConverter.ToInt16(result.Buffer, indexStartOfAnswer);
                                    if (Endianess.MachineArchIsLittleEndian)
                                    {
                                        preferenceMailExchangeServer = Endianess.toLittleEndian(preferenceMailExchangeServer);
                                    }
                                    indexStartOfAnswer += Marshal.SizeOf(preferenceMailExchangeServer);

                                    // Read server name
                                    int sizeServerName = answer.dataLength - Marshal.SizeOf(preferenceMailExchangeServer);
                                    if (sizeServerName < 2)
                                    {
                                        continue;
                                    }

                                    if (indexStartOfAnswer + sizeServerName > result.Buffer.Length)
                                    {
                                        break;
                                    }

                                    string serverName = string.Empty;
                                    int    j          = indexStartOfAnswer;
                                    while (j < indexStartOfAnswer + sizeServerName - 1)
                                    {
                                        if ((result.Buffer[j] & 0xC0) != 0)
                                        {
                                            // It's an offset
                                            var offset = BitConverter.ToInt16(result.Buffer, j);
                                            if (Endianess.MachineArchIsLittleEndian)
                                            {
                                                offset = Endianess.toLittleEndian(offset);
                                            }
                                            offset &= 0x3F; // Remove two most significant bits
                                            j      += Marshal.SizeOf(offset);

                                            // Transverse position from offset until null
                                            do
                                            {
                                                serverName += Encoding.ASCII.GetString(result.Buffer, offset + 1, result.Buffer[offset]) + '.';
                                                offset     += (Int16)(result.Buffer[offset] + 1);
                                            } while (result.Buffer[offset] != 0);
                                        }
                                        else
                                        {
                                            // It's just size
                                            serverName += System.Text.Encoding.ASCII.GetString(result.Buffer, j + 1, result.Buffer[j]) + '.';
                                            j          += result.Buffer[j] + 1;
                                        }
                                    }

                                    indexStartOfAnswer += answer.dataLength - Marshal.SizeOf(preferenceMailExchangeServer);

                                    if (string.IsNullOrEmpty(serverName) && serverName.Length > 2)
                                    {
                                        continue;
                                    }

                                    serverName = serverName.Substring(0, serverName.Length - 1);    // Remove terminating dot

                                    listMailServerAndPrefs.Add(new Tuple <int, string>((int)preferenceMailExchangeServer, serverName));
                                }

                                // Sort by preference
                                listMailServerAndPrefs = listMailServerAndPrefs.OrderBy(x => x.Item1).ToList();

                                // Connect with SMTP
                                _sMTPClient = new TcpClient();
                                _sMTPClient.ConnectAsync(listMailServerAndPrefs.First().Item2, _sMTPPort).Wait();
                                if (!_sMTPClient.Connected)
                                {
                                    throw new WebException("SMTP server refused connection");
                                }

                                var arrSMTPResponse  = new byte[256];
                                var sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse);
                                var connectResponse  = Encoding.ASCII.GetString(arrSMTPResponse);
                                if (!connectResponse.StartsWith("220"))
                                {
                                    throw new WebException("SMTP server refused to connect");
                                }

                                _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("HELO " + HelloServer + "\r\n"));
                                sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse);
                                var heloResponse = Encoding.ASCII.GetString(arrSMTPResponse);
                                if (!heloResponse.StartsWith("250"))
                                {
                                    throw new WebException("SMTP server refused to handshake");
                                }

                                _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("MAIL FROM:<" + QueryEmail + ">\r\n"));
                                sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse);
                                var mailfromResponse = Encoding.ASCII.GetString(arrSMTPResponse);
                                if (!mailfromResponse.StartsWith("250"))
                                {
                                    throw new WebException("SMTP server refused to accept mail from");
                                }

                                _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("RCPT TO:<" + email + ">\r\n"));
                                sizeSMTPResponse = _sMTPClient.Client.Receive(arrSMTPResponse);
                                var rcpttoResponse = Encoding.ASCII.GetString(arrSMTPResponse);

                                _sMTPClient.Client.Send(Encoding.ASCII.GetBytes("QUIT"));   // Bye

                                _sMTPClient.Close();

                                if (!rcpttoResponse.StartsWith("250"))
                                {
                                    return(false);
                                }

                                break;
                            }
                        }
                    }
                } while (true);

                return(true);
            }
Exemple #14
0
        private static DNSQuestion ReadQuestion(byte[] data, DataReader reader)
        {
            DNSQuestion q = new DNSQuestion();

            q.QName = ReadString(data, reader);
            q.QType = (DNSType)reader.ReadUInt16(false);
            q.QClass = (DNSClass)reader.ReadUInt16(false);

            return q;
        }
Exemple #15
0
        /// <summary>
        /// Create from an array
        /// </summary>
        /// <param name="data">The data</param>
        /// <returns>The parsed DNS packet</returns>
        public static DNSPacket FromArray(byte[] data)
        {
            DataReader reader = new DataReader(new MemoryStream(data));

            DNSPacket ret = new DNSPacket();

            ret.Id = reader.ReadUInt16(false);

            ushort flags = reader.ReadUInt16(false);

            ret.Query = GetBooleanFlag(flags, 0);
            ret.Opcode = (DNSOpcode)GetFlagValue(flags, 1);
            ret.AuthoritiveAnswer = GetBooleanFlag(flags, 5);
            ret.Truncation = GetBooleanFlag(flags, 6);
            ret.RecursionDesired = GetBooleanFlag(flags, 7);
            ret.RecursionAvailable = GetBooleanFlag(flags, 8);
            ret.ResponseCode = (DNSRCode)GetFlagValue(flags, 12);

            ushort qdcount = reader.ReadUInt16(false);
            ushort ancount = reader.ReadUInt16(false);
            ushort nscount = reader.ReadUInt16(false);
            ushort arcount = reader.ReadUInt16(false);

            if (qdcount > 0)
            {
                DNSQuestion[] questions = new DNSQuestion[qdcount];

                for (int i = 0; i < qdcount; i++)
                {
                    questions[i] = ReadQuestion(data, reader);
                }

                ret.Questions = questions;
            }

            if (ancount > 0)
            {
                ret.Answers = ReadResourceRecords(data, reader, ancount);
            }

            if (nscount > 0)
            {
                ret.NameServers = ReadResourceRecords(data, reader, nscount);
            }

            if (arcount > 0)
            {
                ret.Additional = ReadResourceRecords(data, reader, arcount);
            }

            return ret;
        }