Esempio n. 1
0
        public void TestQuery()
        {
            var zone         = new DNSZone(start_of_authority, relays);
            var www_a_record = new DNSRecord(
                new Domain("www.example.com"),
                AddressClass.INTERNET,
                42,
                new AResource(IPv4Address.Parse("192.168.0.1")));

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

            // Something that matches the class and record type, but not the domain
            var www2_a_record = new DNSRecord(
                new Domain("www2.example.com"),
                AddressClass.INTERNET,
                42,
                new AResource(IPv4Address.Parse("192.168.0.3")));

            // Something that matches the domain and class, but not the record type
            var www_cname_record = new DNSRecord(
                new Domain("www.example.com"),
                AddressClass.INTERNET,
                42,
                new CNAMEResource(new Domain("www2.example.com")));

            zone.Add(www_a_record);
            zone.Add(www_a_record_2);
            zone.Add(www2_a_record);
            zone.Add(www_cname_record);

            var query_result = zone.Query(
                new Domain("www.example.com"),
                ResourceRecordType.HOST_ADDRESS,
                AddressClass.INTERNET);

            var expected = new List <DNSRecord>();

            expected.Add(www_a_record);
            expected.Add(www_a_record_2);
            Assert.That(query_result, Is.EquivalentTo(expected));
        }
Esempio n. 2
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);
                }
            }
        }