Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __DATABASE_DATASRC_H
16 : : #define __DATABASE_DATASRC_H
17 : :
18 : : #include <string>
19 : :
20 : : #include <boost/scoped_ptr.hpp>
21 : : #include <boost/tuple/tuple.hpp>
22 : :
23 : : #include <dns/rrclass.h>
24 : : #include <dns/rrset.h>
25 : : #include <dns/rrtype.h>
26 : :
27 : : #include <datasrc/data_source.h>
28 : : #include <datasrc/client.h>
29 : : #include <datasrc/zone.h>
30 : : #include <datasrc/logger.h>
31 : :
32 : : #include <dns/name.h>
33 : : #include <exceptions/exceptions.h>
34 : :
35 : : #include <map>
36 : : #include <set>
37 : :
38 : : namespace isc {
39 : : namespace datasrc {
40 : :
41 : : /// \brief Abstraction of lowlevel database with DNS data
42 : : ///
43 : : /// This class is defines interface to databases. Each supported database
44 : : /// will provide methods for accessing the data stored there in a generic
45 : : /// manner. The methods are meant to be low-level, without much or any knowledge
46 : : /// about DNS and should be possible to translate directly to queries.
47 : : ///
48 : : /// On the other hand, how the communication with database is done and in what
49 : : /// schema (in case of relational/SQL database) is up to the concrete classes.
50 : : ///
51 : : /// This class is non-copyable, as copying connections to database makes little
52 : : /// sense and will not be needed.
53 : : ///
54 : : /// \todo Is it true this does not need to be copied? For example the zone
55 : : /// iterator might need it's own copy. But a virtual clone() method might
56 : : /// be better for that than copy constructor.
57 : : ///
58 : : /// \note The same application may create multiple connections to the same
59 : : /// database, having multiple instances of this class. If the database
60 : : /// allows having multiple open queries at one connection, the connection
61 : : /// class may share it.
62 : 603 : class DatabaseAccessor : boost::noncopyable {
63 : : public:
64 : : /// \brief Data columns for by IteratorContext::getNext()
65 : : ///
66 : : /// When implementing getNext(), the columns array should be filled with
67 : : /// the values as described in this enumeration, in this order, i.e.
68 : : /// - TYPE_COLUMN should be the first element (index 0) of the array,
69 : : /// - TTL_COLUMN should be the second element (index 1),
70 : : /// - etc.
71 : : enum RecordColumns {
72 : : TYPE_COLUMN = 0, ///< The RRType of the record (A/NS/TXT etc.)
73 : : TTL_COLUMN = 1, ///< The TTL of the record (a
74 : : SIGTYPE_COLUMN = 2, ///< For RRSIG records, this contains the RRTYPEs
75 : : ///< the RRSIG cover. In the current implementation,
76 : : ///< this field is ignored.
77 : : RDATA_COLUMN = 3, ///< Full text representation of the record's RDATA
78 : : NAME_COLUMN = 4, ///< The domain name of this RR
79 : : COLUMN_COUNT = 5 ///< The total number of columns, MUST be value of
80 : : ///< the largest other element in this enum plus 1.
81 : : };
82 : :
83 : : /// \brief Definitions of the fields to be passed to addRecordToZone()
84 : : ///
85 : : /// Each derived implementation of addRecordToZone() should expect
86 : : /// the "columns" array to be filled with the values as described in this
87 : : /// enumeration, in this order.
88 : : enum AddRecordColumns {
89 : : ADD_NAME = 0, ///< The owner name of the record (a domain name)
90 : : ADD_REV_NAME = 1, ///< Reversed name of NAME (used for DNSSEC)
91 : : ADD_TTL = 2, ///< The TTL of the record (in numeric form)
92 : : ADD_TYPE = 3, ///< The RRType of the record (A/NS/TXT etc.)
93 : : ADD_SIGTYPE = 4, ///< RRSIGs only: RRTYPEs the RRSIG covers.
94 : : ADD_RDATA = 5, ///< Full text representation of the record's RDATA
95 : : ADD_COLUMN_COUNT = 6 ///< Number of columns
96 : : };
97 : :
98 : : /// \brief Definitions of the fields to be passed to addNSEC3RecordToZone()
99 : : ///
100 : : /// Each derived implementation of addNSEC3RecordToZone() should expect
101 : : /// the "columns" array to be filled with the values as described in this
102 : : /// enumeration, in this order.
103 : : ///
104 : : /// Note that there is no "reversed name" column. Since the conceptual
105 : : /// separate namespace for NSEC3 is very simplified and essentially only
106 : : /// consists of a single-label names, there is no need for using reversed
107 : : /// names to identify the "previous hash".
108 : : enum AddNSEC3RecordColumns {
109 : : ADD_NSEC3_HASH = 0, ///< The hash (1st) label of the owner name,
110 : : ///< excluding the dot character
111 : : ADD_NSEC3_TTL = 1, ///< The TTL of the record (in numeric form)
112 : : ADD_NSEC3_TYPE = 2, ///< The RRType of the record (either NSEC3 or
113 : : ///< RRSIG for NSEC3)
114 : : ADD_NSEC3_RDATA = 3, ///< Full text representation of the record's
115 : : ///< RDATA
116 : : ADD_NSEC3_COLUMN_COUNT = 4 ///< Number of columns
117 : : };
118 : :
119 : : /// \brief Definitions of the fields to be passed to deleteRecordInZone()
120 : : /// and deleteNSEC3RecordInZone()
121 : : ///
122 : : /// Each derived implementation of deleteRecordInZone() should expect
123 : : /// the "params" array to be filled with the values as described in this
124 : : /// enumeration, in this order.
125 : : enum DeleteRecordParams {
126 : : DEL_NAME = 0, ///< The owner name of the record (a domain name)
127 : : ///< or the hash label for deleteNSEC3RecordInZone()
128 : : DEL_TYPE = 1, ///< The RRType of the record (A/NS/TXT etc.)
129 : : DEL_RDATA = 2, ///< Full text representation of the record's RDATA
130 : : DEL_PARAM_COUNT = 3 ///< Number of parameters
131 : : };
132 : :
133 : : /// \brief Operation mode when adding a record diff.
134 : : ///
135 : : /// This is used as the "operation" parameter value of addRecordDiff().
136 : : enum DiffOperation {
137 : : DIFF_ADD = 0, ///< This diff is for adding an RR
138 : : DIFF_DELETE = 1 ///< This diff is for deleting an RR
139 : : };
140 : :
141 : : /// \brief Definitions of the fields to be passed to addRecordDiff().
142 : : ///
143 : : /// Each derived implementation of addRecordDiff() should expect
144 : : /// the "params" array to be filled with the values as described in this
145 : : /// enumeration, in this order.
146 : : enum DiffRecordParams {
147 : : DIFF_NAME = 0, ///< Owner name of the record (a domain name)
148 : : DIFF_TYPE = 1, ///< The RRType of the record (A/NS/TXT etc.)
149 : : DIFF_TTL = 2, ///< The TTL of the record (in numeric form)
150 : : DIFF_RDATA = 3, ///< Full text representation of record's RDATA
151 : : DIFF_PARAM_COUNT = 4 ///< Number of parameters
152 : : };
153 : :
154 : : /// \brief Destructor
155 : : ///
156 : : /// It is empty, but needs a virtual one, since we will use the derived
157 : : /// classes in polymorphic way.
158 : 603 : virtual ~DatabaseAccessor() { }
159 : :
160 : : /// \brief Retrieve a zone identifier
161 : : ///
162 : : /// This method looks up a zone for the given name in the database. It
163 : : /// should match only exact zone name (eg. name is equal to the zone's
164 : : /// apex), as the DatabaseClient will loop trough the labels itself and
165 : : /// find the most suitable zone.
166 : : ///
167 : : /// It is not specified if and what implementation of this method may throw,
168 : : /// so code should expect anything.
169 : : ///
170 : : /// \param name The (fully qualified) domain name of the zone's apex to be
171 : : /// looked up.
172 : : /// \return The first part of the result indicates if a matching zone
173 : : /// was found. In case it was, the second part is internal zone ID.
174 : : /// This one will be passed to methods finding data in the zone.
175 : : /// It is not required to keep them, in which case whatever might
176 : : /// be returned - the ID is only passed back to the database as
177 : : /// an opaque handle.
178 : : virtual std::pair<bool, int> getZone(const std::string& name) const = 0;
179 : :
180 : : /// \brief This holds the internal context of ZoneIterator for databases
181 : : ///
182 : : /// While the ZoneIterator implementation from DatabaseClient does all the
183 : : /// translation from strings to DNS classes and validation, this class
184 : : /// holds the pointer to where the database is at reading the data.
185 : : ///
186 : : /// It can either hold shared pointer to the connection which created it
187 : : /// and have some kind of statement inside (in case single database
188 : : /// connection can handle multiple concurrent SQL statements) or it can
189 : : /// create a new connection (or, if it is more convenient, the connection
190 : : /// itself can inherit both from DatabaseConnection and IteratorContext
191 : : /// and just clone itself).
192 : 2797 : class IteratorContext : public boost::noncopyable {
193 : : public:
194 : : /// \brief Destructor
195 : : ///
196 : : /// Virtual destructor, so any descendand class is destroyed correctly.
197 : 2797 : virtual ~IteratorContext() { }
198 : :
199 : : /// \brief Function to provide next resource record
200 : : ///
201 : : /// This function should provide data about the next resource record
202 : : /// from the data that is searched. The data is not converted yet.
203 : : ///
204 : : /// Depending on how the iterator was constructed, there is a difference
205 : : /// in behaviour; for a 'full zone iterator', created with
206 : : /// getAllRecords(), all COLUMN_COUNT elements of the array are
207 : : /// overwritten.
208 : : /// For a 'name iterator', created with getRecords(), the column
209 : : /// NAME_COLUMN is untouched, since what would be added here is by
210 : : /// definition already known to the caller (it already passes it as
211 : : /// an argument to getRecords()).
212 : : ///
213 : : /// Once this function returns false, any subsequent call to it should
214 : : /// result in false. The implementation of a derived class must ensure
215 : : /// it doesn't cause any disruption due to that such as a crash or
216 : : /// exception.
217 : : ///
218 : : /// \note The order of RRs is not strictly set, but the RRs for single
219 : : /// RRset must not be interleaved with any other RRs (eg. RRsets must be
220 : : /// "together").
221 : : ///
222 : : /// \param columns The data will be returned through here. The order
223 : : /// is specified by the RecordColumns enum, and the size must be
224 : : /// COLUMN_COUNT
225 : : /// \todo Do we consider databases where it is stored in binary blob
226 : : /// format?
227 : : /// \throw DataSourceError if there's database-related error. If the
228 : : /// exception (or any other in case of derived class) is thrown,
229 : : /// the iterator can't be safely used any more.
230 : : /// \return true if a record was found, and the columns array was
231 : : /// updated. false if there was no more data, in which case
232 : : /// the columns array is untouched.
233 : : virtual bool getNext(std::string (&columns)[COLUMN_COUNT]) = 0;
234 : : };
235 : :
236 : : typedef boost::shared_ptr<IteratorContext> IteratorContextPtr;
237 : :
238 : : /// \brief Creates an iterator context for a specific name.
239 : : ///
240 : : /// Returns an IteratorContextPtr that contains all records of the
241 : : /// given name from the given zone.
242 : : ///
243 : : /// The implementation of the iterator that is returned may leave the
244 : : /// NAME_COLUMN column of the array passed to getNext() untouched, as that
245 : : /// data is already known (it is the same as the name argument here)
246 : : ///
247 : : /// \exception any Since any implementation can be used, the caller should
248 : : /// expect any exception to be thrown.
249 : : ///
250 : : /// \param name The name to search for. This should be a FQDN.
251 : : /// \param id The ID of the zone, returned from getZone().
252 : : /// \param subdomains If set to true, match subdomains of name instead
253 : : /// of name itself. It is used to find empty domains and match
254 : : /// wildcards.
255 : : /// \return Newly created iterator context. Must not be NULL.
256 : : virtual IteratorContextPtr getRecords(const std::string& name,
257 : : int id,
258 : : bool subdomains = false) const = 0;
259 : :
260 : : /// \brief Creates an iterator context for the records of NSEC3 namespace
261 : : /// for the given hash
262 : : ///
263 : : /// Returns an Iteratorcontextptr that contains all the records of the given
264 : : /// hash in the NSEC3 namespace of the given zone.
265 : : ///
266 : : /// The implementation of the iterator that is returned may leave the
267 : : /// NAME_COLUMN column of the array passed to getNext() untouched,
268 : : /// as that name is easy to construct on the caller side (both the
269 : : /// hash and the name of the zone is known). The SIGTYPE_COLUMN can
270 : : /// be omitted as well, as it would be always empty for NSEC3 RRs or
271 : : /// contained "NSEC3" in case of RRSIG RRs.
272 : : ///
273 : : /// The iterator will contain both the NSEC3 records and the corresponding
274 : : /// RRSIGs, in arbitrary order.
275 : : ///
276 : : /// The iterator might be empty (containing no RRs) in case the zone is not
277 : : /// signed by NSEC3.
278 : : ///
279 : : /// \note In case there are multiple NSEC3 chains and they collide
280 : : /// (unlikely, but it can happen), this can return multiple NSEC3
281 : : /// records.
282 : : /// \exception any Since any implementaion can be used, the caller should
283 : : /// expect any exception to be thrown.
284 : : /// \exception isc::NotImplemented in case the database does not support
285 : : /// NSEC3
286 : : ///
287 : : /// \param hash The hash part of the NSEC3 name (eg. for a name of NSEC3
288 : : /// RKBUCQT8T78GV6QBCGBHCHC019LG73SJ.example.com., we the hash would be
289 : : /// RKBUCQT8T78GV6QBCGBHCHC019LG73SJ).
290 : : /// \param id The id of te zone, as returned from getZone().
291 : : /// \return Newly created iterator context. Must not be NULL.
292 : : virtual IteratorContextPtr getNSEC3Records(const std::string& hash,
293 : : int id) const = 0;
294 : :
295 : : /// \brief Creates an iterator context for the whole zone.
296 : : ///
297 : : /// Returns an IteratorContextPtr that contains all records of the
298 : : /// zone with the given zone id.
299 : : ///
300 : : /// Each call to getNext() on the returned iterator should copy all
301 : : /// column fields of the array that is passed, as defined in the
302 : : /// RecordColumns enum.
303 : : ///
304 : : /// \exception any Since any implementation can be used, the caller should
305 : : /// expect any exception to be thrown.
306 : : ///
307 : : /// \param id The ID of the zone, returned from getZone().
308 : : /// \return Newly created iterator context. Must not be NULL.
309 : : virtual IteratorContextPtr getAllRecords(int id) const = 0;
310 : :
311 : : /// \brief Creates an iterator context for a set of differences.
312 : : ///
313 : : /// Returns an IteratorContextPtr that contains all difference records for
314 : : /// the given zone between two versions of a zone.
315 : : ///
316 : : /// The difference records are the set of records that would appear in an
317 : : /// IXFR serving a request for the difference between two versions of a
318 : : /// zone. The records are returned in the same order as they would be in
319 : : /// the IXFR. This means that if the the difference between versions of a
320 : : /// zone with SOA serial numbers of "start" and "end" is required, and the
321 : : /// zone contains the differences between serial number "start" to serial
322 : : /// number "intermediate" and from serial number "intermediate" to serial
323 : : /// number "end", the returned records will be (in order):
324 : : ///
325 : : /// \li SOA for serial "start"
326 : : /// \li Records removed from the zone between versions "start" and
327 : : /// "intermediate" of the zone. The order of these is not guaranteed.
328 : : /// \li SOA for serial "intermediate"
329 : : /// \li Records added to the zone between versions "start" and
330 : : /// "intermediate" of the zone. The order of these is not guaranteed.
331 : : /// \li SOA for serial "intermediate"
332 : : /// \li Records removed from the zone between versions "intermediate" and
333 : : /// "end" of the zone. The order of these is not guaranteed.
334 : : /// \li SOA for serial "end"
335 : : /// \li Records added to the zone between versions "intermediate" and "end"
336 : : /// of the zone. The order of these is not guaranteed.
337 : : ///
338 : : /// Note that there is no requirement that "start" be less than "end".
339 : : /// Owing to serial number arithmetic, it is entirely possible that a later
340 : : /// version of a zone will have a smaller SOA serial number than an earlier
341 : : /// version.
342 : : ///
343 : : /// Each call to getNext() on the returned iterator should copy all column
344 : : /// fields of the array that is passed, as defined in the RecordColumns
345 : : /// enum.
346 : : ///
347 : : /// \exception any Since any implementation can be used, the caller should
348 : : /// expect any exception to be thrown.
349 : : ///
350 : : /// \param id The ID of the zone, returned from getZone().
351 : : /// \param start The SOA serial number of the version of the zone from
352 : : /// which the difference sequence should start.
353 : : /// \param end The SOA serial number of the version of the zone at which
354 : : /// the difference sequence should end.
355 : : ///
356 : : /// \return Newly created iterator context. Must not be NULL.
357 : : virtual IteratorContextPtr
358 : : getDiffs(int id, uint32_t start, uint32_t end) const = 0;
359 : :
360 : : /// \brief Start a transaction for updating a zone.
361 : : ///
362 : : /// Each derived class version of this method starts a database
363 : : /// transaction to make updates to the given name of zone (whose class was
364 : : /// specified at the construction of the class).
365 : : ///
366 : : /// If \c replace is true, any existing records of the zone will be
367 : : /// deleted on successful completion of updates (after
368 : : /// \c commitUpdateZone()); if it's false, the existing records will be
369 : : /// intact unless explicitly deleted by \c deleteRecordInZone().
370 : : ///
371 : : /// A single \c DatabaseAccessor instance can perform at most one
372 : : /// transaction; a duplicate call to this method before
373 : : /// \c commitUpdateZone() or \c rollbackUpdateZone(), or a call to this
374 : : /// method within another transaction started by \c startTransaction()
375 : : /// will result in a \c DataSourceError exception.
376 : : /// If multiple update attempts need to be performed concurrently (and
377 : : /// if the underlying database allows such operation), separate
378 : : /// \c DatabaseAccessor instance must be created.
379 : : ///
380 : : /// \note The underlying database may not allow concurrent updates to
381 : : /// the same database instance even if different "connections" (or
382 : : /// something similar specific to the database implementation) are used
383 : : /// for different sets of updates. For example, it doesn't seem to be
384 : : /// possible for SQLite3 unless different databases are used. MySQL
385 : : /// allows concurrent updates to different tables of the same database,
386 : : /// but a specific operation may block others. As such, this interface
387 : : /// doesn't require derived classes to allow concurrent updates with
388 : : /// multiple \c DatabaseAccessor instances; however, the implementation
389 : : /// is encouraged to do the best for making it more likely to succeed
390 : : /// as long as the underlying database system allows concurrent updates.
391 : : ///
392 : : /// This method returns a pair of \c bool and \c int. Its first element
393 : : /// indicates whether the given name of zone is found. If it's false,
394 : : /// the transaction isn't considered to be started; a subsequent call to
395 : : /// this method with an existing zone name should succeed. Likewise,
396 : : /// if a call to this method results in an exception, the transaction
397 : : /// isn't considered to be started. Note also that if the zone is not
398 : : /// found this method doesn't try to create a new one in the database.
399 : : /// It must have been created by some other means beforehand.
400 : : ///
401 : : /// The second element is the internal zone ID used for subsequent
402 : : /// updates. Depending on implementation details of the actual derived
403 : : /// class method, it may be different from the one returned by
404 : : /// \c getZone(); for example, a specific implementation may use a
405 : : /// completely new zone ID when \c replace is true.
406 : : ///
407 : : /// \exception DataSourceError Duplicate call to this method, call to
408 : : /// this method within another transaction, or some internal database
409 : : /// related error.
410 : : ///
411 : : /// \param zone_name A string representation of the zone name to be updated
412 : : /// \param replace Whether to replace the entire zone (see above)
413 : : ///
414 : : /// \return A pair of bool and int, indicating whether the specified zone
415 : : /// exists and (if so) the zone ID to be used for the update, respectively.
416 : : virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
417 : : bool replace) = 0;
418 : :
419 : : /// \brief Add a single record to the zone to be updated.
420 : : ///
421 : : /// This method provides a simple interface to insert a new record
422 : : /// (a database "row") to the zone in the update context started by
423 : : /// \c startUpdateZone(). The zone to which the record to be added
424 : : /// is the one specified at the time of the \c startUpdateZone() call.
425 : : ///
426 : : /// A successful call to \c startUpdateZone() must have preceded to
427 : : /// this call; otherwise a \c DataSourceError exception will be thrown.
428 : : ///
429 : : /// The row is defined as a vector of strings that has exactly
430 : : /// ADD_COLUMN_COUNT number of elements. See AddRecordColumns for
431 : : /// the semantics of each element.
432 : : ///
433 : : /// Derived class methods are not required to check whether the given
434 : : /// values in \c columns are valid in terms of the expected semantics;
435 : : /// in general, it's the caller's responsibility.
436 : : /// For example, TTLs would normally be expected to be a textual
437 : : /// representation of decimal numbers, but this interface doesn't require
438 : : /// the implementation to perform this level of validation. It may check
439 : : /// the values, however, and in that case if it detects an error it
440 : : /// should throw a \c DataSourceError exception.
441 : : ///
442 : : /// Likewise, derived class methods are not required to detect any
443 : : /// duplicate record that is already in the zone.
444 : : ///
445 : : /// \note The underlying database schema may not have a trivial mapping
446 : : /// from this style of definition of rows to actual database records.
447 : : /// It's the implementation's responsibility to implement the mapping
448 : : /// in the actual derived method.
449 : : ///
450 : : /// \exception DataSourceError Invalid call without starting a transaction,
451 : : /// or other internal database error.
452 : : ///
453 : : /// \param columns An array of strings that defines a record to be added
454 : : /// to the zone.
455 : : virtual void addRecordToZone(
456 : : const std::string (&columns)[ADD_COLUMN_COUNT]) = 0;
457 : :
458 : : /// \brief Add a single NSEC3-related record to the zone to be updated.
459 : : ///
460 : : /// This method is similar to \c addRecordToZone(), but is expected to
461 : : /// be only used for NSEC3 RRs or RRSIG RRs that cover NSEC3. In terms
462 : : /// of the DNS protocol, these types of RRs reside in a separate space
463 : : /// of the zone. While this interface does not mandate a specific way
464 : : /// of implementing the separate namespaces in the underlying database,
465 : : /// it would be more convenient for the underlying implementation if the
466 : : /// interfaces are separated; for example, the implementation does not
467 : : /// have to examine the given data to identify the appropriate namespace.
468 : : ///
469 : : /// An implementation may choose to skip providing this interface if the
470 : : /// zones managed by that data source are known to not support NSEC3.
471 : : /// In that case the implementation should throw the
472 : : /// \c isc::NotImplemented exception.
473 : : ///
474 : : /// Note that the \c ADD_NSEC3_HASH column of \c columns is expected to
475 : : /// store only the hash label, not the entire owner name. This is similar
476 : : /// to the \c hash parameter of \c getNSEC3Records().
477 : : ///
478 : : /// The RRs to be added using this method are expected to be limited to
479 : : /// NSEC3 or RRSIG RRs that cover NSEC3, but it's generally assumed to
480 : : /// be the caller's responsibility to ensure that; the implementation
481 : : /// is not required to check that condition. The result of adding
482 : : /// unexpected type of RRs (and the result of subsequent lookups) is
483 : : /// undefined.
484 : : ///
485 : : /// Other general notes for \c addRecordToZone() also apply to this
486 : : /// method.
487 : : ///
488 : : /// \exception DataSourceError Invalid call without starting a transaction,
489 : : /// or other internal database error.
490 : : /// \exception isc::NotImplemented in case the database does not support
491 : : /// NSEC3
492 : : ///
493 : : /// \param columns An array of strings that defines a record to be added
494 : : /// to the NSEC3 namespace of the zone.
495 : : virtual void addNSEC3RecordToZone(
496 : : const std::string (&columns)[ADD_NSEC3_COLUMN_COUNT]) = 0;
497 : :
498 : : /// \brief Delete a single record from the zone to be updated.
499 : : ///
500 : : /// This method provides a simple interface to delete a record
501 : : /// (a database "row") from the zone in the update context started by
502 : : /// \c startUpdateZone(). The zone from which the record to be deleted
503 : : /// is the one specified at the time of the \c startUpdateZone() call.
504 : : ///
505 : : /// A successful call to \c startUpdateZone() must have preceded to
506 : : /// this call; otherwise a \c DataSourceError exception will be thrown.
507 : : ///
508 : : /// The record to be deleted is specified by a vector of strings that has
509 : : /// exactly DEL_PARAM_COUNT number of elements. See DeleteRecordParams
510 : : /// for the semantics of each element.
511 : : ///
512 : : /// \note In IXFR, TTL may also be specified, but we intentionally
513 : : /// ignore that in this interface, because it's not guaranteed
514 : : /// that all records have the same TTL (unlike the RRset
515 : : /// assumption) and there can even be multiple records for the
516 : : /// same name, type and rdata with different TTLs. If we only
517 : : /// delete one of them, subsequent lookup will still return a
518 : : /// positive answer, which would be confusing. It's a higher
519 : : /// layer's responsibility to check if there is at least one
520 : : /// record in the database that has the given TTL.
521 : : ///
522 : : /// Like \c addRecordToZone, derived class methods are not required to
523 : : /// validate the semantics of the given parameters or to check if there
524 : : /// is a record that matches the specified parameter; if there isn't
525 : : /// it simply ignores the result.
526 : : ///
527 : : /// \exception DataSourceError Invalid call without starting a transaction,
528 : : /// or other internal database error.
529 : : ///
530 : : /// \param params An array of strings that defines a record to be deleted
531 : : /// from the zone.
532 : : virtual void deleteRecordInZone(
533 : : const std::string (¶ms)[DEL_PARAM_COUNT]) = 0;
534 : :
535 : : /// \brief Delete a single NSEC3-related record from the zone to be
536 : : /// updated.
537 : : ///
538 : : /// This method is similar to \c deleteRecordInZone(), but is expected to
539 : : /// be only used for NSEC3 RRs or RRSIG RRs that cover NSEC3. The
540 : : /// relationship between these two methods is similar to that between
541 : : /// \c addRecordToZone() and \c addNSEC3RecordToZone(), and the same
542 : : /// notes apply to this method.
543 : : ///
544 : : /// This method uses the same set of parameters to specify the record
545 : : /// to be deleted as \c deleteRecordInZone(), but the \c DEL_NAME column
546 : : /// is expected to only store the hash label of the owner name.
547 : : /// This is the same as \c ADD_NSEC3_HASH column for
548 : : /// \c addNSEC3RecordToZone().
549 : : ///
550 : : /// \exception DataSourceError Invalid call without starting a transaction,
551 : : /// or other internal database error.
552 : : /// \exception isc::NotImplemented in case the database does not support
553 : : /// NSEC3
554 : : ///
555 : : /// \param params An array of strings that defines a record to be deleted
556 : : /// from the NSEC3 namespace of the zone.
557 : : virtual void deleteNSEC3RecordInZone(
558 : : const std::string (¶ms)[DEL_PARAM_COUNT]) = 0;
559 : :
560 : : /// \brief Start a general transaction.
561 : : ///
562 : : /// Each derived class version of this method starts a database
563 : : /// transaction in a way specific to the database details. Any subsequent
564 : : /// operations on the accessor are guaranteed to be not susceptible to
565 : : /// any update attempts made during the transaction. The transaction
566 : : /// must be terminated by either \c commit() or \c rollback().
567 : : ///
568 : : /// In practice, this transaction is intended to be used to perform
569 : : /// a set of atomic reads and work as a read-only lock. So, in many
570 : : /// cases \c commit() and \c rollback() will have the same effect.
571 : : ///
572 : : /// This transaction cannot coexist with an update transaction started
573 : : /// by \c startUpdateZone(). Such an attempt will result in
574 : : /// \c DataSourceError.
575 : : ///
576 : : /// \exception DataSourceError An attempt of nested transaction, or some
577 : : /// internal database related error.
578 : : virtual void startTransaction() = 0;
579 : :
580 : : /// \brief Commit a transaction.
581 : : ///
582 : : /// This method completes a transaction started by \c startTransaction
583 : : /// or \c startUpdateZone.
584 : : ///
585 : : /// A successful call to one of the "start" methods must have preceded to
586 : : /// this call; otherwise a \c DataSourceError exception will be thrown.
587 : : /// Once this method successfully completes, the transaction isn't
588 : : /// considered to exist any more. So a new transaction can now be
589 : : /// started. On the other hand, a duplicate call to this method after
590 : : /// a successful completion of it is invalid and should result in
591 : : /// a \c DataSourceError exception.
592 : : ///
593 : : /// If some internal database error happens, a \c DataSourceError
594 : : /// exception must be thrown. In that case the transaction is still
595 : : /// considered to be valid; the caller must explicitly rollback it
596 : : /// or (if it's confident that the error is temporary) try to commit it
597 : : /// again.
598 : : ///
599 : : /// \exception DataSourceError Call without a transaction, duplicate call
600 : : /// to the method or internal database error.
601 : : virtual void commit() = 0;
602 : :
603 : : /// \brief Rollback any changes in a transaction made so far.
604 : : ///
605 : : /// This method rollbacks a transaction started by \c startTransaction or
606 : : /// \c startUpdateZone. When it succeeds (it normally should, but see
607 : : /// below), the underlying database should be reverted to the point
608 : : /// before performing the corresponding "start" method.
609 : : ///
610 : : /// A successful call to one of the "start" method must have preceded to
611 : : /// this call; otherwise a \c DataSourceError exception will be thrown.
612 : : /// Once this method successfully completes, the transaction isn't
613 : : /// considered to exist any more. So a new transaction can now be
614 : : /// started. On the other hand, a duplicate call to this method after
615 : : /// a successful completion of it is invalid and should result in
616 : : /// a \c DataSourceError exception.
617 : : ///
618 : : /// Normally this method should not fail. But it may not always be
619 : : /// possible to guarantee it depending on the characteristics of the
620 : : /// underlying database system. So this interface doesn't require the
621 : : /// actual implementation for the error free property. But if a specific
622 : : /// implementation of this method can fail, it is encouraged to document
623 : : /// when that can happen with its implication.
624 : : ///
625 : : /// \exception DataSourceError Call without a transaction, duplicate call
626 : : /// to the method or internal database error.
627 : : virtual void rollback() = 0;
628 : :
629 : : /// \brief Install a single RR diff in difference sequences for zone update.
630 : : ///
631 : : /// This method inserts parameters of an update operation for a single RR
632 : : /// (either adding or deleting one) in the underlying database.
633 : : /// (These parameters would normally be a separate database table, but
634 : : /// actual realization can differ in specific implementations).
635 : : /// The information given via this method generally corresponds to either
636 : : /// a single call to \c addRecordToZone() or \c deleteRecordInZone(),
637 : : /// and this method is expected to be called immediately after (or before)
638 : : /// a call to either of those methods.
639 : : ///
640 : : /// Note, however, that this method passes more detailed information
641 : : /// than those update methods: it passes "serial", even if the diff
642 : : /// is not for the SOA RR; it passes TTL for a diff that deletes an RR
643 : : /// while in \c deleteRecordInZone() it's omitted. This is because
644 : : /// the stored diffs are expected to be retrieved in the form that
645 : : /// \c getDiffs() is expected to meet. This means if the caller
646 : : /// wants to use this method with other update operations, it must
647 : : /// ensure the additional information is ready when this method is called.
648 : : ///
649 : : /// The caller of this method must ensure that the added diffs via
650 : : /// this method in a single transaction form an IXFR-style difference
651 : : /// sequences: Each difference sequence is a sequence of RRs:
652 : : /// an older version of SOA (to be deleted), zero or more other deleted
653 : : /// RRs, the post-transaction SOA (to be added), and zero or more other
654 : : /// added RRs. So, for example, the first call to this method in a
655 : : /// transaction must always be deleting an SOA. Also, the \c serial
656 : : /// parameter must be equal to the value of the serial field of the
657 : : /// SOA that was last added or deleted (if the call is to add or delete
658 : : /// an SOA RR, \c serial must be identical to the serial of that SOA).
659 : : /// The underlying derived class implementation may or may not check
660 : : /// this condition, but if the caller doesn't meet the condition
661 : : /// a subsequent call to \c getDiffs() will not work as expected.
662 : : ///
663 : : /// Any call to this method must be in a transaction, and, for now,
664 : : /// it must be a transaction triggered by \c startUpdateZone() (that is,
665 : : /// it cannot be a transaction started by \c startTransaction()).
666 : : /// All calls to this method are considered to be part of an atomic
667 : : /// transaction: Until \c commit() is performed, the added diffs are
668 : : /// not visible outside the transaction; if \c rollback() is performed,
669 : : /// all added diffs are canceled; and the added sequences are not
670 : : /// affected by any concurrent attempt of adding diffs (conflict resolution
671 : : /// is up to the database implementation).
672 : : ///
673 : : /// Also for now, all diffs are assumed to be for the zone that is
674 : : /// being updated in the context of \c startUpdateZone(). So the
675 : : /// \c zone_id parameter must be identical to the zone ID returned by
676 : : /// \c startUpdateZone().
677 : : ///
678 : : /// In a future version we may loosen this condition so that diffs can be
679 : : /// added in a generic transaction and may not even have to belong to
680 : : /// a single zone. For this possible extension \c zone_id parameter is
681 : : /// included even if it's redundant under the current restriction.
682 : : ///
683 : : /// The support for adding (or retrieving) diffs is optional; if it's
684 : : /// not supported in a specific data source, this method for the
685 : : /// corresponding derived class will throw an \c NotImplemented exception.
686 : : ///
687 : : /// \exception DataSourceError Invalid call without starting a transaction,
688 : : /// zone ID doesn't match the zone being updated, or other internal
689 : : /// database error.
690 : : /// \exception NotImplemented Adding diffs is not supported in the
691 : : /// data source.
692 : : /// \exception Other The concrete derived method may throw other
693 : : /// data source specific exceptions.
694 : : ///
695 : : /// \param zone_id The zone for the diff to be added.
696 : : /// \param serial The SOA serial to which the diff belongs.
697 : : /// \param operation Either \c DIFF_ADD or \c DIFF_DELETE.
698 : : /// \param params An array of strings that defines a record for the diff.
699 : : virtual void addRecordDiff(
700 : : int zone_id, uint32_t serial, DiffOperation operation,
701 : : const std::string (¶ms)[DIFF_PARAM_COUNT]) = 0;
702 : :
703 : : /// \brief Clone the accessor with the same configuration.
704 : : ///
705 : : /// Each derived class implementation of this method will create a new
706 : : /// accessor of the same derived class with the same configuration
707 : : /// (such as the database server address) as that of the caller object
708 : : /// and return it.
709 : : ///
710 : : /// Note that other internal states won't be copied to the new accessor
711 : : /// even though the name of "clone" may indicate so. For example, even
712 : : /// if the calling accessor is in the middle of a update transaction,
713 : : /// the new accessor will not start a transaction to trace the same
714 : : /// updates.
715 : : ///
716 : : /// The intended use case of cloning is to create a separate context
717 : : /// where a specific set of database operations can be performed
718 : : /// independently from the original accessor. The updater will use it
719 : : /// so that multiple updaters can be created concurrently even if the
720 : : /// underlying database system doesn't allow running multiple transactions
721 : : /// in a single database connection.
722 : : ///
723 : : /// The underlying database system may not support the functionality
724 : : /// that would be needed to implement this method. For example, it
725 : : /// may not allow a single thread (or process) to have more than one
726 : : /// database connections. In such a case the derived class implementation
727 : : /// should throw a \c DataSourceError exception.
728 : : ///
729 : : /// \return A shared pointer to the cloned accessor.
730 : : virtual boost::shared_ptr<DatabaseAccessor> clone() = 0;
731 : :
732 : : /// \brief Returns a string identifying this dabase backend
733 : : ///
734 : : /// The returned string is mainly intended to be used for
735 : : /// debugging/logging purposes.
736 : : ///
737 : : /// Any implementation is free to choose the exact string content,
738 : : /// but it is advisable to make it a name that is distinguishable
739 : : /// from the others.
740 : : ///
741 : : /// \return the name of the database
742 : : virtual const std::string& getDBName() const = 0;
743 : :
744 : : /// \brief It returns the previous name in DNSSEC order.
745 : : ///
746 : : /// This is used in DatabaseClient::findPreviousName and does more
747 : : /// or less the real work, except for working on strings.
748 : : ///
749 : : /// \param rname The name to ask for previous of, in reversed form.
750 : : /// We use the reversed form (see isc::dns::Name::reverse),
751 : : /// because then the case insensitive order of string representation
752 : : /// and the DNSSEC order correspond (eg. org.example.a is followed
753 : : /// by org.example.a.b which is followed by org.example.b, etc).
754 : : /// \param zone_id The zone to look through.
755 : : /// \return The previous name.
756 : : /// \note This function must return previous name even in case
757 : : /// the queried rname does not exist in the zone.
758 : : /// \note This method must skip under-the-zone-cut data (glue data).
759 : : /// This might be implemented by looking for NSEC records (as glue
760 : : /// data don't have them) in the zone or in some other way.
761 : : ///
762 : : /// \throw DataSourceError if there's a problem with the database.
763 : : /// \throw NotImplemented if this database doesn't support DNSSEC
764 : : /// or there's no previous name for the queried one (the NSECs
765 : : /// might be missing or the queried name is less or equal the
766 : : /// apex of the zone).
767 : : virtual std::string findPreviousName(int zone_id,
768 : : const std::string& rname) const = 0;
769 : :
770 : : /// \brief It returns the previous hash in the NSEC3 chain.
771 : : ///
772 : : /// This is used to find previous NSEC3 hashes, to find covering NSEC3 in
773 : : /// case none match exactly.
774 : : ///
775 : : /// In case a hash before the lowest or the lowest is provided,
776 : : /// this should return the largest one in the zone (NSEC3 needs a
777 : : /// wrap-around semantics).
778 : : ///
779 : : /// \param zone_id Specifies the zone to look into, as returned by getZone.
780 : : /// \param hash The hash to look before.
781 : : /// \return The nearest smaller hash than the provided one, or the largest
782 : : /// hash in the zone if something smaller or equal to the lowest one
783 : : /// is provided.
784 : : /// \note If the zone contains multiple NSEC3 chains, you should check that
785 : : /// the returned result contains the NSEC3 for correct parameters. If
786 : : /// not, query again and get something smaller - this will eventually
787 : : /// get to the correct one. This interface and semantics might change
788 : : /// in future.
789 : : ///
790 : : /// \throw DataSourceError if there's a problem with the database or if
791 : : /// this zone is not signed with NSEC3.
792 : : /// \throw NotImplemented if this database doesn't support NSEC3.
793 : : /// \throw anything else, as this might be any implementation.
794 : : virtual std::string findPreviousNSEC3Hash(int zone_id,
795 : : const std::string& hash)
796 : : const = 0;
797 : : };
798 : :
799 : : /// \brief Concrete data source client oriented at database backends.
800 : : ///
801 : : /// This class (together with corresponding versions of ZoneFinder,
802 : : /// ZoneIterator, etc.) translates high-level data source queries to
803 : : /// low-level calls on DatabaseAccessor. It calls multiple queries
804 : : /// if necessary and validates data from the database, allowing the
805 : : /// DatabaseAccessor to be just simple translation to SQL/other
806 : : /// queries to database.
807 : : ///
808 : : /// While it is possible to subclass it for specific database in case
809 : : /// of special needs, it is not expected to be needed. This should just
810 : : /// work as it is with whatever DatabaseAccessor.
811 : 490 : class DatabaseClient : public DataSourceClient {
812 : : public:
813 : : /// \brief Constructor
814 : : ///
815 : : /// It initializes the client with a database via the given accessor.
816 : : ///
817 : : /// \exception isc::InvalidParameter if accessor is NULL. It might throw
818 : : /// standard allocation exception as well, but doesn't throw anything else.
819 : : ///
820 : : /// \param rrclass The RR class of the zones that this client will handle.
821 : : /// \param accessor The accessor to the database to use to get data.
822 : : /// As the parameter suggests, the client takes ownership of the accessor
823 : : /// and will delete it when itself deleted.
824 : : DatabaseClient(isc::dns::RRClass rrclass,
825 : : boost::shared_ptr<DatabaseAccessor> accessor);
826 : :
827 : :
828 : : /// \brief Corresponding ZoneFinder implementation
829 : : ///
830 : : /// The zone finder implementation for database data sources. Similarly
831 : : /// to the DatabaseClient, it translates the queries to methods of the
832 : : /// database.
833 : : ///
834 : : /// Application should not come directly in contact with this class
835 : : /// (it should handle it trough generic ZoneFinder pointer), therefore
836 : : /// it could be completely hidden in the .cc file. But it is provided
837 : : /// to allow testing and for rare cases when a database needs slightly
838 : : /// different handling, so it can be subclassed.
839 : : ///
840 : : /// Methods directly corresponds to the ones in ZoneFinder.
841 : 1549 : class Finder : public ZoneFinder {
842 : : public:
843 : : /// \brief Constructor
844 : : ///
845 : : /// \param database The database (shared with DatabaseClient) to
846 : : /// be used for queries (the one asked for ID before).
847 : : /// \param zone_id The zone ID which was returned from
848 : : /// DatabaseAccessor::getZone and which will be passed to further
849 : : /// calls to the database.
850 : : /// \param origin The name of the origin of this zone. It could query
851 : : /// it from database, but as the DatabaseClient just searched for
852 : : /// the zone using the name, it should have it.
853 : : Finder(boost::shared_ptr<DatabaseAccessor> database, int zone_id,
854 : : const isc::dns::Name& origin);
855 : :
856 : : // The following three methods are just implementations of inherited
857 : : // ZoneFinder's pure virtual methods.
858 : : virtual isc::dns::Name getOrigin() const;
859 : : virtual isc::dns::RRClass getClass() const;
860 : :
861 : : /// \brief Find an RRset in the datasource
862 : : ///
863 : : /// Searches the datasource for an RRset of the given name and
864 : : /// type. If there is a CNAME at the given name, the CNAME rrset
865 : : /// is returned.
866 : : /// (this implementation is not complete, and currently only
867 : : /// does full matches, CNAMES, and the signatures for matches and
868 : : /// CNAMEs)
869 : : ///
870 : : /// \note Maybe counter intuitively, this method is not a const member
871 : : /// function. This is intentional; some of the underlying
872 : : /// implementations are expected to use a database backend, and would
873 : : /// internally contain some abstraction of "database connection". In
874 : : /// the most strict sense any (even read only) operation might change
875 : : /// the internal state of such a connection, and in that sense the
876 : : /// operation cannot be considered "const". In order to avoid giving a
877 : : /// false sense of safety to the caller, we indicate a call to this
878 : : /// method may have a surprising side effect. That said, this view may
879 : : /// be too strict and it may make sense to say the internal database
880 : : /// connection doesn't affect external behavior in terms of the
881 : : /// interface of this method. As we gain more experiences with various
882 : : /// kinds of backends we may revisit the constness.
883 : : ///
884 : : /// \exception DataSourceError when there is a problem reading
885 : : /// the data from the dabase backend.
886 : : /// This can be a connection, code, or
887 : : /// data (parse) error.
888 : : ///
889 : : /// \param name The name to find
890 : : /// \param type The RRType to find
891 : : /// \param options Options about how to search.
892 : : /// See ZoneFinder::FindOptions.
893 : : virtual ZoneFinderContextPtr find(const isc::dns::Name& name,
894 : : const isc::dns::RRType& type,
895 : : const FindOptions options =
896 : : FIND_DEFAULT);
897 : : /// \brief Implementation of the ZoneFinder::findAll method.
898 : : ///
899 : : /// In short, it is mostly the same thing as find, but it returns all
900 : : /// RRsets in the named node through the target parameter in successful
901 : : /// case. It acts the same in the unsuccessful one.
902 : : virtual ZoneFinderContextPtr findAll(
903 : : const isc::dns::Name& name,
904 : : std::vector<isc::dns::ConstRRsetPtr>& target,
905 : : const FindOptions options = FIND_DEFAULT);
906 : :
907 : : /// \brief Implementation of ZoneFinder::findPreviousName method.
908 : : virtual isc::dns::Name findPreviousName(const isc::dns::Name& query)
909 : : const;
910 : :
911 : : /// Look for NSEC3 for proving (non)existence of given name.
912 : : ///
913 : : /// See documentation in \c Zone.
914 : : virtual FindNSEC3Result
915 : : findNSEC3(const isc::dns::Name& name, bool recursive);
916 : :
917 : : /// \brief The zone ID
918 : : ///
919 : : /// This function provides the stored zone ID as passed to the
920 : : /// constructor. This is meant for testing purposes and normal
921 : : /// applications shouldn't need it.
922 : 0 : int zone_id() const { return (zone_id_); }
923 : :
924 : : /// \brief The database accessor.
925 : : ///
926 : : /// This function provides the database accessor stored inside as
927 : : /// passed to the constructor. This is meant for testing purposes and
928 : : /// normal applications shouldn't need it.
929 : : const DatabaseAccessor& getAccessor() const {
930 : : return (*accessor_);
931 : : }
932 : :
933 : : private:
934 : : boost::shared_ptr<DatabaseAccessor> accessor_;
935 : : const int zone_id_;
936 : : const isc::dns::Name origin_;
937 : :
938 : : /// \brief Shortcut name for the result of getRRsets
939 : : typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
940 : : FoundRRsets;
941 : : /// \brief Just shortcut for set of types
942 : : typedef std::set<dns::RRType> WantedTypes;
943 : :
944 : : /// \brief Internal logit of find and findAll methods.
945 : : ///
946 : : /// Most of their handling is in the "error" cases and delegations
947 : : /// and so on. So they share the logic here and find and findAll provide
948 : : /// just an interface for it.
949 : : ///
950 : : /// Parameters and behaviour is like of those combined together.
951 : : /// Unexpected parameters, like type != ANY and having the target, are
952 : : /// just that - unexpected and not checked.
953 : : ResultContext findInternal(const isc::dns::Name& name,
954 : : const isc::dns::RRType& type,
955 : : std::vector<isc::dns::ConstRRsetPtr>*
956 : : target,
957 : : const FindOptions options = FIND_DEFAULT);
958 : :
959 : : /// \brief Searches database for RRsets of one domain.
960 : : ///
961 : : /// This method scans RRs of single domain specified by name and
962 : : /// extracts any RRsets found and requested by parameters.
963 : : ///
964 : : /// It is used internally by find(), because it is called multiple
965 : : /// times (usually with different domains).
966 : : ///
967 : : /// \param name Which domain name should be scanned.
968 : : /// \param types List of types the caller is interested in.
969 : : /// \param check_ns If this is set to true, it checks nothing lives
970 : : /// together with NS record (with few little exceptions, like RRSIG
971 : : /// or NSEC). This check is meant for non-apex NS records.
972 : : /// \param construct_name If this is NULL, the resulting RRsets have
973 : : /// their name set to name. If it is not NULL, it overrides the name
974 : : /// and uses this one (this can be used for wildcard synthesized
975 : : /// records).
976 : : /// \param any If this is true, it records all the types, not only the
977 : : /// ones requested by types. It also puts a NULL pointer under the
978 : : /// ANY type into the result, if it finds any RRs at all, to easy the
979 : : /// identification of success.
980 : : /// \param srcContext This can be set to non-NULL value to override the
981 : : /// iterator context used for obtaining the data. This can be used,
982 : : /// for example, to get data from the NSEC3 namespace.
983 : : /// \return A pair, where the first element indicates if the domain
984 : : /// contains any RRs at all (not only the requested, it may happen
985 : : /// this is set to true, but the second part is empty). The second
986 : : /// part is map from RRtypes to RRsets of the corresponding types.
987 : : /// If the RRset is not present in DB, the RRtype is not there at
988 : : /// all (so you'll not find NULL pointer in the result).
989 : : /// \throw DataSourceError If there's a low-level error with the
990 : : /// database or the database contains bad data.
991 : : FoundRRsets getRRsets(const std::string& name,
992 : : const WantedTypes& types, bool check_ns,
993 : : const std::string* construct_name = NULL,
994 : : bool any = false,
995 : : DatabaseAccessor::IteratorContextPtr srcContext =
996 : : DatabaseAccessor::IteratorContextPtr());
997 : :
998 : : /// \brief DNSSEC related context for ZoneFinder::findInternal.
999 : : ///
1000 : : /// This class is a helper for the ZoneFinder::findInternal method,
1001 : : /// encapsulating DNSSEC related information and processing logic.
1002 : : /// Specifically, it tells the finder whether the zone under search
1003 : : /// is DNSSEC signed or not, and if it is, whether it's with NSEC or
1004 : : /// with NSEC3. It also provides a RRset DNSSEC proof RRset for some
1005 : : /// specific situations (in practice, this means an NSEC RRs for
1006 : : /// negative proof when they are needed and expected).
1007 : : ///
1008 : : /// The purpose of this class is to keep the main finder implementation
1009 : : /// unaware of DNSSEC related details. It's also intended to help
1010 : : /// avoid unnecessary lookup for DNSSEC proof RRsets; this class
1011 : : /// doesn't look into the DB for these RRsets unless it's known to
1012 : : /// be needed. The same optimization could be implemented in the
1013 : : /// main code, but it will result in duplicate similar code logic
1014 : : /// and make the code more complicated. By encapsulating and unifying
1015 : : /// the logic in a single separate class, we can keep the main
1016 : : /// search logic readable.
1017 : : class FindDNSSECContext {
1018 : : public:
1019 : : /// \brief Constructor for FindDNSSECContext class.
1020 : : ///
1021 : : /// This constructor doesn't involve any expensive operation such
1022 : : /// as database lookups. It only initializes some internal
1023 : : /// states (in a cheap way) and remembers if DNSSEC proof
1024 : : /// is requested.
1025 : : ///
1026 : : /// \param finder The Finder for the findInternal that uses this
1027 : : /// context.
1028 : : /// \param options Find options given to the finder.
1029 : : FindDNSSECContext(Finder& finder, const FindOptions options);
1030 : :
1031 : : /// \brief Return DNSSEC related result flags for the context.
1032 : : ///
1033 : : /// This method returns a FindResultFlags value related to
1034 : : /// DNSSEC, based on the context. If DNSSEC proof is requested
1035 : : /// and the zone is signed with NSEC/NSEC3, it returns
1036 : : /// RESULT_NSEC_SIGNED/RESULT_NSEC3_SIGNED, respectively;
1037 : : /// otherwise it returns RESULT_DEFAULT. So the caller can simply
1038 : : /// take a logical OR for the returned value of this method and
1039 : : /// whatever other flags it's going to set, without knowing
1040 : : /// DNSSEC specific information.
1041 : : ///
1042 : : /// If it's not yet identified whether and how the zone is DNSSEC
1043 : : /// signed at the time of the call, it now detects that via
1044 : : /// database lookups (if necessary). (And this is because why
1045 : : /// this method cannot be a const member function).
1046 : : ZoneFinder::FindResultFlags getResultFlags();
1047 : :
1048 : : /// \brief Get DNSSEC negative proof for a given name.
1049 : : ///
1050 : : /// If the zone is considered NSEC-signed and the context
1051 : : /// requested DNSSEC proofs, this method tries to find NSEC RRs
1052 : : /// for the give name. If \c covering is true, it means a
1053 : : /// "no name" proof is requested, so it calls findPreviousName on
1054 : : /// the given name and extracts an NSEC record on the result;
1055 : : /// otherwise it tries to get NSEC RRs for the given name. If
1056 : : /// the NSEC is found, this method returns it; otherwise it returns
1057 : : /// NULL.
1058 : : ///
1059 : : /// In all other cases this method simply returns NULL.
1060 : : ///
1061 : : /// \param name The name which the NSEC RRset belong to.
1062 : : /// \param covering true if a covering NSEC is required; false if
1063 : : /// a matching NSEC is required.
1064 : : /// \return Any found DNSSEC proof RRset or NULL
1065 : : isc::dns::ConstRRsetPtr getDNSSECRRset(
1066 : : const isc::dns::Name& name, bool covering);
1067 : :
1068 : : /// \brief Get DNSSEC negative proof for a given name.
1069 : : ///
1070 : : /// If the zone is considered NSEC-signed and the context
1071 : : /// requested DNSSEC proofs, this method tries to find NSEC RRset
1072 : : /// from the given set (\c found_set) and returns it if found;
1073 : : /// in other cases this method simply returns NULL.
1074 : : ///
1075 : : /// \param found_set The RRset which may contain an NSEC RRset.
1076 : : /// \return Any found DNSSEC proof RRset or NULL
1077 : : isc::dns::ConstRRsetPtr getDNSSECRRset(const FoundRRsets&
1078 : : found_set);
1079 : :
1080 : : private:
1081 : : /// \brief Returns whether the zone is signed with NSEC3.
1082 : : ///
1083 : : /// This method returns true if the zone for the finder that
1084 : : /// uses this context is considered DNSSEC signed with NSEC3;
1085 : : /// otherwise it returns false. If it's not yet detected,
1086 : : /// this method now detects that via database lookups (if
1087 : : /// necessary).
1088 : : bool isNSEC3();
1089 : :
1090 : : /// \brief Returns whether the zone is signed with NSEC.
1091 : : ///
1092 : : /// This is similar to isNSEC3(), but works for NSEC.
1093 : : bool isNSEC();
1094 : :
1095 : : /// \brief Probe into the database to see if/how the zone is
1096 : : /// signed.
1097 : : ///
1098 : : /// This is a subroutine of isNSEC3() and isNSEC(), and performs
1099 : : /// delayed database probe to detect whether the zone used by
1100 : : /// the finder is DNSSEC signed, and if it is, with NSEC or NSEC3.
1101 : : void probe();
1102 : :
1103 : : DatabaseClient::Finder& finder_;
1104 : : const bool need_dnssec_;
1105 : :
1106 : : bool is_nsec3_;
1107 : : bool is_nsec_;
1108 : : bool probed_;
1109 : : };
1110 : :
1111 : : /// \brief Search result of \c findDelegationPoint().
1112 : : ///
1113 : : /// This is a tuple combining the result of the search - a status code
1114 : : /// and a pointer to the RRset found - together with additional
1115 : : /// information needed for subsequent processing, an indication of
1116 : : /// the first NS RRset found in the search and the number of labels
1117 : : /// in the last non-empty domain encountered in the search. It is
1118 : : /// used by \c findDelegationPoint().
1119 : : ///
1120 : : /// The last two items are located naturally in the search and although
1121 : : /// not strictly part of the result, they are passed back to avoid
1122 : : /// another (duplicate) search later in the processing.
1123 : : ///
1124 : : /// Note that the code and rrset elements are the same as that in
1125 : : /// the \c ZoneFinder::FindResult struct: this structure could be
1126 : : /// derived from that one, but as it is used just once in the code and
1127 : : /// will never be treated as a \c FindResult, the obscurity involved in
1128 : : /// deriving it from a parent class was deemed not worthwhile.
1129 : 726 : struct DelegationSearchResult {
1130 : : DelegationSearchResult(const ZoneFinder::Result param_code,
1131 : : const isc::dns::ConstRRsetPtr param_rrset,
1132 : : const isc::dns::ConstRRsetPtr param_ns,
1133 : : size_t param_last_known) :
1134 : : code(param_code), rrset(param_rrset),
1135 : : first_ns(param_ns),
1136 : 2178 : last_known(param_last_known)
1137 : : {}
1138 : : const ZoneFinder::Result code; ///< Result code
1139 : : const isc::dns::ConstRRsetPtr rrset; ///< RRset found
1140 : : const isc::dns::ConstRRsetPtr first_ns; ///< First NS found
1141 : : const size_t last_known; ///< No. labels in last non-empty domain
1142 : : };
1143 : :
1144 : : /// \brief Find delegation point
1145 : : ///
1146 : : /// Given a name, searches through the superdomains from the origin
1147 : : /// down, searching for a point that indicates a delegation (i.e. an
1148 : : /// NS record or a DNAME).
1149 : : ///
1150 : : /// The method operates in two modes, non-glue-ok and glue-ok modes:
1151 : : ///
1152 : : /// In non-glue-ok mode, the search is made purely for the NS or DNAME
1153 : : /// RR. The zone is searched from the origin down looking for one
1154 : : /// of these RRTypes (and ignoring the NS records at the zone origin).
1155 : : /// A status is returned indicating what is found: DNAME, DELEGATION
1156 : : /// of SUCCESS, the last indicating that nothing was found, together
1157 : : /// with a pointer to the relevant RR.
1158 : : ///
1159 : : /// In glue-ok mode, the first NS encountered in the search (apart from
1160 : : /// the NS at the zone apex) is remembered but otherwise NS records are
1161 : : /// ignored and the search attempts to find a DNAME. The result is
1162 : : /// returned in the same format, along with a pointer to the first non-
1163 : : /// apex NS (if found).
1164 : : ///
1165 : : /// \param name The name to find
1166 : : /// \param options Options about how to search. See the documentation
1167 : : /// for ZoneFinder::FindOptions.
1168 : : ///
1169 : : /// \return Tuple holding the result of the search - the RRset of the
1170 : : /// delegation point and the type of the point (DELEGATION or
1171 : : /// DNAME) - and associated information. This latter item
1172 : : /// comprises two pieces of data: a pointer to the highest
1173 : : /// encountered NS, and the number of labels in the last known
1174 : : /// non-empty domain. The associated information is found as
1175 : : /// a natural part of the search for the delegation point and
1176 : : /// is used later in the find() processing; it is passed back
1177 : : /// to avoid the need to perform a second search to obtain it.
1178 : : DelegationSearchResult
1179 : : findDelegationPoint(const isc::dns::Name& name,
1180 : : const FindOptions options);
1181 : :
1182 : : /// \brief Find wildcard match
1183 : : ///
1184 : : /// Having found that the name is not an empty non-terminal, this
1185 : : /// searches the zone for for wildcards that match the name.
1186 : : ///
1187 : : /// It searches superdomains of the name from the zone origin down
1188 : : /// looking for a wildcard in the zone that matches the name. There
1189 : : /// are several cases to consider:
1190 : : ///
1191 : : /// - If the previous search for a delegation point has found that
1192 : : /// there is an NS at the superdomain of the point at which the
1193 : : /// wildcard is found, the delegation is returned.
1194 : : /// - If there is a match to the name, an appropriate status is
1195 : : /// returned (match on requested type, delegation, cname, or just
1196 : : /// the indication of a match but no RRs relevant to the query).
1197 : : /// - If the match is to an non-empty non-terminal wildcard, a
1198 : : /// wildcard NXRRSET is returned.
1199 : : ///
1200 : : /// Note that if DNSSEC is enabled for the search and the zone uses
1201 : : /// NSEC for authenticated denial of existence, the search may
1202 : : /// return NSEC records.
1203 : : ///
1204 : : /// \param name The name to find
1205 : : /// \param type The RRType to find
1206 : : /// \param options Options about how to search. See the documentation
1207 : : /// for ZoneFinder::FindOptions.
1208 : : /// \param dresult Result of the search through the zone for a
1209 : : /// delegation.
1210 : : /// \param target If the type happens to be ANY, it will insert all
1211 : : /// the RRsets of the found name (if any is found) here instead
1212 : : /// of being returned by the result.
1213 : : /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
1214 : : /// find function.
1215 : : /// \return Tuple holding the result of the search - the RRset of the
1216 : : /// wildcard records matching the name, together with a status
1217 : : /// indicating the match type (e.g. CNAME at the wildcard
1218 : : /// match, no RRs of the requested type at the wildcard,
1219 : : /// success due to an exact match). Also returned if there
1220 : : /// is no match is an indication as to whether there was an
1221 : : /// NXDOMAIN or an NXRRSET.
1222 : : ResultContext findWildcardMatch(const isc::dns::Name& name,
1223 : : const isc::dns::RRType& type,
1224 : : const FindOptions options,
1225 : : const DelegationSearchResult& dresult,
1226 : : std::vector<isc::dns::ConstRRsetPtr>*
1227 : : target, FindDNSSECContext& dnssec_ctx);
1228 : :
1229 : : /// \brief Handle matching results for name
1230 : : ///
1231 : : /// This is called when something is found in the underlying database
1232 : : /// whose domain name is an exact match of the name to be searched for.
1233 : : /// It explores four possible cases to decide the final lookup result:
1234 : : /// - The name is a zone cut due to an NS RR.
1235 : : /// - CNAME is found (while the requested RR type is not CNAME).
1236 : : /// In this case multiple CNAMEs are checked and rejected with
1237 : : /// a \c DataSourceError exception.
1238 : : /// - Requested type is not found at that name.
1239 : : /// - A record of the requested type is found, or the query is ANY and
1240 : : /// some records were found.
1241 : : /// and returns a corresponding find result.
1242 : : ///
1243 : : /// This method is commonly used for normal (non wildcard) and wildcard
1244 : : /// matches.
1245 : : ///
1246 : : /// \param name The name to find
1247 : : /// \param type The RRType to find
1248 : : /// \param options Options about how to search. See the documentation
1249 : : /// for ZoneFinder::FindOptions.
1250 : : /// \param is_origin If name is the zone's origin name.
1251 : : /// \param found A set of found RRsets in the search for the name
1252 : : /// and type. It could contain one or more of the requested
1253 : : /// type, CNAME, NS, and NSEC RRsets of the name.
1254 : : /// \param wildname If non NULL, the method is called on a wildcard
1255 : : /// match, and points to a string object representing
1256 : : /// a textual form of the matched wildcard name;
1257 : : /// it's NULL in the case of non wildcard match.
1258 : : /// \param target When the query is any, this must be set to a vector
1259 : : /// where the result will be stored.
1260 : : /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
1261 : : /// find function.
1262 : :
1263 : : /// \return Tuple holding the result of the search - the RRset of the
1264 : : /// wildcard records matching the name, together with a status
1265 : : /// indicating the match type (corresponding to the each of
1266 : : /// the above 4 cases). The return value is intended to be
1267 : : /// usable as a return value of the caller of this helper
1268 : : /// method.
1269 : : ResultContext findOnNameResult(const isc::dns::Name& name,
1270 : : const isc::dns::RRType& type,
1271 : : const FindOptions options,
1272 : : const bool is_origin,
1273 : : const FoundRRsets& found,
1274 : : const std::string* wildname,
1275 : : std::vector<isc::dns::ConstRRsetPtr>*
1276 : : target, FindDNSSECContext& dnssec_ctx);
1277 : :
1278 : : /// \brief Handle no match for name
1279 : : ///
1280 : : /// This is called when it is known that there is no delegation and
1281 : : /// there is no exact match for the name (regardless of RR types
1282 : : /// requested). Before returning NXDOMAIN, we need to check two
1283 : : /// cases:
1284 : : /// - Empty non-terminal: if the name has subdomains in the database,
1285 : : /// flag the fact. An NXRRSET will be returned (along with the
1286 : : /// NSEC record covering the requested domain name if DNSSEC data
1287 : : /// is being returned).
1288 : : /// - Wildcard: is there a wildcard record in the zone that matches
1289 : : /// requested name? If so, return it. If not, return the relevant
1290 : : /// NSEC records (if requested).
1291 : : ///
1292 : : /// \param name The name to find
1293 : : /// \param type The RRType to find
1294 : : /// \param options Options about how to search. See the documentation
1295 : : /// for ZoneFinder::FindOptions.
1296 : : /// \param dresult Result of the search through the zone for a
1297 : : /// delegation.
1298 : : /// \param target If the query is for type ANY, the successfull result,
1299 : : /// if there happens to be one, will be returned through the
1300 : : /// parameter, as it doesn't fit into the result.
1301 : : /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
1302 : : /// find function.
1303 : : /// \return Tuple holding the result of the search - the RRset of the
1304 : : /// wildcard records matching the name, together with a status
1305 : : /// indicating the match type (e.g. CNAME at the wildcard
1306 : : /// match, no RRs of the requested type at the wildcard,
1307 : : /// success due to an exact match).
1308 : : ResultContext findNoNameResult(const isc::dns::Name& name,
1309 : : const isc::dns::RRType& type,
1310 : : FindOptions options,
1311 : : const DelegationSearchResult& dresult,
1312 : : std::vector<isc::dns::ConstRRsetPtr>*
1313 : : target, FindDNSSECContext& dnssec_ctx);
1314 : :
1315 : : /// Logs condition and creates result
1316 : : ///
1317 : : /// A convenience function used by findOnNameResult(), it both creates
1318 : : /// the FindResult object that find() will return to its caller as well
1319 : : /// as logging a debug message for the information being returned.
1320 : : ///
1321 : : /// \param name Domain name of the RR that was being sought.
1322 : : /// \param wildname Domain name string of a matched wildcard name or
1323 : : /// NULL for non wildcard match.
1324 : : /// \param type Type of RR being sought.
1325 : : /// \param code Result of the find operation
1326 : : /// \param rrset RRset found as a result of the find (which may be
1327 : : /// null).
1328 : : /// \param log_id ID of the message being logged. Up to five
1329 : : /// parameters are available to the message: data source name,
1330 : : /// requested domain name, requested class, requested type
1331 : : /// and (but only if the search was successful and returned
1332 : : /// an RRset) details of the RRset found.
1333 : : ///
1334 : : /// \return FindResult object constructed from the code and rrset
1335 : : /// arguments.
1336 : : ResultContext logAndCreateResult(const isc::dns::Name& name,
1337 : : const std::string* wildname,
1338 : : const isc::dns::RRType& type,
1339 : : ZoneFinder::Result code,
1340 : : isc::dns::ConstRRsetPtr rrset,
1341 : : const isc::log::MessageID& log_id,
1342 : : FindResultFlags flags) const;
1343 : :
1344 : : /// \brief Checks if something lives below this domain.
1345 : : ///
1346 : : /// This looks if there's any subdomain of the given name. It can be
1347 : : /// used to test if domain is empty non-terminal.
1348 : : ///
1349 : : /// \param name The domain to check.
1350 : : ///
1351 : : /// \return true if the name has subdomains, false if not.
1352 : : bool hasSubdomains(const std::string& name);
1353 : :
1354 : : /// \brief Convenience type shortcut.
1355 : : ///
1356 : : /// To find stuff in the result of getRRsets.
1357 : : typedef std::map<dns::RRType, dns::RRsetPtr>::const_iterator
1358 : : FoundIterator;
1359 : : };
1360 : :
1361 : : /// \brief Find a zone in the database
1362 : : ///
1363 : : /// This queries database's getZone to find the best matching zone.
1364 : : /// It will propagate whatever exceptions are thrown from that method
1365 : : /// (which is not restricted in any way).
1366 : : ///
1367 : : /// \param name Name of the zone or data contained there.
1368 : : /// \return FindResult containing the code and an instance of Finder, if
1369 : : /// anything is found. However, application should not rely on the
1370 : : /// ZoneFinder being instance of Finder (possible subclass of this class
1371 : : /// may return something else and it may change in future versions), it
1372 : : /// should use it as a ZoneFinder only.
1373 : : virtual FindResult findZone(const isc::dns::Name& name) const;
1374 : :
1375 : : /// \brief Get the zone iterator
1376 : : ///
1377 : : /// The iterator allows going through the whole zone content. If the
1378 : : /// underlying DatabaseConnection is implemented correctly, it should
1379 : : /// be possible to have multiple ZoneIterators at once and query data
1380 : : /// at the same time.
1381 : : ///
1382 : : /// \exception DataSourceError if the zone doesn't exist.
1383 : : /// \exception isc::NotImplemented if the underlying DatabaseConnection
1384 : : /// doesn't implement iteration. But in case it is not implemented
1385 : : /// and the zone doesn't exist, DataSourceError is thrown.
1386 : : /// \exception Anything else the underlying DatabaseConnection might
1387 : : /// want to throw.
1388 : : /// \param name The origin of the zone to iterate.
1389 : : /// \param separate_rrs If true, the iterator will return each RR as a
1390 : : /// new RRset object. If false, the iterator will
1391 : : /// combine consecutive RRs with the name and type
1392 : : /// into 1 RRset. The capitalization of the RRset will
1393 : : /// be that of the first RR read, and TTLs will be
1394 : : /// adjusted to the lowest one found.
1395 : : /// \return Shared pointer to the iterator (it will never be NULL)
1396 : : virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
1397 : : bool separate_rrs = false) const;
1398 : :
1399 : : /// This implementation internally clones the accessor from the one
1400 : : /// used in the client and starts a separate transaction using the cloned
1401 : : /// accessor. The returned updater will be able to work separately from
1402 : : /// the original client.
1403 : : virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name& name,
1404 : : bool replace,
1405 : : bool journaling = false) const;
1406 : :
1407 : :
1408 : : /// This implementation internally clones the accessor from the one
1409 : : /// used in the client for retrieving diffs and iterating over them.
1410 : : /// The returned reader object will be able to work separately from
1411 : : /// the original client.
1412 : : virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
1413 : : getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
1414 : : uint32_t end_serial) const;
1415 : :
1416 : : private:
1417 : : /// \brief The RR class that this client handles.
1418 : : const isc::dns::RRClass rrclass_;
1419 : :
1420 : : /// \brief The accessor to our database.
1421 : : const boost::shared_ptr<DatabaseAccessor> accessor_;
1422 : : };
1423 : :
1424 : : }
1425 : : }
1426 : :
1427 : : #endif // __DATABASE_DATASRC_H
1428 : :
1429 : : // Local Variables:
1430 : : // mode: c++
1431 : : // End:
|