1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
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
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
// Copyright (C) 2013-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef NCR_MSG_H
#define NCR_MSG_H

/// @file ncr_msg.h
/// @brief This file provides the classes needed to embody, compose, and
/// decompose DNS update requests that are sent by DHCP-DDNS clients to
/// DHCP-DDNS. These requests are referred to as NameChangeRequests.

#include <cc/data.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dns/name.h>
#include <dns/time_utils.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>

#include <time.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp_ddns {

/// @brief Exception thrown when NameChangeRequest marshalling error occurs.
class NcrMessageError : public isc::Exception {
public:
    NcrMessageError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Exception thrown when there is an error occurred during computation
/// of the DHCID.
class DhcidRdataComputeError : public isc::Exception {
public:
    DhcidRdataComputeError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Defines the types of DNS updates that can be requested.
enum NameChangeType {
  CHG_ADD,
  CHG_REMOVE
};

/// @brief Defines the runtime processing status values for requests.
enum NameChangeStatus  {
  ST_NEW,
  ST_PENDING,
  ST_COMPLETED,
  ST_FAILED
};

/// @brief Defines the list of data wire formats supported.
enum NameChangeFormat {
  FMT_JSON
};

// DDNS Conflict resolution modes
enum ConflictResolutionMode {
   CHECK_WITH_DHCID,
   NO_CHECK_WITH_DHCID,
   CHECK_EXISTS_WITH_DHCID,
   NO_CHECK_WITHOUT_DHCID
};

/// @brief Function which converts labels to  NameChangeFormat enum values.
///
/// @param fmt_str text to convert to an enum.
/// Valid string values: "JSON"
///
/// @return NameChangeFormat value which maps to the given string.
///
/// @throw isc::BadValue if given a string value which does not map to an
/// enum value.
extern NameChangeFormat stringToNcrFormat(const std::string& fmt_str);

/// @brief Function which converts NameChangeFormat enums to text labels.
///
/// @param format enum value to convert to label
///
/// @return std:string containing the text label if the value is valid, or
/// "UNKNOWN" if not.
extern std::string ncrFormatToString(NameChangeFormat format);

/// @brief Function which converts string to ConflictResolutionMode enum values.
///
/// @param mode_str text to convert to an enum.
/// Valid string values: "check-with-dhcid", "no-check-with-dhcid",
///                      "check-exists-with-dhcid", "no-check-without-dhcid"
///
/// @return ConflictResolutionMode value which maps to the given string.
///
/// @throw isc::BadValue if given a string value which does not map to an
/// enum value.
ConflictResolutionMode StringToConflictResolutionMode(const std::string& mode_str);

/// @brief Function which converts ConflictResolutionMode enums to text labels.
///
/// @param mode ConflictResolutionMode enum value to convert to string.
///
/// @return std:string containing the text label if the value is valid, or
/// "unknown" if not.
std::string ConflictResolutionModeToString(const ConflictResolutionMode& mode);

/// @brief Container class for handling the DHCID value within a
/// NameChangeRequest. It provides conversion to and from string for JSON
/// formatting, but stores the data internally as unsigned bytes.
class D2Dhcid {
public:
    /// @brief Default constructor
    D2Dhcid();

    /// @brief Constructor - Creates a new instance, populated by converting
    /// a given string of digits into an array of unsigned bytes.
    ///
    /// @param data is a string of hexadecimal digits. The format is simply
    /// a contiguous stream of digits, with no delimiters. For example a string
    /// containing "14A3" converts to a byte array containing:  0x14, 0xA3.
    ///
    /// @throw NcrMessageError if the input data contains non-digits
    /// or there is an odd number of digits.
    D2Dhcid(const std::string& data);

    /// @brief Constructor, creates an instance of the @c D2Dhcid from the
    /// HW address.
    ///
    /// @param hwaddr A pointer to the object encapsulating HW address.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    D2Dhcid(const isc::dhcp::HWAddrPtr& hwaddr,
            const std::vector<uint8_t>& wire_fqdn);

    /// @brief Constructor, creates an instance of the @c D2Dhcid from the
    /// client identifier carried in the Client Identifier option.
    ///
    /// @param clientid_data Holds the raw bytes representing client identifier.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    D2Dhcid(const std::vector<uint8_t>& clientid_data,
            const std::vector<uint8_t>& wire_fqdn);

    /// @brief Constructor, creates an instance of the @c D2Dhcid from the
    /// @c isc::dhcp::DUID.
    ///
    /// @param duid An object representing DUID.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    D2Dhcid(const isc::dhcp::DUID& duid,
            const std::vector<uint8_t>& wire_fqdn);

    /// @brief Returns the DHCID value as a string of hexadecimal digits.
    ///
    /// @return a string containing a contiguous stream of digits.
    std::string toStr() const;

    /// @brief Sets the DHCID value based on the given string.
    ///
    /// @param data is a string of hexadecimal digits. The format is simply
    /// a contiguous stream of digits, with no delimiters. For example a string
    /// containing "14A3" converts to a byte array containing:  0x14, 0xA3.
    ///
    /// @throw NcrMessageError if the input data contains non-digits
    /// or there is an odd number of digits.
    void fromStr(const std::string& data);

    /// @brief Sets the DHCID value based on the Client Identifier.
    ///
    /// @param clientid_data Holds the raw bytes representing client identifier.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    void fromClientId(const std::vector<uint8_t>& clientid_data,
                      const std::vector<uint8_t>& wire_fqdn);

    /// @brief Sets the DHCID value based on the DUID and FQDN.
    ///
    /// This function requires that the FQDN conforms to the section 3.5
    /// of the RFC4701, which says that the FQDN must be in lowercase.
    /// This function doesn't validate if it really converted.
    ///
    /// @param duid A @c isc::dhcp::DUID object encapsulating DUID.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    void fromDUID(const isc::dhcp::DUID& duid,
                  const std::vector<uint8_t>& wire_fqdn);

    /// @brief Sets the DHCID value based on the HW address and FQDN.
    ///
    /// @param hwaddr A pointer to the object encapsulating HW address.
    /// @param wire_fqdn A on-wire canonical representation of the FQDN.
    void fromHWAddr(const isc::dhcp::HWAddrPtr& hwaddr,
                    const std::vector<uint8_t>& wire_fqdn);

    /// @brief Returns a reference to the DHCID byte vector.
    ///
    /// @return a reference to the vector.
    const std::vector<uint8_t>& getBytes() const {
        return (bytes_);
    }

    /// @brief Compares two D2Dhcids for equality
    bool operator==(const D2Dhcid& other) const {
        return (this->bytes_ == other.bytes_);
    }

    /// @brief Compares two D2Dhcids for inequality
    bool operator!=(const D2Dhcid& other) const {
        return (this->bytes_ != other.bytes_);
    }

    /// @brief Compares two D2Dhcids lexically
    bool operator<(const D2Dhcid& other) const {
        return (this->bytes_ < other.bytes_);
    }

private:

    /// @brief Creates the DHCID using specified identifier.
    ///
    /// This function creates the DHCID RDATA as specified in RFC4701,
    /// section 3.5.
    ///
    /// @param identifier_type is a less significant byte of the identifier-type
    /// defined in RFC4701.
    /// @param identifier_data A buffer holding client identifier raw data -
    /// e.g. DUID, data carried in the Client Identifier option or client's
    /// HW address.
    /// @param A on-wire canonical representation of the FQDN.
    void createDigest(const uint8_t identifier_type,
                      const std::vector<uint8_t>& identifier_data,
                      const std::vector<uint8_t>& wire_fqdn);

    /// @brief Storage for the DHCID value in unsigned bytes.
    std::vector<uint8_t> bytes_;
};

std::ostream&
operator<<(std::ostream& os, const D2Dhcid& dhcid);

class NameChangeRequest;
/// @brief Defines a pointer to a NameChangeRequest.
typedef boost::shared_ptr<NameChangeRequest> NameChangeRequestPtr;

/// @brief Defines a map of Elements, keyed by their string name.
typedef std::map<std::string, isc::data::ConstElementPtr> ElementMap;

/// @brief  Represents a DHCP-DDNS client request.
/// This class is used by DHCP-DDNS clients (e.g. DHCP4, DHCP6) to
/// request DNS updates.  Each message contains a single DNS change (either an
/// add/update or a remove) for a single FQDN.  It provides marshalling services
/// for moving instances to and from the wire.  Currently, the only format
/// supported is JSON detailed here isc::dhcp_ddns::NameChangeRequest::fromJSON
/// The class provides an interface such that other formats can be readily
/// supported.
class NameChangeRequest {
public:
    /// @brief Default Constructor.
    ///
    /// @todo Currently, fromWire makes use of the ability to create an empty
    /// NameChangeRequest and then builds it bit by bit.  This means that it
    /// is technically possible to create one and attempt to use in ways
    /// other than intended and its invalid content may or may not be handled
    /// gracefully by consuming code.  It might be wise to revisit this
    /// structuring such that we do not use a default constructor and only
    /// allow valid instantiations.
    NameChangeRequest();

    /// @brief Constructor.  Full constructor, which provides parameters for
    /// all of the class members, except status.
    ///
    /// @param change_type the type of change (Add or Update)
    /// @param forward_change indicates if this change should be sent to forward
    /// DNS servers.
    /// @param reverse_change indicates if this change should be sent to reverse
    /// DNS servers.
    /// @param fqdn the domain name whose pointer record(s) should be
    /// updated.
    /// @param ip_address the ip address leased to the given FQDN.
    /// @param dhcid the lease client's unique DHCID.
    /// @param lease_expires_on a timestamp containing the date/time the lease
    /// expires.
    /// @param lease_length the amount of time in seconds for which the
    /// lease is valid (TTL).
    /// @param conflict_resolution_mode conflict resolution mode to use, defaults
    /// to CHECK_WITH_DHCID.
    /// (per RFC 4703) is enabled.
    NameChangeRequest(const NameChangeType change_type,
                      const bool forward_change, const bool reverse_change,
                      const std::string& fqdn, const std::string& ip_address,
                      const D2Dhcid& dhcid,
                      const uint64_t lease_expires_on,
                      const uint32_t lease_length,
                      const ConflictResolutionMode
                      conflict_resolution_mode = CHECK_WITH_DHCID);

    /// @brief Static method for creating a NameChangeRequest from a
    /// buffer containing a marshalled request in a given format.
    ///
    /// When the format is:
    ///
    /// JSON: The buffer is expected to contain a two byte unsigned integer
    /// which specified the length of the JSON text; followed by the JSON
    /// text itself.  This method attempts to extract "length" characters
    /// from the buffer. This data is used to create a character string that
    /// is than treated as JSON which is then parsed into the data needed
    /// to create a request instance.
    ///
    /// (NOTE currently only JSON is supported.)
    ///
    /// @param format indicates the data format to use
    /// @param buffer is the input buffer containing the marshalled request
    ///
    /// @return a pointer to the new NameChangeRequest
    ///
    /// @throw NcrMessageError if an error occurs creating new
    /// request.
    static NameChangeRequestPtr fromFormat(const NameChangeFormat format,
                                           isc::util::InputBuffer& buffer);

    /// @brief Instance method for marshalling the contents of the request
    /// into the given buffer in the given format.
    ///
    /// When the format is:
    ///
    /// JSON: Upon completion, the buffer will contain a two byte unsigned
    /// integer which specifies the length of the JSON text; followed by the
    /// JSON text itself. The JSON text contains the names and values for all
    /// the request data needed to reassemble the request on the receiving
    /// end. The JSON text in the buffer is NOT null-terminated.  The format
    /// is identical that described under
    /// isc::dhcp_ddns::NameChangeRequest::fromJSON
    ///
    /// (NOTE currently only JSON is supported.)
    ///
    /// @param format indicates the data format to use
    /// @param buffer is the output buffer to which the request should be
    /// marshalled.
    void toFormat(const NameChangeFormat format,
                  isc::util::OutputBuffer& buffer) const;

    /// @brief Static method for creating a NameChangeRequest from a
    /// string containing a JSON rendition of a request.
    ///
    /// The JSON expected is described below.  Note that a request must be
    /// enclosed within curly brackets "{..}" and that whitespace is optional
    /// (it is used in the following examples for clarity).
    ///
    /// @code
    ///     {
    ///      "change-type" : <integer>,
    ///      "forward-change" : <boolean>,
    ///      "reverse-change" : <boolean>,
    ///      "fqdn" : "<fqdn>",
    ///      "ip-address" : "<address>",
    ///      "dhcid" : "<hex_string>",
    ///      "lease-expires-on" : "<yyyymmddHHMMSS>",
    ///      "lease-length" : <secs>,
    ///      "use-conflict-resolution": <boolean>
    ///     }
    /// @endcode
    ///
    /// - change-type - indicates whether this request is to add or update
    ///   DNS entries or to remove them.  The value is an integer and is
    ///   0 for add/update and 1 for remove.
    /// - forward-change - indicates whether the forward (name to
    ///   address) DNS zone should be updated.  The value is a string
    ///   representing a boolean.  It is "true" if the zone should be updated
    ///   and "false" if not. (Unlike the keyword, the boolean value is
    ///   case-insensitive.)
    /// - reverse-change - indicates whether the reverse (address to
    ///   name) DNS zone should be updated.  The value is a string
    ///   representing a boolean.  It is "true" if the zone should be updated
    ///   and "false" if not. (Unlike the keyword, the boolean value is
    ///   case-insensitive.)
    /// - fqdn - fully qualified domain name such as "myhost.example.com.".
    ///   (Note that a trailing dot will be appended if not supplied.)
    /// - ip-address - the IPv4 or IPv6 address of the client.  The value
    ///   is a string representing the IP address (e.g. "192.168.0.1" or
    ///   "2001:db8:1::2").
    /// - dhcid - identification of the DHCP client to whom the IP address has
    ///   been leased.  The value is a string containing an even number of
    ///   hexadecimal digits without delimiters such as "2C010203040A7F8E3D"
    ///   (case insensitive).
    /// - lease-expires-on - the date and time on which the lease expires.
    ///   The value is a string of the form "yyyymmddHHMMSS" where:
    ///     - yyyy - four digit year
    ///     - mm - month of year (1-12),
    ///     - dd - day of the month (1-31),
    ///     - HH - hour of the day (0-23)
    ///     - MM - minutes of the hour (0-59)
    ///     - SS - seconds of the minute (0-59)
    /// - lease-length - the length of the lease in seconds.  This is an
    ///   integer and may range between 1 and 4294967295 (2^32 - 1) inclusive.
    /// - use-conflict-resolution - when true, follow RFC 4703 which uses
    ///   DHCID records to prohibit multiple clients from updating an FQDN
    ///
    /// Examples:
    ///
    /// Removal of an IPv4 address from the forward DNS zone only:
    ///
    /// @code
    ///  {
    ///     "change-type" : 1,
    ///     "forward-change" : true,
    ///     "reverse-change" : false,
    ///     "fqdn" : "myhost.example.com.",
    ///     "ip-address" : "192.168.2.1" ,
    ///     "dhcid" : "010203040A7F8E3D" ,
    ///     "lease-expires-on" : "20130121132405",
    ///     "lease-length" : 1300,
    ///     "use-conflict-resolution": true
    ///  }
    /// @endcode
    ///
    /// Addition of an IPv6 address to both forward and reverse DNS zones:
    ///
    /// @code
    ///  {
    ///     "change-type" : 0,
    ///     "forward-change" : true,
    ///     "reverse-change" : true,
    ///     "fqdn" : "someother.example.com.",
    ///     "ip-address" : "2001::db8:1::2",
    ///     "dhcid" : "010203040A7F8E3D" , "
    ///     "lease-expires-on" : "20130121132405",
    ///     "lease-length" : 27400,
    ///     "use-conflict-resolution": true
    ///   }
    /// @endcode
    ///
    /// @param json is a string containing the JSON text
    ///
    /// @return a pointer to the new NameChangeRequest
    ///
    /// @throw NcrMessageError if an error occurs creating new request.
    static NameChangeRequestPtr fromJSON(const std::string& json);

    /// @brief Instance method for marshalling the contents of the request
    /// into a string of JSON text.
    ///
    /// @return a string containing the JSON rendition of the request
    std::string toJSON() const;

    /// @brief Validates the content of a populated request.  This method is
    /// used by both the full constructor and from-wire marshalling to ensure
    /// that the request is content valid.  Currently it enforces the
    /// following rules:
    ///
    ///  - FQDN must not be blank.
    ///  - The IP address must be a valid address.
    ///  - The DHCID must not be blank.
    ///  - The lease expiration date must be a valid date/time.
    ///  - That at least one of the two direction flags, forward change and
    ///    reverse change is true.
    ///
    /// @todo This is an initial implementation which provides a minimal amount
    /// of validation.  FQDN, DHCID, and IP Address members are all currently
    /// strings, these may be replaced with richer classes.
    ///
    /// @throw NcrMessageError if the request content violates any
    /// of the validation rules.
    void validateContent();

    /// @brief Fetches the request change type.
    ///
    /// @return the change type
    NameChangeType getChangeType() const {
        return (change_type_);
    }

    /// @brief Sets the change type to the given value.
    ///
    /// @param value is the NameChangeType value to assign to the request.
    void setChangeType(const NameChangeType value);

    /// @brief Sets the change type to the value of the given Element.
    ///
    /// @param element is an integer Element containing the change type value.
    ///
    /// @throw NcrMessageError if the element is not an integer
    /// Element or contains an invalid value.
    void setChangeType(isc::data::ConstElementPtr element);

    /// @brief Checks forward change flag.
    ///
    /// @return a true if the forward change flag is true.
    bool isForwardChange() const {
        return (forward_change_);
    }

    /// @brief Sets the forward change flag to the given value.
    ///
    /// @param value contains the new value to assign to the forward change
    /// flag
    void setForwardChange(const bool value);

    /// @brief Sets the forward change flag to the value of the given Element.
    ///
    /// @param element is a boolean Element containing the forward change flag
    /// value.
    ///
    /// @throw NcrMessageError if the element is not a boolean
    /// Element
    void setForwardChange(isc::data::ConstElementPtr element);

    /// @brief Checks reverse change flag.
    ///
    /// @return a true if the reverse change flag is true.
    bool isReverseChange() const {
        return (reverse_change_);
    }

    /// @brief Sets the reverse change flag to the given value.
    ///
    /// @param value contains the new value to assign to the reverse change
    /// flag
    void setReverseChange(const bool value);

    /// @brief Sets the reverse change flag to the value of the given Element.
    ///
    /// @param element is a boolean Element containing the reverse change flag
    /// value.
    ///
    /// @throw NcrMessageError if the element is not a boolean
    /// Element
    void setReverseChange(isc::data::ConstElementPtr element);

    /// @brief Fetches the request FQDN
    ///
    /// @return a string containing the FQDN
    const std::string getFqdn() const {
        return (fqdn_);
    }

    /// @brief Sets the FQDN to the given value.
    ///
    /// @param value contains the new value to assign to the FQDN
    void setFqdn(const std::string& value);

    /// @brief Sets the FQDN to the value of the given Element.
    ///
    /// @param element is a string Element containing the FQDN
    ///
    /// @throw NcrMessageError if the element is not a string
    /// Element
    void setFqdn(isc::data::ConstElementPtr element);

    /// @brief Fetches the request IP address string.
    ///
    /// @return a string containing the IP address
    std::string getIpAddress() const {
        return (ip_io_address_.toText());
    }

    /// @brief Fetches the request IP address as an IOAddress.
    ///
    /// @return a asiolink::IOAddress containing the IP address
    const asiolink::IOAddress& getIpIoAddress() const {
        return (ip_io_address_);
    }

    /// @brief Returns true if the lease address is a IPv4 lease.
    ///
    /// @return boolean true if the lease address family is AF_INET.
    bool isV4 () const {
        return (ip_io_address_.isV4());
    }

    /// @brief Returns true if the lease address is a IPv6 lease.
    ///
    /// @return boolean true if the lease address family is AF_INET6.
    bool isV6 () const {
        return (ip_io_address_.isV6());
    }

    /// @brief Sets the IP address to the given value.
    ///
    /// @param value contains the new value to assign to the IP address
    void setIpAddress(const std::string& value);

    /// @brief Sets the IP address to the value of the given Element.
    ///
    /// @param element is a string Element containing the IP address
    ///
    /// @throw NcrMessageError if the element is not a string
    /// Element
    void setIpAddress(isc::data::ConstElementPtr element);

    /// @brief Fetches the request DHCID
    ///
    /// @return a reference to the request's D2Dhcid
    const D2Dhcid& getDhcid() const {
        return (dhcid_);
    }

    /// @brief Sets the DHCID based on the given string value.
    ///
    /// @param value is a string of hexadecimal digits. The format is simply
    /// a contiguous stream of digits, with no delimiters. For example a string
    /// containing "14A3" converts to a byte array containing:  0x14, 0xA3.
    ///
    /// @throw NcrMessageError if the input data contains non-digits
    /// or there is an odd number of digits.
    void setDhcid(const std::string& value);

    /// @brief Sets the DHCID based on the value of the given Element.
    ///
    /// @param element is a string Element containing the string of hexadecimal
    /// digits. (See setDhcid(std::string&) above.)
    ///
    /// @throw NcrMessageError if the input data contains non-digits
    /// or there is an odd number of digits.
    void setDhcid(isc::data::ConstElementPtr element);

    /// @brief Fetches the request ID.
    ///
    /// @todo Currently this is the DHCID, in the future we may add a unique ID per
    /// request to allow for correlating messages and events between the DHCP servers
    /// and the D2 server.  If we do that we shall also need to add or update other
    /// functions to: set the request ID, add it to the JSON strings, etc.  The
    /// primary purpose of this function is to provide a consistent way to identify
    /// requests for logging purposes.
    ///
    /// @return a string with the request's request ID (currently DHCID)
    std::string getRequestId() const {
        return (dhcid_.toStr());
    }

    /// @brief Fetches the request lease expiration
    ///
    /// @return the lease expiration as the number of seconds since
    /// the (00:00:00 January 1, 1970)
    uint64_t getLeaseExpiresOn() const {
        return (lease_expires_on_);
    }

    /// @brief Fetches the request lease expiration as string.
    ///
    /// The format of the string returned is:
    ///
    ///    YYYYMMDDHHmmSS
    ///
    /// Example: 18:54:54 June 26, 2013 would be: 20130626185455
    /// NOTE This is always UTC time.
    ///
    /// @return a ISO date-time string of the lease expiration.
    std::string getLeaseExpiresOnStr() const;

    /// @brief Sets the lease expiration based on the given string.
    ///
    /// @param value is an date-time string from which to set the
    /// lease expiration. The format of the input is:
    ///
    ///    YYYYMMDDHHmmSS
    ///
    /// Example: 18:54:54 June 26, 2013 would be: 20130626185455
    /// NOTE This is always UTC time.
    ///
    /// @throw NcrMessageError if the ISO string is invalid.
    void setLeaseExpiresOn(const std::string& value);

    /// @brief Sets the lease expiration based on the given Element.
    ///
    /// @param element is string Element containing a date-time string.
    ///
    /// @throw NcrMessageError if the element is not a string
    /// Element, or if the element value is an invalid date-time string.
    void setLeaseExpiresOn(isc::data::ConstElementPtr element);

    /// @brief Fetches the request lease length.
    ///
    /// @return an integer containing the lease length
    uint32_t getLeaseLength() const {
        return (lease_length_);
    }

    /// @brief Sets the lease length to the given value.
    ///
    /// @param value contains the new value to assign to the lease length
    void setLeaseLength(const uint32_t value);

    /// @brief Sets the lease length to the value of the given Element.
    ///
    /// @param element is a integer Element containing the lease length
    ///
    /// @throw NcrMessageError if the element is not a string
    /// Element
    void setLeaseLength(isc::data::ConstElementPtr element);

    /// @brief Fetches the conflict resolution mode
    ///
    /// @return a true if the conflict resolution is enabled.
    ConflictResolutionMode getConflictResolutionMode() const {
        return (conflict_resolution_mode_);
    }

    /// @brief Sets the conflict resolution mode to the given value.
    ///
    /// @param value contains the new value to assign to the conflict
    /// resolution mode
    void setConflictResolutionMode(const ConflictResolutionMode value);

    /// @brief Sets the conflict resolution mode to the value of the given Element.
    ///
    /// @param element is a enum Element containing the conflict resolution mode
    /// value.
    ///
    /// @throw NcrMessageError if the element is not an enum Element.
    void setConflictResolutionMode(isc::data::ConstElementPtr element);

    /// @brief Sets the conflict resolution mode based on the value of
    /// the given boolean Element.
    ///
    /// This function is used to translate use-conflict-resolution sent by
    /// older versions of Kea.
    ///
    /// @param element is a boolean Element containing the conflict resolution flag
    /// value.
    ///
    /// @throw NcrMessageError if the element is not a boolean
    /// Element
    void translateUseConflictResolution(isc::data::ConstElementPtr element);

    /// @brief Fetches the request status.
    ///
    /// @return the request status as a NameChangeStatus
    NameChangeStatus getStatus() const {
        return (status_);
    }

    /// @brief Sets the request status to the given value.
    ///
    /// @param value contains the new value to assign to request status
    void setStatus(const NameChangeStatus value);

    /// @brief Given a name, finds and returns an element from a map of
    /// elements.
    ///
    /// @param name is the name of the desired element
    /// @param element_map is the map of elements to search
    ///
    /// @return a pointer to the element if located
    /// @throw NcrMessageError if the element cannot be found within
    /// the map
    isc::data::ConstElementPtr getElement(const std::string& name,
                                          const ElementMap& element_map) const;

    /// @brief Returns a text rendition of the contents of the request.
    /// This method is primarily for logging purposes.
    ///
    /// @return a string containing the text.
    std::string toText() const;

    bool operator == (const NameChangeRequest& b) const;
    bool operator != (const NameChangeRequest& b) const;

private:
    /// @brief Denotes the type of this change as either an Add or a Remove.
    NameChangeType change_type_;

    /// @brief Indicates if this change should sent to forward DNS servers.
    bool forward_change_;

    /// @brief Indicates if this change should sent to reverse DNS servers.
    bool reverse_change_;

    /// @brief The domain name whose DNS entry(ies) are to be updated.
    /// @todo Currently, this is a std::string but may be replaced with
    /// dns::Name which provides additional validation and domain name
    /// manipulation.
    std::string fqdn_;

    /// @brief The ip address leased to the FQDN as an IOAddress.
    ///
    /// The lease address is used in many places, sometimes as a string
    /// and sometimes as an IOAddress.  To avoid converting back and forth
    /// continually over the life span of an NCR, we do it once when the
    /// ip address is actually set.
    asiolink::IOAddress ip_io_address_;

    /// @brief The lease client's unique DHCID.
    /// @todo Currently, this is uses D2Dhcid it but may be replaced with
    /// dns::DHCID which provides additional validation.
    D2Dhcid dhcid_;

    /// @brief The date-time the lease expires.
    uint64_t lease_expires_on_;

    /// @brief The amount of time in seconds for which the lease is valid (TTL).
    uint32_t lease_length_;

    /// @brief Indicates the conflict resolution mode.
    ConflictResolutionMode conflict_resolution_mode_;

    /// @brief The processing status of the request.  Used internally.
    NameChangeStatus status_;
};


}; // end of isc::dhcp_ddns namespace
}; // end of isc namespace

#endif