123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <dhcp_ddns/ncr_msg.h>
- #include <dhcp/duid.h>
- #include <util/time_utilities.h>
- #include <gtest/gtest.h>
- #include <algorithm>
- using namespace std;
- using namespace isc;
- using namespace isc::dhcp_ddns;
- using namespace isc::dhcp;
- namespace {
- /// @brief Defines a list of valid JSON NameChangeRequest renditions.
- /// They are used as input to test conversion from JSON.
- const char *valid_msgs[] =
- {
- // Valid Add.
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Valid Remove.
- "{"
- " \"change_type\" : 1 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Valid Add with IPv6 address
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"fe80::2acf:e9ff:fe12:e56f\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}"
- };
- /// @brief Defines a list of invalid JSON NameChangeRequest renditions.
- /// They are used as input to test conversion from JSON.
- const char *invalid_msgs[] =
- {
- // Invalid change type.
- "{"
- " \"change_type\" : 7 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Invalid forward change.
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : \"bogus\" , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Invalid reverse change.
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : 500 , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Forward and reverse change both false.
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : false , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Blank FQDN
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Bad IP address
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"xxxxxx\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Blank DHCID
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Odd number of digits in DHCID
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Text in DHCID
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"THIS IS BOGUS!!!\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Invalid lease expiration string
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"Wed Jun 26 13:46:46 EDT 2013\" , "
- " \"lease_length\" : 1300 "
- "}",
- // Non-integer for lease length.
- "{"
- " \"change_type\" : 0 , "
- " \"forward_change\" : true , "
- " \"reverse_change\" : false , "
- " \"fqdn\" : \"walah.walah.com\" , "
- " \"ip_address\" : \"192.168.2.1\" , "
- " \"dhcid\" : \"010203040A7F8E3D\" , "
- " \"lease_expires_on\" : \"20130121132405\" , "
- " \"lease_length\" : \"BOGUS\" "
- "}"
- };
- /// @brief Tests the NameChangeRequest constructors.
- /// This test verifies that:
- /// 1. Default constructor works.
- /// 2. "Full" constructor, when given valid parameter values, works.
- /// 3. "Full" constructor, given a blank FQDN fails
- /// 4. "Full" constructor, given an invalid IP Address FQDN fails
- /// 5. "Full" constructor, given a blank DHCID fails
- /// 6. "Full" constructor, given false for both forward and reverse fails
- TEST(NameChangeRequestTest, constructionTests) {
- // Verify the default constructor works.
- NameChangeRequestPtr ncr;
- EXPECT_NO_THROW(ncr.reset(new NameChangeRequest()));
- EXPECT_TRUE(ncr);
- // Verify that full constructor works.
- uint64_t expiry = isc::util::detail::gettimeWrapper();
- D2Dhcid dhcid("010203040A7F8E3D");
- EXPECT_NO_THROW(ncr.reset(new NameChangeRequest(
- CHG_ADD, true, true, "walah.walah.com",
- "192.168.1.101", dhcid, expiry, 1300)));
- EXPECT_TRUE(ncr);
- ncr.reset();
- // Verify blank FQDN is detected.
- EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "",
- "192.168.1.101", dhcid, expiry, 1300), NcrMessageError);
- // Verify that an invalid IP address is detected.
- EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "valid.fqdn",
- "xxx.168.1.101", dhcid, expiry, 1300), NcrMessageError);
- // Verify that a blank DHCID is detected.
- D2Dhcid blank_dhcid;
- EXPECT_THROW(NameChangeRequest(CHG_ADD, true, true, "walah.walah.com",
- "192.168.1.101", blank_dhcid, expiry, 1300), NcrMessageError);
- // Verify that one or both of direction flags must be true.
- EXPECT_THROW(NameChangeRequest(CHG_ADD, false, false, "valid.fqdn",
- "192.168.1.101", dhcid, expiry, 1300), NcrMessageError);
- }
- /// @brief Tests the basic workings of D2Dhcid to and from string conversions.
- /// It verifies that:
- /// 1. DHCID input strings must contain an even number of characters
- /// 2. DHCID input strings must contain only hexadecimal character digits
- /// 3. A valid DHCID string converts correctly.
- /// 4. Converting a D2Dhcid to a string works correctly.
- /// 5. Equality, inequality, and less-than-equal operators work.
- TEST(NameChangeRequestTest, dhcidTest) {
- D2Dhcid dhcid;
- // Odd number of digits should be rejected.
- std::string test_str = "010203040A7F8E3";
- EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError);
- // Non digit content should be rejected.
- test_str = "0102BOGUSA7F8E3D";
- EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError);
- // Verify that valid input converts into a proper byte array.
- test_str = "010203040A7F8E3D";
- ASSERT_NO_THROW(dhcid.fromStr(test_str));
- // Create a test vector of expected byte contents.
- const uint8_t bytes[] = { 0x1, 0x2, 0x3, 0x4, 0xA, 0x7F, 0x8E, 0x3D };
- std::vector<uint8_t> expected_bytes(bytes, bytes + sizeof(bytes));
- // Fetch the byte vector from the dhcid and verify if equals the expected
- // content.
- const std::vector<uint8_t>& converted_bytes = dhcid.getBytes();
- EXPECT_EQ(expected_bytes.size(), converted_bytes.size());
- EXPECT_TRUE (std::equal(expected_bytes.begin(),
- expected_bytes.begin()+expected_bytes.size(),
- converted_bytes.begin()));
- // Convert the new dhcid back to string and verify it matches the original
- // DHCID input string.
- std::string next_str = dhcid.toStr();
- EXPECT_EQ(test_str, next_str);
- // Test equality, inequality, and less-than-equal operators
- test_str="AABBCCDD";
- EXPECT_NO_THROW(dhcid.fromStr(test_str));
- D2Dhcid other_dhcid;
- EXPECT_NO_THROW(other_dhcid.fromStr(test_str));
- EXPECT_TRUE(dhcid == other_dhcid);
- EXPECT_FALSE(dhcid != other_dhcid);
- EXPECT_NO_THROW(other_dhcid.fromStr("BBCCDDEE"));
- EXPECT_TRUE(dhcid < other_dhcid);
- }
- /// Tests that DHCID is correctly created from a DUID and FQDN. The final format
- /// of the DHCID is as follows:
- /// <identifier-type> <digest-type-code> <digest>
- /// where:
- /// - identifier-type (2 octets) is 0x0002.
- /// - digest-type-code (1 octet) indicates SHA-256 hashing and is equal 0x1.
- /// - digest = SHA-256(<DUID> <FQDN>)
- /// Note: FQDN is given in the on-wire canonical format.
- TEST(NameChangeRequestTest, dhcidFromDUID) {
- D2Dhcid dhcid;
- // Create DUID.
- uint8_t duid_data[] = { 0, 1, 2, 3, 4, 5, 6 };
- DUID duid(duid_data, sizeof(duid_data));
- // Create FQDN in on-wire format: myhost.example.com. It is encoded
- // as a set of labels, each preceded by its length. The whole FQDN
- // is zero-terminated.
- const uint8_t fqdn_data[] = {
- 6, 109, 121, 104, 111, 115, 116, // myhost.
- 7, 101, 120, 97, 109, 112, 108, 101, // example.
- 3, 99, 111, 109, 0 // com.
- };
- std::vector<uint8_t> wire_fqdn(fqdn_data, fqdn_data + sizeof(fqdn_data));
- // Create DHCID.
- ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn));
- // The reference DHCID (represented as string of hexadecimal digits)
- // has been calculated using one of the online calculators.
- std::string dhcid_ref = "0002012191B7B21AF97E0E656DF887C5E2D"
- "EF30E7758A207EDF4CCB2DE8CA37066021C";
- // Make sure that the DHCID is valid.
- EXPECT_EQ(dhcid_ref, dhcid.toStr());
- }
- // Test that DHCID is correctly created when the DUID has minimal length (1).
- TEST(NameChangeRequestTest, dhcidFromMinDUID) {
- D2Dhcid dhcid;
- // Create DUID.
- uint8_t duid_data[] = { 1 };
- DUID duid(duid_data, sizeof(duid_data));
- // Create FQDN in on-wire format: myhost.example.com. It is encoded
- // as a set of labels, each preceded by its length. The whole FQDN
- // is zero-terminated.
- const uint8_t fqdn_data[] = {
- 6, 109, 121, 104, 111, 115, 116, // myhost.
- 7, 101, 120, 97, 109, 112, 108, 101, // example.
- 3, 99, 111, 109, 0 // com.
- };
- std::vector<uint8_t> wire_fqdn(fqdn_data, fqdn_data + sizeof(fqdn_data));
- // Create DHCID.
- ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn));
- // The reference DHCID (represented as string of hexadecimal digits)
- // has been calculated using one of the online calculators.
- std::string dhcid_ref = "000201F89004F73E60CAEDFF514E11CB91D"
- "1F45C8F0A55D4BC4C688484A819F8EA4074";
- // Make sure that the DHCID is valid.
- EXPECT_EQ(dhcid_ref, dhcid.toStr());
- }
- // Test that DHCID is correctly created when the DUID has maximal length (128).
- TEST(NameChangeRequestTest, dhcidFromMaxDUID) {
- D2Dhcid dhcid;
- // Create DUID.
- std::vector<uint8_t> duid_data(128, 1);
- DUID duid(&duid_data[0], duid_data.size());
- // Create FQDN in on-wire format: myhost.example.com. It is encoded
- // as a set of labels, each preceded by its length. The whole FQDN
- // is zero-terminated.
- const uint8_t fqdn_data[] = {
- 6, 109, 121, 104, 111, 115, 116, // myhost.
- 7, 101, 120, 97, 109, 112, 108, 101, // example.
- 3, 99, 111, 109, 0 // com.
- };
- std::vector<uint8_t> wire_fqdn(fqdn_data, fqdn_data + sizeof(fqdn_data));
- // Create DHCID.
- ASSERT_NO_THROW(dhcid.fromDUID(duid, wire_fqdn));
- // The reference DHCID (represented as string of hexadecimal digits)
- // has been calculated using one of the online calculators.
- std::string dhcid_ref = "00020137D8FBDC0585B44DFA03FAD2E36C6"
- "159737D545A12EFB40B0D88D110A5748234";
- // Make sure that the DHCID is valid.
- EXPECT_EQ(dhcid_ref, dhcid.toStr());
- }
- /// @brief Verifies the fundamentals of converting from and to JSON.
- /// It verifies that:
- /// 1. A NameChangeRequest can be created from a valid JSON string.
- /// 2. A valid JSON string can be created from a NameChangeRequest
- TEST(NameChangeRequestTest, basicJsonTest) {
- // Define valid JSON rendition of a request.
- std::string msg_str = "{"
- "\"change_type\":1,"
- "\"forward_change\":true,"
- "\"reverse_change\":false,"
- "\"fqdn\":\"walah.walah.com\","
- "\"ip_address\":\"192.168.2.1\","
- "\"dhcid\":\"010203040A7F8E3D\","
- "\"lease_expires_on\":\"20130121132405\","
- "\"lease_length\":1300"
- "}";
- // Verify that a NameChangeRequests can be instantiated from the
- // a valid JSON rendition.
- NameChangeRequestPtr ncr;
- ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(msg_str));
- ASSERT_TRUE(ncr);
- // Verify that the JSON string created by the new request equals the
- // original input string.
- std::string json_str = ncr->toJSON();
- EXPECT_EQ(msg_str, json_str);
- }
- /// @brief Tests a variety of invalid JSON message strings.
- /// This test iterates over a list of JSON messages, each containing a single
- /// content error. The list of messages is defined by the global array,
- /// invalid_messages. Currently that list contains the following invalid
- /// conditions:
- /// 1. Invalid change type
- /// 2. Invalid forward change
- /// 3. Invalid reverse change
- /// 4. Forward and reverse change both false
- /// 5. Invalid forward change
- /// 6. Blank FQDN
- /// 7. Bad IP address
- /// 8. Blank DHCID
- /// 9. Odd number of digits in DHCID
- /// 10. Text in DHCID
- /// 11. Invalid lease expiration string
- /// 12. Non-integer for lease length.
- /// If more permutations arise they can easily be added to the list.
- TEST(NameChangeRequestTest, invalidMsgChecks) {
- // Iterate over the list of JSON strings, attempting to create a
- // NameChangeRequest. The attempt should throw a NcrMessageError.
- int num_msgs = sizeof(invalid_msgs)/sizeof(char*);
- for (int i = 0; i < num_msgs; i++) {
- EXPECT_THROW(NameChangeRequest::fromJSON(invalid_msgs[i]),
- NcrMessageError) << "Invalid message not caught idx: "
- << i << std::endl << " text:[" << invalid_msgs[i] << "]"
- << std::endl;
- }
- }
- /// @brief Tests a variety of valid JSON message strings.
- /// This test iterates over a list of JSON messages, each containing a single
- /// valid request rendition. The list of messages is defined by the global
- /// array, valid_messages. Currently that list contains the following valid
- /// messages:
- /// 1. Valid, IPv4 Add
- /// 2. Valid, IPv4 Remove
- /// 3. Valid, IPv6 Add
- /// If more permutations arise they can easily be added to the list.
- TEST(NameChangeRequestTest, validMsgChecks) {
- // Iterate over the list of JSON strings, attempting to create a
- // NameChangeRequest. The attempt should succeed.
- int num_msgs = sizeof(valid_msgs)/sizeof(char*);
- for (int i = 0; i < num_msgs; i++) {
- EXPECT_NO_THROW(NameChangeRequest::fromJSON(valid_msgs[i]))
- << "Valid message failed, message idx: " << i
- << std::endl << " text:[" << valid_msgs[i] << "]"
- << std::endl;
- }
- }
- /// @brief Tests converting to and from JSON via isc::util buffer classes.
- /// This test verifies that:
- /// 1. A NameChangeRequest can be rendered in JSON written to an OutputBuffer
- /// 2. A InputBuffer containing a valid JSON request rendition can be used
- /// to create a NameChangeRequest.
- TEST(NameChangeRequestTest, toFromBufferTest) {
- // Define a string containing a valid JSON NameChangeRequest rendition.
- std::string msg_str = "{"
- "\"change_type\":1,"
- "\"forward_change\":true,"
- "\"reverse_change\":false,"
- "\"fqdn\":\"walah.walah.com\","
- "\"ip_address\":\"192.168.2.1\","
- "\"dhcid\":\"010203040A7F8E3D\","
- "\"lease_expires_on\":\"20130121132405\","
- "\"lease_length\":1300"
- "}";
- // Create a request from JSON directly.
- NameChangeRequestPtr ncr;
- ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(msg_str));
- // Verify that we output the request as JSON text to a buffer
- // without error.
- isc::util::OutputBuffer output_buffer(1024);
- ASSERT_NO_THROW(ncr->toFormat(FMT_JSON, output_buffer));
- // Make an InputBuffer from the OutputBuffer.
- isc::util::InputBuffer input_buffer(output_buffer.getData(),
- output_buffer.getLength());
- // Verify that we can create a new request from the InputBuffer.
- NameChangeRequestPtr ncr2;
- ASSERT_NO_THROW(ncr2 =
- NameChangeRequest::fromFormat(FMT_JSON, input_buffer));
- // Convert the new request to JSON directly.
- std::string final_str = ncr2->toJSON();
- // Verify that the final string matches the original.
- ASSERT_EQ(final_str, msg_str);
- }
- } // end of anonymous namespace
|