query.cc 6.76 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <dns/message.h>
#include <dns/rcode.h>
17
#include <dns/rdataclass.h>
18

19
#include <datasrc/memory_datasrc.h>
20
21
22
23
24

#include <auth/query.h>

using namespace isc::dns;
using namespace isc::datasrc;
25
using namespace isc::dns::rdata;
26
27
28

namespace isc {
namespace auth {
29

30
void
Jerry's avatar
Jerry committed
31
Query::getAdditional(const Zone& zone, const RRset& rrset) const {
32
33
34
35
36
37
    if (rrset.getType() == RRType::NS()) {
        // Need to perform the search in the "GLUE OK" mode.
        RdataIteratorPtr rdata_iterator = rrset.getRdataIterator();
        for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
             const Rdata& rdata(rdata_iterator->getCurrent());
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
38
             findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
39
40
41
42
43
        }
    }
}

void
44
45
Query::findAddrs(const Zone& zone, const Name& qname,
                 const Zone::FindOptions options) const
46
{
47
48
49
50
51
52
    // Out of zone name
    NameComparisonResult result = zone.getOrigin().compare(qname);
    if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
        (result.getRelation() != NameComparisonResult::EQUAL))
        return;

53
54
55
56
57
58
59
60
    // Omit additional data which has already been provided in the answer
    // section from the additional.
    //
    // All the address rrset with the owner name of qname have been inserted
    // into ANSWER section.
    if (qname_ == qname && qtype_ == RRType::ANY())
        return;

61
    // Find A rrset
62
63
64
65
66
67
    if (qname_ != qname || qtype_ != RRType::A()) {
        Zone::FindResult a_result = zone.find(qname, RRType::A(), options);
        if (a_result.code == Zone::SUCCESS) {
            response_.addRRset(Message::SECTION_ADDITIONAL,
                    boost::const_pointer_cast<RRset>(a_result.rrset));
        }
68
    }
69

70
    // Find AAAA rrset
71
    if (qname_ != qname || qtype_ != RRType::AAAA()) {
Jerry's avatar
Jerry committed
72
73
        Zone::FindResult aaaa_result =
            zone.find(qname, RRType::AAAA(), options);
74
75
76
77
        if (aaaa_result.code == Zone::SUCCESS) {
            response_.addRRset(Message::SECTION_ADDITIONAL,
                    boost::const_pointer_cast<RRset>(aaaa_result.rrset));
        }
78
79
80
    }
}

Michal Vaner's avatar
Michal Vaner committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
void
Query::putSOA(const Zone& zone) const {
    Zone::FindResult soa_result(zone.find(zone.getOrigin(),
        RRType::SOA()));
    if (soa_result.code != Zone::SUCCESS) {
        isc_throw(NoSOA, "There's no SOA record in zone " <<
            zone.getOrigin().toText());
    } else {
        /*
         * FIXME:
         * The const-cast is wrong, but the Message interface seems
         * to insist.
         */
        response_.addRRset(Message::SECTION_AUTHORITY,
            boost::const_pointer_cast<RRset>(soa_result.rrset));
    }
}

99
100
101
102
103
void
Query::getAuthAdditional(const Zone& zone) const {
    // Fill in authority and addtional sections.
    Zone::FindResult ns_result = zone.find(zone.getOrigin(), RRType::NS());
    // zone origin name should have NS records
Jerry's avatar
Jerry committed
104
105
106
107
108
    if (ns_result.code != Zone::SUCCESS) {
        isc_throw(NoApexNS, "There's no apex NS records in zone " <<
                zone.getOrigin().toText());
    } else {
        response_.addRRset(Message::SECTION_AUTHORITY,
109
110
            boost::const_pointer_cast<RRset>(ns_result.rrset));
        // Handle additional for authority section
Jerry's avatar
Jerry committed
111
112
        getAdditional(zone, *ns_result.rrset);
    }
113
114
}

115
116
void
Query::process() const {
Jerry's avatar
Jerry committed
117
118
    bool keep_doing = true;
    response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
119
    const MemoryDataSrc::FindResult result =
120
        memory_datasrc_.findZone(qname_);
121

122
123
124
125
126
    // If we have no matching authoritative zone for the query name, return
    // REFUSED.  In short, this is to be compatible with BIND 9, but the
    // background discussion is not that simple.  See the relevant topic
    // at the BIND 10 developers's ML:
    // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
127
128
    if (result.code != result::SUCCESS &&
        result.code != result::PARTIALMATCH) {
129
        response_.setRcode(Rcode::REFUSED());
130
131
132
        return;
    }

Jerry's avatar
Jerry committed
133
134
    // Found a zone which is the nearest ancestor to QNAME, set the AA bit
    response_.setHeaderFlag(Message::HEADERFLAG_AA);
135
136
    while (keep_doing) {
        keep_doing = false;
137
        Zone::FindResult db_result = result.zone->find(qname_, qtype_);
138
139
        switch (db_result.code) {
            case Zone::SUCCESS:
140
141
                response_.setRcode(Rcode::NOERROR());
                response_.addRRset(Message::SECTION_ANSWER,
142
                    boost::const_pointer_cast<RRset>(db_result.rrset));
143
144
145
146
147
148
149
150
151
152
153
                // Handle additional for answer section
                getAdditional(*result.zone, *db_result.rrset);
                // If apex NS records haven't been provided in the answer
                // section, insert apex NS records into the authority section
                // and AAAA/A RRS of each of the NS RDATA into the additional
                // section.
                if (qname_ != result.zone->getOrigin() ||
                    (qtype_ != RRType::NS() && qtype_ != RRType::ANY()))
                {
                    getAuthAdditional(*result.zone);
                }
154
155
                break;
            case Zone::DELEGATION:
Jerry's avatar
Jerry committed
156
                response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
157
158
                response_.setRcode(Rcode::NOERROR());
                response_.addRRset(Message::SECTION_AUTHORITY,
159
                    boost::const_pointer_cast<RRset>(db_result.rrset));
160
                getAdditional(*result.zone, *db_result.rrset);
161
162
                break;
            case Zone::NXDOMAIN:
Michal Vaner's avatar
Michal Vaner committed
163
                // Just empty answer with SOA in authority section
164
                response_.setRcode(Rcode::NXDOMAIN());
Michal Vaner's avatar
Michal Vaner committed
165
                putSOA(*result.zone);
166
167
                break;
            case Zone::NXRRSET:
Michal Vaner's avatar
Michal Vaner committed
168
                // Just empty answer with SOA in authority section
169
                response_.setRcode(Rcode::NOERROR());
Michal Vaner's avatar
Michal Vaner committed
170
                putSOA(*result.zone);
171
172
173
                break;
            case Zone::CNAME:
            case Zone::DNAME:
Jerry's avatar
Jerry committed
174
                // TODO : replace qname, continue lookup
175
176
177
                break;
        }
    }
178
179
180
}
}
}