zone.h 27.8 KB
Newer Older
1
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
Michal Vaner's avatar
Michal Vaner committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// 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.

#ifndef __ZONE_H
#define __ZONE_H 1

18
#include <dns/rrset.h>
19
#include <dns/rrsetlist.h>
Michal Vaner's avatar
Michal Vaner committed
20

21
22
#include <datasrc/result.h>

Michal Vaner's avatar
Michal Vaner committed
23
24
25
namespace isc {
namespace datasrc {

26
/// \brief The base class to search a zone for RRsets
Michal Vaner's avatar
Michal Vaner committed
27
///
28
29
30
31
32
33
34
35
/// The \c ZoneFinder class is an abstract base class for representing
/// an object that performs DNS lookups in a specific zone accessible via
/// a data source.  In general, different types of data sources (in-memory,
/// database-based, etc) define their own derived classes of \c ZoneFinder,
/// implementing ways to retrieve the required data through the common
/// interfaces declared in the base class.  Each concrete \c ZoneFinder
/// object is therefore (conceptually) associated with a specific zone
/// of one specific data source instance.
Michal Vaner's avatar
Michal Vaner committed
36
///
37
38
/// The origin name and the RR class of the associated zone are available
/// via the \c getOrigin() and \c getClass() methods, respectively.
Michal Vaner's avatar
Michal Vaner committed
39
///
40
41
42
/// The most important method of this class is \c find(), which performs
/// the lookup for a given domain and type.  See the description of the
/// method for details.
Michal Vaner's avatar
Michal Vaner committed
43
///
44
45
46
47
48
49
50
/// \note It's not clear whether we should request that a zone finder form a
/// "transaction", that is, whether to ensure the finder is not susceptible
/// to changes made by someone else than the creator of the finder.  If we
/// don't request that, for example, two different lookup results for the
/// same name and type can be different if other threads or programs make
/// updates to the zone between the lookups.  We should revisit this point
/// as we gain more experiences.
51
class ZoneFinder {
Michal Vaner's avatar
Michal Vaner committed
52
53
54
55
56
public:
    /// Result codes of the \c find() method.
    ///
    /// Note: the codes are tentative.  We may need more, or we may find
    /// some of them unnecessary as we implement more details.
57
58
59
60
61
62
63
64
    ///
    /// Some are synonyms of others in terms of RCODE returned to user.
    /// But they help the logic to decide if it should ask for a NSEC
    /// that covers something or not (for example, in case of NXRRSET,
    /// the directly returned NSEC is sufficient, but with wildcard one,
    /// we need to add one proving there's no exact match and this is
    /// actually the best wildcard we have). Data sources that don't
    /// support DNSSEC don't need to distinguish them.
65
    ///
66
67
68
69
    /// In case of CNAME, if the CNAME is a wildcard (i.e., its owner name
    /// starts with the label "*"), WILDCARD_CNAME will be returned instead
    /// of CNAME.
    ///
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    /// In case of NXDOMAIN, the returned NSEC covers the queried domain
    /// that proves that the query name does not exist in the zone.  Note that
    /// this does not necessarily prove it doesn't even match a wildcard
    /// (even if the result of NXDOMAIN can only happen when there's no
    /// matching wildcard either).  It is caller's responsibility to provide
    /// a proof that there is no matching wildcard if that proof is necessary.
    ///
    /// Various variants of "no data" cases are complicated, when involves
    /// DNSSEC and wildcard processing.  Referring to Section 3.1.3 of
    /// RFC4035, we need to consider the following cases:
    /// -# (Normal) no data: there is a matching non-wildcard name with a
    ///    different RR type.  This is the "No Data" case of the RFC.
    /// -# (Normal) empty non terminal: there is no matching (exact or
    ///    wildcard) name, but there is a subdomain with an RR of the query
    ///    name.  This is one case of "Name Error" of the RFC.
    /// -# Wildcard empty non terminal: similar to 2a, but the empty name
    ///    is a wildcard, and matches the query name by wildcard expansion.
    ///    This is a special case of "Name Error" of the RFC.
    /// -# Wildcard no data: there is no exact match name, but there is a
    ///    wildcard name that matches the query name with a different type
    ///    of RR.  This is the "Wildcard No Data" case of the RFC.
    ///
    /// In any case, \c find() will result in \c NXRRSET with no RRset
    /// unless the \c FIND_DNSSEC option is specified.  The rest of the
    /// discussion only applies to the case where this option is specified.
    ///
    /// In case 1, \c find() will result in NXRRSET, and return NSEC of the
    /// matching name.
    ///
    /// In case 2, \c find() will result in NXRRSET, and return NSEC for the
    /// interval where the empty nonterminal lives. The end of the interval
    /// is the subdomain causing existence of the empty nonterminal (if
    /// there's sub.x.example.com, and no record in x.example.com, then
    /// x.example.com exists implicitly - is the empty nonterminal and
    /// sub.x.example.com is the subdomain causing it).  Note that this NSEC
    /// proves not only the existence of empty non terminal name but also
    /// the non existence of possibly matching wildcard name, because
    /// there can be no better wildcard match than the exact matching empty
    /// name.
    ///
    /// In case 3, \c find() will result in WILDCARD_NXRRSET, and return NSEC
    /// for the interval where the wildcard empty nonterminal lives.
    /// Cases 2 and 3 are especially complicated and confusing.  See the
    /// examples below.
    ///
    /// In case 4, \c find() will result in WILDCARD_NXRRSET, and return
    /// NSEC of the matching wildcard name.
117
    ///
118
    /// Examples: if zone "example.com" has the following record:
119
    /// \code
120
    /// a.example.com. NSEC a.b.example.com.
121
    /// \endcode
122
123
    /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
    /// will result in NXRRSET, and this NSEC will be returned.
124
125
    /// Likewise, if zone "example.org" has the following record,
    /// \code
126
    /// a.example.org. NSEC x.*.b.example.org.
127
    /// \endcode
128
129
    /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
    /// result in NXRRSET_NXRRSET, and this NSEC will be returned.
Michal Vaner's avatar
Michal Vaner committed
130
131
132
133
134
135
    enum Result {
        SUCCESS,                ///< An exact match is found.
        DELEGATION,             ///< The search encounters a zone cut.
        NXDOMAIN, ///< There is no domain name that matches the search name
        NXRRSET,  ///< There is a matching name but no RRset of the search type
        CNAME,    ///< The search encounters and returns a CNAME RR
136
137
        DNAME,    ///< The search encounters and returns a DNAME RR
        WILDCARD, ///< Succes by wildcard match, for DNSSEC
138
        WILDCARD_CNAME, ///< CNAME on wildcard, search returns CNAME, for DNSSEC
139
        WILDCARD_NXRRSET ///< NXRRSET on wildcard, for DNSSEC
Michal Vaner's avatar
Michal Vaner committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    };

    /// A helper structure to represent the search result of \c find().
    ///
    /// This is a straightforward tuple of the result code and a pointer
    /// to the found RRset to represent the result of \c find()
    /// (there will be more members in the future - see the class
    /// description).
    /// We use this in order to avoid overloading the return value for both
    /// the result code ("success" or "not found") and the found object,
    /// i.e., avoid using \c NULL to mean "not found", etc.
    ///
    /// This is a simple value class whose internal state never changes,
    /// so for convenience we allow the applications to refer to the members
    /// directly.
    ///
    /// Note: we should eventually include a notion of "zone node", which
    /// corresponds to a particular domain name of the zone, so that we can
    /// find RRsets of a different RR type for that name (e.g. for type ANY
    /// query or to include DS RRs with delegation).
    ///
    /// Note: we may also want to include the closest enclosure "node" to
    /// optimize including the NSEC for no-wildcard proof (FWIW NSD does that).
    struct FindResult {
        FindResult(Result param_code,
                   const isc::dns::ConstRRsetPtr param_rrset) :
            code(param_code), rrset(param_rrset)
        {}
        const Result code;
        const isc::dns::ConstRRsetPtr rrset;
    };

172
173
174
175
176
177
178
    /// Find options.
    ///
    /// The option values are used as a parameter for \c find().
    /// These are values of a bitmask type.  Bitwise operations can be
    /// performed on these values to express compound options.
    enum FindOptions {
        FIND_DEFAULT = 0,       ///< The default options
179
        FIND_GLUE_OK = 1,       ///< Allow search under a zone cut
180
        FIND_DNSSEC = 2,        ///< Require DNSSEC data in the answer
181
182
183
                                ///< (RRSIG, NSEC, etc.). The implementation
                                ///< is allowed to include it even if it is
                                ///< not set.
184
        NO_WILDCARD = 4         ///< Do not try wildcard matching.
185
186
    };

Michal Vaner's avatar
Michal Vaner committed
187
188
189
190
191
192
193
194
195
    ///
    /// \name Constructors and Destructor.
    ///
    //@{
protected:
    /// The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class should
    /// never be instantiated (except as part of a derived class).
196
    ZoneFinder() {}
Michal Vaner's avatar
Michal Vaner committed
197
198
public:
    /// The destructor.
199
    virtual ~ZoneFinder() {}
Michal Vaner's avatar
Michal Vaner committed
200
201
202
203
204
205
206
207
    //@}

    ///
    /// \name Getter Methods
    ///
    /// These methods should never throw an exception.
    //@{
    /// Return the origin name of the zone.
208
    virtual isc::dns::Name getOrigin() const = 0;
Michal Vaner's avatar
Michal Vaner committed
209
210

    /// Return the RR class of the zone.
211
    virtual isc::dns::RRClass getClass() const = 0;
Michal Vaner's avatar
Michal Vaner committed
212
213
214
    //@}

    ///
215
    /// \name Search Methods
Michal Vaner's avatar
Michal Vaner committed
216
217
218
219
220
221
222
223
    ///
    //@{
    /// Search the zone for a given pair of domain name and RR type.
    ///
    /// Each derived version of this method searches the underlying backend
    /// for the data that best matches the given name and type.
    /// This method is expected to be "intelligent", and identifies the
    /// best possible answer for the search key.  Specifically,
224
    ///
Michal Vaner's avatar
Michal Vaner committed
225
226
227
228
229
230
231
232
    /// - If the search name belongs under a zone cut, it returns the code
    ///   of \c DELEGATION and the NS RRset at the zone cut.
    /// - If there is no matching name, it returns the code of \c NXDOMAIN,
    ///   and, if DNSSEC is requested, the NSEC RRset that proves the
    ///   non-existence.
    /// - If there is a matching name but no RRset of the search type, it
    ///   returns the code of \c NXRRSET, and, if DNSSEC is required,
    ///   the NSEC RRset for that name.
233
234
235
    /// - If there is a CNAME RR of the searched name but there is no
    ///   RR of the searched type of the name (so this type is different from
    ///   CNAME), it returns the code of \c CNAME and that CNAME RR.
236
    ///   Note that if the searched RR type is CNAME, it is considered
237
    ///   a successful match, and the code of \c SUCCESS will be returned.
Michal Vaner's avatar
Michal Vaner committed
238
239
    /// - If the search name matches a delegation point of DNAME, it returns
    ///   the code of \c DNAME and that DNAME RR.
240
241
242
    /// - If the target isn't NULL, all RRsets under the domain are inserted
    ///   there and SUCCESS (or NXDOMAIN, in case of empty domain) is returned
    ///   instead of normall processing. This is intended to handle ANY query.
243
244
245
246
    ///
    /// \note This behavior is controversial as we discussed in
    /// https://lists.isc.org/pipermail/bind10-dev/2011-January/001918.html
    /// We should revisit the interface before we heavily rely on it.
Michal Vaner's avatar
Michal Vaner committed
247
    ///
248
    /// The \c options parameter specifies customized behavior of the search.
249
    /// Their semantics is as follows (they are or bit-field):
250
    ///
251
    /// - \c FIND_GLUE_OK Allow search under a zone cut.  By default the search
252
253
254
255
256
257
258
    ///   will stop once it encounters a zone cut.  If this option is specified
    ///   it remembers information about the highest zone cut and continues
    ///   the search until it finds an exact match for the given name or it
    ///   detects there is no exact match.  If an exact match is found,
    ///   RRsets for that name are searched just like the normal case;
    ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
    ///   with the information of the highest zone cut will be returned.
259
260
261
    /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
    ///   returned with the answer. It is allowed for the data source to
    ///   include them even when not requested.
262
263
264
265
    /// - \c NO_WILDCARD Do not try wildcard matching.  This option is of no
    ///   use for normal lookups; it's intended to be used to get a DNSSEC
    ///   proof of the non existence of any matching wildcard or non existence
    ///   of an exact match when a wildcard match is found.
266
    ///
Michal Vaner's avatar
Michal Vaner committed
267
268
269
    /// A derived version of this method may involve internal resource
    /// allocation, especially for constructing the resulting RRset, and may
    /// throw an exception if it fails.
270
271
    /// It throws DuplicateRRset exception if there are duplicate rrsets under
    /// the same domain.
Michal Vaner's avatar
Michal Vaner committed
272
273
274
275
    /// It should not throw other types of exceptions.
    ///
    /// \param name The domain name to be searched for.
    /// \param type The RR type to be searched for.
276
277
    /// \param target If target is not NULL, insert all RRs under the domain
    /// into it.
278
    /// \param options The search options.
Michal Vaner's avatar
Michal Vaner committed
279
280
    /// \return A \c FindResult object enclosing the search result (see above).
    virtual FindResult find(const isc::dns::Name& name,
281
                            const isc::dns::RRType& type,
282
                            isc::dns::RRsetList* target = NULL,
283
                            const FindOptions options
Jelte Jansen's avatar
Jelte Jansen committed
284
                            = FIND_DEFAULT) = 0;
285
286
287

    /// \brief Get previous name in the zone
    ///
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
288
    /// Gets the previous name in the DNSSEC order. This can be used
289
    /// to find the correct NSEC records for proving nonexistence
290
291
292
293
294
295
    /// of domains.
    ///
    /// The concrete implementation might throw anything it thinks appropriate,
    /// however it is recommended to stick to the ones listed here. The user
    /// of this method should be able to handle any exceptions.
    ///
296
297
    /// This method does not include under-zone-cut data (glue data).
    ///
298
299
300
301
302
    /// \param query The name for which one we look for a previous one. The
    ///     queried name doesn't have to exist in the zone.
    /// \return The preceding name
    ///
    /// \throw NotImplemented in case the data source backend doesn't support
303
304
    ///     DNSSEC or there is no previous in the zone (NSEC records might be
    ///     missing in the DB, the queried name is less or equal to the apex).
305
306
307
308
309
    /// \throw DataSourceError for low-level or internal datasource errors
    ///     (like broken connection to database, wrong data living there).
    /// \throw std::bad_alloc For allocation errors.
    virtual isc::dns::Name findPreviousName(const isc::dns::Name& query)
        const = 0;
Michal Vaner's avatar
Michal Vaner committed
310
311
312
    //@}
};

313
314
315
316
317
318
319
320
321
/// \brief Operator to combine FindOptions
///
/// We would need to manually static-cast the options if we put or
/// between them, which is undesired with bit-flag options. Therefore
/// we hide the cast here, which is the simplest solution and it still
/// provides reasonable level of type safety.
inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
                                          ZoneFinder::FindOptions b)
{
322
323
    return (static_cast<ZoneFinder::FindOptions>(static_cast<unsigned>(a) |
                                                 static_cast<unsigned>(b)));
324
325
}

326
327
/// \brief A pointer-like type pointing to a \c ZoneFinder object.
typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
Michal Vaner's avatar
Michal Vaner committed
328

329
330
/// \brief A pointer-like type pointing to a \c ZoneFinder object.
typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
Michal Vaner's avatar
Michal Vaner committed
331

332
/// The base class to make updates to a single zone.
333
334
335
336
///
/// On construction, each derived class object will start a "transaction"
/// for making updates to a specific zone (this means a constructor of
/// a derived class would normally take parameters to identify the zone
JINMEI Tatuya's avatar
JINMEI Tatuya committed
337
/// to be updated).  The underlying realization of a "transaction" will differ
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/// for different derived classes; if it uses a general purpose database
/// as a backend, it will involve performing some form of "begin transaction"
/// statement for the database.
///
/// Updates (adding or deleting RRs) are made via \c addRRset() and
/// \c deleteRRset() methods.  Until the \c commit() method is called the
/// changes are local to the updater object.  For example, they won't be
/// visible via a \c ZoneFinder object except the one returned by the
/// updater's own \c getFinder() method.  The \c commit() completes the
/// transaction and makes the changes visible to others.
///
/// This class does not provide an explicit "rollback" interface.  If
/// something wrong or unexpected happens during the updates and the
/// caller wants to cancel the intermediate updates, the caller should
/// simply destruct the updater object without calling \c commit().
/// The destructor is supposed to perform the "rollback" operation,
/// depending on the internal details of the derived class.
///
/// \note This initial implementation provides a quite simple interface of
/// adding and deleting RRs (see the description of the related methods).
/// It may be revisited as we gain more experiences.
359
class ZoneUpdater {
360
protected:
361
362
363
364
    /// The default constructor.
    ///
    /// This is intentionally defined as protected to ensure that this base
    /// class is never instantiated directly.
365
366
    ZoneUpdater() {}

367
public:
368
369
370
371
372
    /// The destructor
    ///
    /// Each derived class implementation must ensure that if \c commit()
    /// has not been performed by the time of the call to it, then it
    /// "rollbacks" the updates made via the updater so far.
373
374
    virtual ~ZoneUpdater() {}

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
    /// Return a finder for the zone being updated.
    ///
    /// The returned finder provides the functionalities of \c ZoneFinder
    /// for the zone as updates are made via the updater.  That is, before
    /// making any update, the finder will be able to find all RRsets that
    /// exist in the zone at the time the updater is created.  If RRsets
    /// are added or deleted via \c addRRset() or \c deleteRRset(),
    /// this finder will find the added ones or miss the deleted ones
    /// respectively.
    ///
    /// The finder returned by this method is effective only while the updates
    /// are performed, i.e., from the construction of the corresponding
    /// updater until \c commit() is performed or the updater is destructed
    /// without commit.  The result of a subsequent call to this method (or
    /// the use of the result) after that is undefined.
390
    ///
391
    /// \return A reference to a \c ZoneFinder for the updated zone
392
    virtual ZoneFinder& getFinder() = 0;
393

394
395
396
397
398
399
400
401
    /// Add an RRset to a zone via the updater
    ///
    /// This may be revisited in a future version, but right now the intended
    /// behavior of this method is simple: It "naively" adds the specified
    /// RRset to the zone specified on creation of the updater.
    /// It performs minimum level of validation on the specified RRset:
    /// - Whether the RR class is identical to that for the zone to be updated
    /// - Whether the RRset is not empty, i.e., it has at least one RDATA
402
403
    /// - Whether the RRset is not associated with an RRSIG, i.e.,
    ///   whether \c getRRsig() on the RRset returns a NULL pointer.
404
405
406
407
408
409
410
411
412
413
    ///
    /// and otherwise does not check any oddity.  For example, it doesn't
    /// check whether the owner name of the specified RRset is a subdomain
    /// of the zone's origin; it doesn't care whether or not there is already
    /// an RRset of the same name and RR type in the zone, and if there is,
    /// whether any of the existing RRs have duplicate RDATA with the added
    /// ones.  If these conditions matter the calling application must examine
    /// the existing data beforehand using the \c ZoneFinder returned by
    /// \c getFinder().
    ///
414
415
416
417
418
419
    /// The validation requirement on the associated RRSIG is temporary.
    /// If we find it more reasonable and useful to allow adding a pair of
    /// RRset and its RRSIG RRset as we gain experiences with the interface,
    /// we may remove this restriction.  Until then we explicitly check it
    /// to prevent accidental misuse.
    ///
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
    /// Conceptually, on successful call to this method, the zone will have
    /// the specified RRset, and if there is already an RRset of the same
    /// name and RR type, these two sets will be "merged".  "Merged" means
    /// that a subsequent call to \c ZoneFinder::find() for the name and type
    /// will result in success and the returned RRset will contain all
    /// previously existing and newly added RDATAs with the TTL being the
    /// minimum of the two RRsets.  The underlying representation of the
    /// "merged" RRsets may vary depending on the characteristic of the
    /// underlying data source.  For example, if it uses a general purpose
    /// database that stores each RR of the same RRset separately, it may
    /// simply be a larger sets of RRs based on both the existing and added
    /// RRsets; the TTLs of the RRs may be different within the database, and
    /// there may even be duplicate RRs in different database rows.  As long
    /// as the RRset returned via \c ZoneFinder::find() conforms to the
    /// concept of "merge", the actual internal representation is up to the
    /// implementation.
436
    ///
437
438
439
    /// This method must not be called once commit() is performed.  If it
    /// calls after \c commit() the implementation must throw a
    /// \c DataSourceError exception.
440
    ///
441
442
443
444
    /// If journaling was requested when getting this updater, it might reject
    /// to add the RRset if the squence doesn't look like and IXFR. In such
    /// such case isc::BadValue is thrown.
    ///
445
446
    /// \todo As noted above we may have to revisit the design details as we
    /// gain experiences:
447
    ///
448
449
450
451
452
453
454
455
456
457
    /// - we may want to check (and maybe reject) if there is already a
    /// duplicate RR (that has the same RDATA).
    /// - we may want to check (and maybe reject) if there is already an
    /// RRset of the same name and RR type with different TTL
    /// - we may even want to check if there is already any RRset of the
    /// same name and RR type.
    /// - we may want to add an "options" parameter that can control the
    /// above points
    /// - we may want to have this method return a value containing the
    /// information on whether there's a duplicate, etc.
458
    ///
459
460
    /// \exception DataSourceError Called after \c commit(), RRset is invalid
    /// (see above), internal data source error
461
462
    /// \exception isc::BadValue Journaling is enabled and the current RRset
    ///   doesn't fit into the IXFR sequence (see above).
463
464
465
    /// \exception std::bad_alloc Resource allocation failure
    ///
    /// \param rrset The RRset to be added
466
467
    virtual void addRRset(const isc::dns::RRset& rrset) = 0;

468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    /// Delete an RRset from a zone via the updater
    ///
    /// Like \c addRRset(), the detailed semantics and behavior of this method
    /// may have to be revisited in a future version.  The following are
    /// based on the initial implementation decisions.
    ///
    /// On successful completion of this method, it will remove from the zone
    /// the RRs of the specified owner name and RR type that match one of
    /// the RDATAs of the specified RRset.  There are several points to be
    /// noted:
    /// - Existing RRs that don't match any of the specified RDATAs will
    ///   remain in the zone.
    /// - Any RRs of the specified RRset that doesn't exist in the zone will
    ///   simply be ignored; the implementation of this method is not supposed
    ///   to check that condition.
    /// - The TTL of the RRset is ignored; matching is only performed by
    ///   the owner name, RR type and RDATA
    ///
    /// Ignoring the TTL may not look sensible, but it's based on the
    /// observation that it will result in more intuitive result, especially
    /// when the underlying data source is a general purpose database.
    /// See also \c DatabaseAccessor::deleteRecordInZone() on this point.
    /// It also matches the dynamic update protocol (RFC2136), where TTLs
    /// are ignored when deleting RRs.
    ///
    /// \note Since the TTL is ignored, this method could take the RRset
    /// to be deleted as a tuple of name, RR type, and a list of RDATAs.
    /// But in practice, it's quite likely that the caller has the RRset
    /// in the form of the \c RRset object (e.g., extracted from a dynamic
    /// update request message), so this interface would rather be more
    /// convenient.  If it turns out not to be true we can change or extend
    /// the method signature.
    ///
    /// This method performs minimum level of validation on the specified
    /// RRset:
    /// - Whether the RR class is identical to that for the zone to be updated
    /// - Whether the RRset is not empty, i.e., it has at least one RDATA
505
506
    /// - Whether the RRset is not associated with an RRSIG, i.e.,
    ///   whether \c getRRsig() on the RRset returns a NULL pointer.
507
    ///
508
509
510
511
    /// This method must not be called once commit() is performed.  If it
    /// calls after \c commit() the implementation must throw a
    /// \c DataSourceError exception.
    ///
512
513
514
515
    /// If journaling was requested when getting this updater, it might reject
    /// to add the RRset if the squence doesn't look like and IXFR. In such
    /// such case isc::BadValue is thrown.
    ///
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
    /// \todo As noted above we may have to revisit the design details as we
    /// gain experiences:
    ///
    /// - we may want to check (and maybe reject) if some or all of the RRs
    ///   for the specified RRset don't exist in the zone
    /// - we may want to allow an option to "delete everything" for specified
    ///   name and/or specified name + RR type.
    /// - as mentioned above, we may want to include the TTL in matching the
    ///   deleted RRs
    /// - we may want to add an "options" parameter that can control the
    ///   above points
    /// - we may want to have this method return a value containing the
    ///   information on whether there's any RRs that are specified but don't
    ///   exit, the number of actually deleted RRs, etc.
    ///
    /// \exception DataSourceError Called after \c commit(), RRset is invalid
    /// (see above), internal data source error
533
534
    /// \exception isc::BadValue Journaling is enabled and the current RRset
    ///   doesn't fit into the IXFR sequence (see above).
535
536
537
    /// \exception std::bad_alloc Resource allocation failure
    ///
    /// \param rrset The RRset to be deleted
538
539
    virtual void deleteRRset(const isc::dns::RRset& rrset) = 0;

540
541
542
543
544
545
546
547
548
    /// Commit the updates made in the updater to the zone
    ///
    /// This method completes the "transaction" started at the creation
    /// of the updater.  After successful completion of this method, the
    /// updates will be visible outside the scope of the updater.
    /// The actual internal behavior will defer for different derived classes.
    /// For a derived class with a general purpose database as a backend,
    /// for example, this method would perform a "commit" statement for the
    /// database.
549
550
551
    ///
    /// This operation can only be performed at most once.  A duplicate call
    /// must result in a DatasourceError exception.
552
553
554
    ///
    /// \exception DataSourceError Duplicate call of the method,
    /// internal data source error
555
    virtual void commit() = 0;
556
557
558
559
560
561
562
};

/// \brief A pointer-like type pointing to a \c ZoneUpdater object.
typedef boost::shared_ptr<ZoneUpdater> ZoneUpdaterPtr;

} // end of datasrc
} // end of isc
Michal Vaner's avatar
Michal Vaner committed
563

564
565
566
567
568
#endif  // __ZONE_H

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