query.h 14 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.
 */

Michal Vaner's avatar
Michal Vaner committed
17
#include <exceptions/exceptions.h>
18
#include <datasrc/zone.h>
Michal Vaner's avatar
Michal Vaner committed
19

20
21
22
23
24
namespace isc {
namespace dns {
class Message;
class Name;
class RRType;
25
class RRset;
26
27
28
}

namespace datasrc {
29
class DataSourceClient;
30
31
32
33
34
35
36
37
38
39
}

namespace auth {

/// The \c Query class represents a standard DNS query that encapsulates
/// processing logic to answer the query.
///
/// Many of the design details for this class are still in flux.
/// We'll revisit and update them as we add more functionality, for example:
/// - as a related point, we may have to pass the RR class of the query.
40
///   in the initial implementation the RR class is an attribute of
41
///   datasource and omitted.  It's not clear if this assumption holds with
42
43
44
///   generic data sources.  On the other hand, it will help keep
///   implementation simpler, and we might rather want to modify the design
///   of the data source on this point.
45
46
/// - return value of process().  rather than or in addition to setting the
///   Rcode, we might use it as a return value of \c process().
47
48
49
50
51
/// - we'll have to be able to specify whether DNSSEC is requested.
///   It's an open question whether it should be in the constructor or via a
///   separate attribute setter.
/// - likewise, we'll eventually need to do per zone access control, for which
///   we need querier's information such as its IP address.
52
/// - datasrc_client and response may better be parameters to process() instead
53
///   of the constructor.
54
55
56
57
58
59
60
61
62
63
///
/// <b>Note:</b> The class name is intentionally the same as the one used in
/// the datasrc library.  This is because the plan is to eventually merge
/// the two classes.  We could give it a different name such as "AuthQuery"
/// to avoid possible ambiguity, but it may sound redundant in that it's
/// obvious that this class is for authoritative queries.
/// Since the interfaces are very different for now and it's less
/// likely to misuse one of the classes instead of the other
/// accidentally, and since it's considered a temporary development state,
/// we keep this name at the moment.
64
class Query {
Jerry's avatar
Jerry committed
65
private:
66

67
    /// \brief Adds a SOA.
68
69
70
71
    ///
    /// Adds a SOA of the zone into the authority zone of response_.
    /// Can throw NoSOA.
    ///
72
    void addSOA(isc::datasrc::ZoneFinder& finder);
73

74
75
76
    /// \brief Adds the DS rrset for the given name, if available
    ///
    /// This is intended to be called when returning a delegation, and
77
78
    /// if DNSSEC data is requested. If the DS record is not found
    /// (signaled by find() returning NXRRSET), and the zone is signed
Jelte Jansen's avatar
Jelte Jansen committed
79
    /// with NSEC, an NSEC denial of existence proof is added.
80
    ///
Jelte Jansen's avatar
Jelte Jansen committed
81
82
83
    /// \exception BadDS raised if find() returns anything other than
    ///                  SUCCESS or NXRRSET when searching for the DS
    ///                  record.
84
    /// \param finder The ZoneFinder where the delegation was found
85
    /// \param ds_name The name of the delegation RRset
86
87
88
    void addDS(isc::datasrc::ZoneFinder& finder,
               const isc::dns::Name& ds_name);

Jelte Jansen's avatar
Jelte Jansen committed
89
    /// \brief Adds NSEC(3) denial proof for the given NXRRset result
90
    ///
Jelte Jansen's avatar
Jelte Jansen committed
91
92
    /// If available, NSEC or NSEC3 records are added to the authority
    /// section (depending on whether isNSECSigned() or isNSEC3Signed()
Jelte Jansen's avatar
Jelte Jansen committed
93
    /// returns true).
94
95
96
97
    ///
    /// \param finder The ZoneFinder that was used to search for the missing
    ///               data
    /// \param db_result The ZoneFinder::FindResult returned by find()
98
    void addNXRRsetProof(isc::datasrc::ZoneFinder& finder,
99
        const isc::datasrc::ZoneFinder::FindResult& db_result);
100

101
102
103
    /// Add NSEC RRs that prove an NXDOMAIN result.
    ///
    /// This corresponds to Section 3.1.3.2 of RFC 4035.
104
    void addNXDOMAINProof(isc::datasrc::ZoneFinder& finder,
105
                          isc::dns::ConstRRsetPtr nsec);
106

107
    /// Add NSEC or NSEC3 RRs that prove a wildcard answer is the best one.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
108
    ///
109
110
    /// This corresponds to Section 3.1.3.3 of RFC 4035 and Section 7.2.6
    /// of RFC5155.
111
112
113
    void addWildcardProof(
        isc::datasrc::ZoneFinder& finder,
        const isc::datasrc::ZoneFinder::FindResult& dbResult);
114

115
    /// \brief Adds one NSEC RR proved no matched QNAME,one NSEC RR proved no
116
117
118
    /// matched <QNAME,QTYPE> through wildcard extension.
    ///
    /// Add NSEC RRs that prove an WILDCARD_NXRRSET result.
119
    /// This corresponds to Section 3.1.3.4 of RFC 4035.
120
121
122
123
    /// \param finder The ZoneFinder through which the authority data for the
    /// query is to be found.
    /// \param nsec The RRset (NSEC RR) which proved that there is no matched 
    /// <QNAME,QTTYPE>.
124
    void addWildcardNXRRSETProof(isc::datasrc::ZoneFinder& finder,
125
                                 isc::dns::ConstRRsetPtr nsec);
126

127
    /// \brief Look up additional data (i.e., address records for the names
128
    /// included in NS or MX records) and add them to the additional section.
129
130
131
132
    ///
    /// Note: Any additional data which has already been provided in the
    /// answer section (i.e., if the original query happend to be for the
    /// address of the DNS server), it should be omitted from the additional.
Jerry's avatar
Jerry committed
133
134
135
136
    ///
    /// This method may throw a exception because its underlying methods may
    /// throw exceptions.
    ///
137
138
    /// \param zone The ZoneFinder through which the additional data for the
    /// query is to be found.
Jerry's avatar
Jerry committed
139
140
    /// \param rrset The RRset (i.e., NS or MX rrset) which require additional
    /// processing.
141
    void addAdditional(isc::datasrc::ZoneFinder& zone,
142
                       const isc::dns::AbstractRRset& rrset);
Jerry's avatar
Jerry committed
143

144
    /// \brief Find address records for a specified name.
Jerry's avatar
Jerry committed
145
146
147
    ///
    /// Search the specified zone for AAAA/A RRs of each of the NS/MX RDATA
    /// (domain name), and insert the found ones into the additional section
148
149
    /// if address records are available. By default the search will stop
    /// once it encounters a zone cut.
Jerry's avatar
Jerry committed
150
151
152
153
154
155
    ///
    /// Note: we need to perform the search in the "GLUE OK" mode for NS RDATA,
    /// which means that we should include A/AAAA RRs under a zone cut.
    /// The glue records must exactly match the name in the NS RDATA, without
    /// CNAME or wildcard processing.
    ///
156
157
    /// \param zone The \c ZoneFinder through which the address records is to
    /// be found.
Jerry's avatar
Jerry committed
158
    /// \param qname The name in rrset RDATA.
159
    /// \param options The search options.
160
161
162
163
    void addAdditionalAddrs(isc::datasrc::ZoneFinder& zone,
                            const isc::dns::Name& qname,
                            const isc::datasrc::ZoneFinder::FindOptions options
                            = isc::datasrc::ZoneFinder::FIND_DEFAULT);
Jerry's avatar
Jerry committed
164

165
    /// \brief Look up a zone's NS RRset and their address records for an
166
    /// authoritative answer, and add them to the additional section.
167
    ///
168
    /// On returning an authoritative answer, insert a zone's NS into the
169
170
171
172
173
174
175
176
177
178
179
180
    /// authority section and AAAA/A RRs of each of the NS RDATA into the
    /// additional section.
    ///
    /// <b>Notes to developer:</b>
    ///
    /// We should omit address records which has already been provided in the
    /// answer section from the additional.
    ///
    /// For now, in order to optimize the additional section processing, we
    /// include AAAA/A RRs under a zone cut in additional section. (BIND 9
    /// excludes under-cut RRs; NSD include them.)
    ///
181
182
183
    /// \param finder The \c ZoneFinder through which the NS and additional
    /// data for the query are to be found.
    void addAuthAdditional(isc::datasrc::ZoneFinder& finder);
184

185
186
    /// \brief Process a DS query possible at the child side of zone cut.
    ///
187
    /// This private method is a subroutine of process(), and is called if
188
189
190
191
192
193
194
195
196
197
198
199
    /// there's a possibility that this server has authority for the child
    /// side of the DS's owner name (and it's detected that the server at
    /// least doesn't have authority at the parent side).  This method
    /// first checks if it has authority for the child, and if does,
    /// just build a "no data" response with SOA for the zone origin
    /// (possibly with a proof for the no data) as specified in Section
    /// 2.2.1.1 of RFC3658.
    ///
    /// It returns true if this server has authority of the child; otherwise
    /// it returns false.  In the former case, the caller is expected to
    /// terminate the query processing, because it should have been completed
    /// within this method.
200
201
    bool processDSAtChild();

202
203
204
205
206
public:
    /// Constructor from query parameters.
    ///
    /// This constructor never throws an exception.
    ///
207
    /// \param datasrc_client The datasource wherein the answer to the query is
208
209
210
211
    /// to be found.
    /// \param qname The query name
    /// \param qtype The RR type of the query
    /// \param response The response message to store the answer to the query.
212
213
    /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
    ///     possible.
214
    Query(const isc::datasrc::DataSourceClient& datasrc_client,
215
          const isc::dns::Name& qname, const isc::dns::RRType& qtype,
216
          isc::dns::Message& response, bool dnssec = false) :
217
        datasrc_client_(datasrc_client), qname_(qname), qtype_(qtype),
218
219
220
        response_(response), dnssec_(dnssec),
        dnssec_opt_(dnssec ?  isc::datasrc::ZoneFinder::FIND_DNSSEC :
                    isc::datasrc::ZoneFinder::FIND_DEFAULT)
221
    {}
222
223
224
225
226

    /// Process the query.
    ///
    /// This method first identifies the zone that best matches the query
    /// name (and in some cases RR type when the search is dependent on the
227
228
    /// type) and then searches the zone for an entry that best matches the
    /// query name.
229
230
231
232
    /// It then updates the response message accordingly; for example, a
    /// successful search would result in adding a corresponding RRset to
    /// the answer section of the response.
    ///
233
    /// If no matching zone is found in the datasource, the RCODE of
234
    /// SERVFAIL will be set in the response.
235
236
237
238
239
240
241
242
243
244
    /// <b>Note:</b> this is different from the error code that BIND 9 returns
    /// by default when it's configured as an authoritative-only server (and
    /// from the behavior of the BIND 10 datasrc library, which was implemented
    /// to be compatible with BIND 9).
    /// The difference comes from the fact that BIND 9 returns REFUSED as a
    /// result of access control check on the use of its cache.
    /// Since BIND 10's authoritative server doesn't have the notion of cache
    /// by design, it doesn't make sense to return REFUSED.  On the other hand,
    /// providing compatible behavior may have its own benefit, so this point
    /// should be revisited later.
245
    ///
Michal Vaner's avatar
Michal Vaner committed
246
247
248
    /// This might throw BadZone or any of its specific subclasses, but that
    /// shouldn't happen in real-life (as BadZone means wrong data, it should
    /// have been rejected upon loading).
249
    void process();
250

Michal Vaner's avatar
Michal Vaner committed
251
252
253
254
255
256
    /// \short Bad zone data encountered.
    ///
    /// This is thrown when process encounteres misconfigured zone in a way
    /// it can't continue. This throws, not sets the Rcode, because such
    /// misconfigured zone should not be present in the data source and
    /// should have been rejected sooner.
Michal Vaner's avatar
Michal Vaner committed
257
258
259
    struct BadZone : public isc::Exception {
        BadZone(const char* file, size_t line, const char* what) :
            Exception(file, line, what)
Michal Vaner's avatar
Michal Vaner committed
260
        {}
Michal Vaner's avatar
Michal Vaner committed
261
262
    };

Michal Vaner's avatar
Michal Vaner committed
263
264
265
266
    /// \short Zone is missing its SOA record.
    ///
    /// We tried to add a SOA into the authoritative section, but the zone
    /// does not contain one.
Michal Vaner's avatar
Michal Vaner committed
267
268
269
    struct NoSOA : public BadZone {
        NoSOA(const char* file, size_t line, const char* what) :
            BadZone(file, line, what)
Michal Vaner's avatar
Michal Vaner committed
270
        {}
Michal Vaner's avatar
Michal Vaner committed
271
272
    };

Jerry's avatar
Jerry committed
273
274
275
276
277
278
279
280
281
282
    /// \short Zone is missing its apex NS records.
    ///
    /// We tried to add apex NS records into the authority section, but the
    /// zone does not contain any.
    struct NoApexNS: public BadZone {
        NoApexNS(const char* file, size_t line, const char* what) :
            BadZone(file, line, what)
        {}
    };

283
    /// An invalid result is given when a valid NSEC is expected
284
    ///
285
    /// This can only happen when the underlying data source implementation or
286
287
    /// the zone is broken.  By throwing an exception we treat such cases
    /// as SERVFAIL.
288
289
290
291
292
293
    struct BadNSEC : public BadZone {
        BadNSEC(const char* file, size_t line, const char* what) :
            BadZone(file, line, what)
        {}
    };

294
295
296
297
298
299
300
301
302
303
304
    /// An invalid result is given when a valid NSEC3 is expected
    ///
    /// This can only happen when the underlying data source implementation or
    /// the zone is broken.  By throwing an exception we treat such cases
    /// as SERVFAIL.
    struct BadNSEC3 : public BadZone {
        BadNSEC3(const char* file, size_t line, const char* what) :
            BadZone(file, line, what)
        {}
    };

305
306
307
308
309
310
311
312
313
314
315
316
    /// An invalid result is given when a valid DS records (or NXRRSET) is
    /// expected
    ///
    /// This can only happen when the underlying data source implementation
    /// or the zone is broken. A DS query for a known delegation point should
    /// either result in SUCCESS (if available) or NXRRSET
    struct BadDS : public BadZone {
        BadDS(const char* file, size_t line, const char* what) :
            BadZone(file, line, what)
        {}
    };

317
private:
318
    const isc::datasrc::DataSourceClient& datasrc_client_;
319
320
321
    const isc::dns::Name& qname_;
    const isc::dns::RRType& qtype_;
    isc::dns::Message& response_;
322
    const bool dnssec_;
323
    const isc::datasrc::ZoneFinder::FindOptions dnssec_opt_;
324
325
326
327
328
329
330
331
};

}
}

// Local Variables:
// mode: c++
// End: