1 // Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 #include <dhcp/option_data_types.h>
9 #include <gtest/gtest.h>
10 #include <utility>
11 
12 using namespace isc;
13 using namespace isc::asiolink;
14 using namespace isc::dhcp;
15 
16 namespace {
17 
18 /// @brief Default (zero) prefix tuple.
19 const PrefixTuple
20 ZERO_PREFIX_TUPLE(std::make_pair(PrefixLen(0),
21                                  IOAddress(IOAddress::IPV6_ZERO_ADDRESS())));
22 
23 /// @brief Test class for option data type utilities.
24 class OptionDataTypesTest : public ::testing::Test {
25 public:
26 
27     /// @brief Constructor.
OptionDataTypesTest()28     OptionDataTypesTest() { }
29 
30     /// @brief Write IP address into a buffer.
31     ///
32     /// @param address address to be written.
33     /// @param [out] buf output buffer.
writeAddress(const asiolink::IOAddress & address,std::vector<uint8_t> & buf)34     void writeAddress(const asiolink::IOAddress& address,
35                       std::vector<uint8_t>& buf) {
36         const std::vector<uint8_t>& vec = address.toBytes();
37         buf.insert(buf.end(), vec.begin(), vec.end());
38     }
39 
40     /// @brief Write integer (signed or unsigned) into a buffer.
41     ///
42     /// @param value integer value.
43     /// @param [out] buf output buffer.
44     /// @tparam integer type.
45     template<typename T>
writeInt(T value,std::vector<uint8_t> & buf)46     void writeInt(T value, std::vector<uint8_t>& buf) {
47         switch (sizeof(T)) {
48         case 4:
49             buf.push_back((value >> 24) & 0xFF);
50             /* falls through */
51         case 3:
52             buf.push_back((value >> 16) & 0xFF);
53             /* falls through */
54         case 2:
55             buf.push_back((value >> 8) & 0xFF);
56             /* falls through */
57         case 1:
58             buf.push_back(value & 0xFF);
59             break;
60         default:
61             // This loop is incorrectly compiled by some old g++?!
62             for (int i = 0; i < sizeof(T); ++i) {
63                 buf.push_back(value >> ((sizeof(T) - i - 1) * 8) & 0xFF);
64             }
65         }
66     }
67 
68     /// @brief Write a string into a buffer.
69     ///
70     /// @param value string to be written into a buffer.
71     /// @param buf output buffer.
writeString(const std::string & value,std::vector<uint8_t> & buf)72     void writeString(const std::string& value,
73                      std::vector<uint8_t>& buf) {
74         buf.resize(buf.size() + value.size());
75         std::copy_backward(value.c_str(), value.c_str() + value.size(),
76                            buf.end());
77     }
78 };
79 
80 // The goal of this test is to verify that the getLabelCount returns the
81 // correct number of labels in the domain name specified as a string
82 // parameter.
TEST_F(OptionDataTypesTest,getLabelCount)83 TEST_F(OptionDataTypesTest, getLabelCount) {
84     EXPECT_EQ(0, OptionDataTypeUtil::getLabelCount(""));
85     EXPECT_EQ(1, OptionDataTypeUtil::getLabelCount("."));
86     EXPECT_EQ(2, OptionDataTypeUtil::getLabelCount("example"));
87     EXPECT_EQ(3, OptionDataTypeUtil::getLabelCount("example.com"));
88     EXPECT_EQ(3, OptionDataTypeUtil::getLabelCount("example.com."));
89     EXPECT_EQ(4, OptionDataTypeUtil::getLabelCount("myhost.example.com"));
90     EXPECT_THROW(OptionDataTypeUtil::getLabelCount(".abc."),
91                  isc::dhcp::BadDataTypeCast);
92 }
93 
94 // The goal of this test is to verify that an IPv4 address being
95 // stored in a buffer (wire format) can be read into IOAddress
96 // object.
TEST_F(OptionDataTypesTest,readAddress)97 TEST_F(OptionDataTypesTest, readAddress) {
98     // Create some IPv4 address.
99     asiolink::IOAddress address("192.168.0.1");
100     // And store it in a buffer in a wire format.
101     std::vector<uint8_t> buf;
102     writeAddress(address, buf);
103 
104     // Now, try to read the IP address with a utility function
105     // being under test.
106     asiolink::IOAddress address_out("127.0.0.1");
107     EXPECT_NO_THROW(address_out = OptionDataTypeUtil::readAddress(buf, AF_INET));
108 
109     // Check that the read address matches address that
110     // we used as input.
111     EXPECT_EQ(address, address_out);
112 
113     // Check that an attempt to read the buffer as IPv6 address
114     // causes an error as the IPv6 address needs at least 16 bytes
115     // long buffer.
116     EXPECT_THROW(
117         OptionDataTypeUtil::readAddress(buf, AF_INET6),
118         isc::dhcp::BadDataTypeCast
119     );
120 
121     buf.clear();
122 
123     // Do another test like this for IPv6 address.
124     address = asiolink::IOAddress("2001:db8:1:0::1");
125     writeAddress(address, buf);
126     EXPECT_NO_THROW(address_out = OptionDataTypeUtil::readAddress(buf, AF_INET6));
127     EXPECT_EQ(address, address_out);
128 
129     // Truncate the buffer and expect an error to be reported when
130     // trying to read it.
131     buf.resize(buf.size() - 1);
132     EXPECT_THROW(
133         OptionDataTypeUtil::readAddress(buf, AF_INET6),
134         isc::dhcp::BadDataTypeCast
135     );
136 }
137 
138 // The goal of this test is to verify that an IPv6 address
139 // is properly converted to wire format and stored in a
140 // buffer.
TEST_F(OptionDataTypesTest,writeAddress)141 TEST_F(OptionDataTypesTest, writeAddress) {
142     // Encode an IPv6 address 2001:db8:1::1 in wire format.
143     // This will be used as reference data to validate if
144     // an IPv6 address is stored in a buffer properly.
145     const uint8_t data[] = {
146         0x20, 0x01, 0x0d, 0xb8, 0x0, 0x1, 0x0, 0x0,
147         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1
148     };
149     std::vector<uint8_t> buf_in(data, data + sizeof(data));
150 
151     // Create IPv6 address object.
152     asiolink::IOAddress address("2001:db8:1::1");
153     // Define the output buffer to write IP address to.
154     std::vector<uint8_t> buf_out;
155     // Write the address to the buffer.
156     ASSERT_NO_THROW(OptionDataTypeUtil::writeAddress(address, buf_out));
157     // Make sure that input and output buffers have the same size
158     // so we can compare them.
159     ASSERT_EQ(buf_in.size(), buf_out.size());
160     // And finally compare them.
161     EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf_out.begin()));
162 
163     buf_out.clear();
164 
165     // Do similar test for IPv4 address.
166     address = asiolink::IOAddress("192.168.0.1");
167     ASSERT_NO_THROW(OptionDataTypeUtil::writeAddress(address, buf_out));
168     ASSERT_EQ(4, buf_out.size());
169     // Verify that the IP address has been written correctly.
170     EXPECT_EQ(192, buf_out[0]);
171     EXPECT_EQ(168, buf_out[1]);
172     EXPECT_EQ(0, buf_out[2]);
173     EXPECT_EQ(1, buf_out[3]);
174 }
175 
176 // The purpose of this test is to verify that binary data represented
177 // as a string of hexadecimal digits can be written to a buffer.
TEST_F(OptionDataTypesTest,writeBinary)178 TEST_F(OptionDataTypesTest, writeBinary) {
179     // Prepare the reference data.
180     const char data[] = {
181         0x0, 0x1, 0x2, 0x3, 0x4, 0x5,
182         0x6, 0x7, 0x8, 0x9, 0xA, 0xB
183     };
184     std::vector<uint8_t> buf_ref(data, data + sizeof(data));
185     // Create empty vector where binary data will be written to.
186     std::vector<uint8_t> buf;
187     ASSERT_NO_THROW(
188         OptionDataTypeUtil::writeBinary("000102030405060708090A0B", buf)
189     );
190     // Verify that the buffer contains valid data.
191     ASSERT_EQ(buf_ref.size(), buf.size());
192     EXPECT_TRUE(std::equal(buf_ref.begin(), buf_ref.end(), buf.begin()));
193 }
194 
195 // The purpose of this test is to verify that the tuple value stored
TEST_F(OptionDataTypesTest,readTuple)196 TEST_F(OptionDataTypesTest, readTuple) {
197     // The string
198     std::string value = "hello world";
199     // Create an input buffer.
200     std::vector<uint8_t> buf;
201     // DHCPv4 tuples use 1 byte length
202     writeInt<uint8_t>(static_cast<uint8_t>(value.size()), buf);
203     writeString(value, buf);
204 
205     // Read the string from the buffer.
206     std::string result;
207     ASSERT_NO_THROW(
208         result = OptionDataTypeUtil::readTuple(buf, OpaqueDataTuple::LENGTH_1_BYTE);
209     );
210     // Check that it is valid.
211     EXPECT_EQ(value, result);
212 
213     // Read the tuple from the buffer.
214     OpaqueDataTuple tuple4(OpaqueDataTuple::LENGTH_1_BYTE);
215     ASSERT_NO_THROW(OptionDataTypeUtil::readTuple(buf, tuple4));
216     // Check that it is valid.
217     EXPECT_EQ(value, tuple4.getText());
218 
219     buf.clear();
220 
221     // DHCPv6 tuples use 2 byte length
222     writeInt<uint16_t>(static_cast<uint16_t>(value.size()), buf);
223     writeString(value, buf);
224 
225     // Read the string from the buffer.
226     ASSERT_NO_THROW(
227         result = OptionDataTypeUtil::readTuple(buf, OpaqueDataTuple::LENGTH_2_BYTES);
228     );
229     // Check that it is valid.
230     EXPECT_EQ(value, result);
231 
232     // Read the tuple from the buffer.
233     OpaqueDataTuple tuple6(OpaqueDataTuple::LENGTH_2_BYTES);
234     ASSERT_NO_THROW(OptionDataTypeUtil::readTuple(buf, tuple6));
235     // Check that it is valid.
236     EXPECT_EQ(value, tuple6.getText());
237 }
238 
239 // The purpose of this test is to verify that a tuple value
240 // are correctly encoded in a buffer (string version)
TEST_F(OptionDataTypesTest,writeTupleString)241 TEST_F(OptionDataTypesTest, writeTupleString) {
242     // The string
243     std::string value = "hello world";
244     // Create an output buffer.
245     std::vector<uint8_t> buf;
246 
247     // Encode it in DHCPv4
248     OptionDataTypeUtil::writeTuple(value, OpaqueDataTuple::LENGTH_1_BYTE, buf);
249 
250     // Check that it is valid.
251     ASSERT_EQ(value.size() + 1, buf.size());
252     std::vector<uint8_t> expected;
253     writeInt<uint8_t>(static_cast<uint8_t>(value.size()), expected);
254     writeString(value, expected);
255     EXPECT_EQ(0, std::memcmp(&buf[0], &expected[0], buf.size()));
256 
257     buf.clear();
258 
259     // Encode it in DHCPv6
260     OptionDataTypeUtil::writeTuple(value, OpaqueDataTuple::LENGTH_2_BYTES, buf);
261 
262     // Check that it is valid.
263     ASSERT_EQ(value.size() + 2, buf.size());
264     expected.clear();
265     writeInt<uint16_t>(static_cast<uint16_t>(value.size()), expected);
266     writeString(value, expected);
267     EXPECT_EQ(0, std::memcmp(&buf[0], &expected[0], buf.size()));
268 }
269 
270 // The purpose of this test is to verify that a tuple value
271 // are correctly encoded in a buffer (tuple version)
TEST_F(OptionDataTypesTest,writeTuple)272 TEST_F(OptionDataTypesTest, writeTuple) {
273     // The string
274     std::string value = "hello world";
275     // Create a DHCPv4 tuple
276     OpaqueDataTuple tuple4(OpaqueDataTuple::LENGTH_1_BYTE);
277     tuple4.append(value);
278     // Create an output buffer.
279     std::vector<uint8_t> buf;
280 
281     // Encode it in DHCPv4
282     OptionDataTypeUtil::writeTuple(tuple4, buf);
283 
284     // Check that it is valid.
285     ASSERT_EQ(value.size() + 1, buf.size());
286     std::vector<uint8_t> expected;
287     writeInt<uint8_t>(static_cast<uint8_t>(value.size()), expected);
288     writeString(value, expected);
289     EXPECT_EQ(0, std::memcmp(&buf[0], &expected[0], buf.size()));
290 
291     buf.clear();
292 
293     // Create a DHCPv6 tuple
294     OpaqueDataTuple tuple6(OpaqueDataTuple::LENGTH_2_BYTES);
295     tuple6.append(value);
296 
297     // Encode it in DHCPv6
298     OptionDataTypeUtil::writeTuple(tuple6, buf);
299 
300     // Check that it is valid.
301     ASSERT_EQ(value.size() + 2, buf.size());
302     expected.clear();
303     writeInt<uint16_t>(static_cast<uint16_t>(value.size()), expected);
304     writeString(value, expected);
305     EXPECT_EQ(0, std::memcmp(&buf[0], &expected[0], buf.size()));
306 }
307 
308 // The purpose of this test is to verify that the boolean value stored
309 // in a buffer is correctly read from this buffer.
TEST_F(OptionDataTypesTest,readBool)310 TEST_F(OptionDataTypesTest, readBool) {
311     // Create an input buffer.
312     std::vector<uint8_t> buf;
313     // 'true' value is encoded as 1 ('false' is encoded as 0)
314     buf.push_back(1);
315 
316     // Read the value from the buffer.
317     bool value = false;
318     ASSERT_NO_THROW(
319         value = OptionDataTypeUtil::readBool(buf);
320     );
321     // Verify the value.
322     EXPECT_TRUE(value);
323     // Check if 'false' is read correctly either.
324     buf[0] = 0;
325     ASSERT_NO_THROW(
326         value = OptionDataTypeUtil::readBool(buf);
327     );
328     EXPECT_FALSE(value);
329 
330     // Check that invalid value causes exception.
331     buf[0] = 5;
332     ASSERT_THROW(
333         OptionDataTypeUtil::readBool(buf),
334         isc::dhcp::BadDataTypeCast
335     );
336 }
337 
338 // The purpose of this test is to verify that boolean values
339 // are correctly encoded in a buffer as '1' for 'true' and
340 // '0' for 'false' values.
TEST_F(OptionDataTypesTest,writeBool)341 TEST_F(OptionDataTypesTest, writeBool) {
342     // Create a buffer we will write to.
343     std::vector<uint8_t> buf;
344     // Write the 'true' value to the buffer.
345     ASSERT_NO_THROW(OptionDataTypeUtil::writeBool(true, buf));
346     // We should now have 'true' value stored in a buffer.
347     ASSERT_EQ(1, buf.size());
348     EXPECT_EQ(buf[0], 1);
349     // Let's append another value to make sure that it is not always
350     // 'true' value being written.
351     ASSERT_NO_THROW(OptionDataTypeUtil::writeBool(false, buf));
352     ASSERT_EQ(2, buf.size());
353     // Check that the first value has not changed.
354     EXPECT_EQ(buf[0], 1);
355     // Check the second value is correct.
356     EXPECT_EQ(buf[1], 0);
357 }
358 
359 // The purpose of this test is to verify that the integer values
360 // of different types are correctly read from a buffer.
TEST_F(OptionDataTypesTest,readInt)361 TEST_F(OptionDataTypesTest, readInt) {
362     std::vector<uint8_t> buf;
363 
364     // Write an 8-bit unsigned integer value to the buffer.
365     writeInt<uint8_t>(129, buf);
366     uint8_t valueUint8 = 0;
367     // Read the value and check that it is valid.
368     ASSERT_NO_THROW(
369         valueUint8 = OptionDataTypeUtil::readInt<uint8_t>(buf);
370     );
371     EXPECT_EQ(129, valueUint8);
372 
373     // Try to read 16-bit value from a buffer holding 8-bit value.
374     // This should result in an exception.
375     EXPECT_THROW(
376         OptionDataTypeUtil::readInt<uint16_t>(buf),
377         isc::dhcp::BadDataTypeCast
378     );
379 
380     // Clear the buffer for the next check we are going to do.
381     buf.clear();
382 
383     // Test uint16_t value.
384     writeInt<uint16_t>(1234, buf);
385     uint16_t valueUint16 = 0;
386     ASSERT_NO_THROW(
387         valueUint16 = OptionDataTypeUtil::readInt<uint16_t>(buf);
388     );
389     EXPECT_EQ(1234, valueUint16);
390 
391     // Try to read 32-bit value from a buffer holding 16-bit value.
392     // This should result in an exception.
393     EXPECT_THROW(
394         OptionDataTypeUtil::readInt<uint32_t>(buf),
395         isc::dhcp::BadDataTypeCast
396     );
397 
398     buf.clear();
399 
400     // Test uint32_t value.
401     writeInt<uint32_t>(56789, buf);
402     uint32_t valueUint32 = 0;
403     ASSERT_NO_THROW(
404         valueUint32 = OptionDataTypeUtil::readInt<uint32_t>(buf);
405     );
406     EXPECT_EQ(56789, valueUint32);
407     buf.clear();
408 
409     // Test int8_t value.
410     writeInt<int8_t>(-65, buf);
411     int8_t valueInt8 = 0;
412     ASSERT_NO_THROW(
413         valueInt8 = OptionDataTypeUtil::readInt<int8_t>(buf);
414     );
415     EXPECT_EQ(-65, valueInt8);
416     buf.clear();
417 
418     // Try to read 16-bit value from a buffer holding 8-bit value.
419     // This should result in an exception.
420     EXPECT_THROW(
421         OptionDataTypeUtil::readInt<int16_t>(buf),
422         isc::dhcp::BadDataTypeCast
423     );
424 
425     // Test int16_t value.
426     writeInt<int16_t>(2345, buf);
427     int32_t valueInt16 = 0;
428     ASSERT_NO_THROW(
429         valueInt16 = OptionDataTypeUtil::readInt<int16_t>(buf);
430     );
431     EXPECT_EQ(2345, valueInt16);
432     buf.clear();
433 
434     // Try to read 32-bit value from a buffer holding 16-bit value.
435     // This should result in an exception.
436     EXPECT_THROW(
437         OptionDataTypeUtil::readInt<int32_t>(buf),
438         isc::dhcp::BadDataTypeCast
439     );
440 
441     // Test int32_t value.
442     writeInt<int32_t>(-16543, buf);
443     int32_t valueInt32 = 0;
444     ASSERT_NO_THROW(
445         valueInt32 = OptionDataTypeUtil::readInt<int32_t>(buf);
446     );
447     EXPECT_EQ(-16543, valueInt32);
448 
449     buf.clear();
450 }
451 
452 // The purpose of this test is to verify that integer values of different
453 // types are correctly written to a buffer.
TEST_F(OptionDataTypesTest,writeInt)454 TEST_F(OptionDataTypesTest, writeInt) {
455     // Prepare the reference buffer.
456     const uint8_t data[] = {
457         0x7F, // 127
458         0x03, 0xFF, // 1023
459         0x00, 0x00, 0x10, 0x00, // 4096
460         0xFF, 0xFF, 0xFC, 0x00, // -1024
461         0x02, 0x00, // 512
462         0x81 // -127
463     };
464     std::vector<uint8_t> buf_ref(data, data + sizeof(data));
465 
466     // Fill in the buffer with data. Each write operation appends an
467     // integer value. Eventually the buffer holds all values and should
468     // match with the reference buffer.
469     std::vector<uint8_t> buf;
470     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<uint8_t>(127, buf));
471     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<uint16_t>(1023, buf));
472     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<uint32_t>(4096, buf));
473     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<int32_t>(-1024, buf));
474     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<int16_t>(512, buf));
475     ASSERT_NO_THROW(OptionDataTypeUtil::writeInt<int8_t>(-127, buf));
476 
477     // Make sure that the buffer has the same size as the reference
478     // buffer.
479     ASSERT_EQ(buf_ref.size(), buf.size());
480     // Compare buffers.
481     EXPECT_TRUE(std::equal(buf_ref.begin(), buf_ref.end(), buf.begin()));
482 }
483 
484 // The purpose of this test is to verify that FQDN is read from
485 // a buffer and returned as a text. The representation of the FQDN
486 // in the buffer complies with RFC1035, section 3.1.
487 // This test also checks that if invalid (truncated) FQDN is stored
488 // in a buffer the appropriate exception is returned when trying to
489 // read it as a string.
TEST_F(OptionDataTypesTest,readFqdn)490 TEST_F(OptionDataTypesTest, readFqdn) {
491     // The binary representation of the "mydomain.example.com".
492     // Values: 8, 7, 3 and 0 specify the lengths of subsequent
493     // labels within the FQDN.
494     const char data[] = {
495         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
496         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
497         3, 99, 111, 109,                          // "com"
498         0
499     };
500 
501     // Make a vector out of the data.
502     std::vector<uint8_t> buf(data, data + sizeof(data));
503 
504     // Read the buffer as FQDN and verify its correctness.
505     std::string fqdn;
506     EXPECT_NO_THROW(fqdn = OptionDataTypeUtil::readFqdn(buf));
507     EXPECT_EQ("mydomain.example.com.", fqdn);
508 
509     // By resizing the buffer we simulate truncation. The first
510     // length field (8) indicate that the first label's size is
511     // 8 but the actual buffer size is 5. Expect that conversion
512     // fails.
513     buf.resize(5);
514     EXPECT_THROW(
515         OptionDataTypeUtil::readFqdn(buf),
516         isc::dhcp::BadDataTypeCast
517     );
518 
519     // Another special case: provide an empty buffer.
520     buf.clear();
521     EXPECT_THROW(
522         OptionDataTypeUtil::readFqdn(buf),
523         isc::dhcp::BadDataTypeCast
524     );
525 }
526 
527 // The purpose of this test is to verify that FQDN's syntax is validated
528 // and that FQDN is correctly written to a buffer in a format described
529 // in RFC1035 section 3.1.
TEST_F(OptionDataTypesTest,writeFqdn)530 TEST_F(OptionDataTypesTest, writeFqdn) {
531     // Create empty buffer. The FQDN will be written to it.
532     OptionBuffer buf;
533     // Write a domain name into the buffer in the format described
534     // in RFC1035 section 3.1. This function should not throw
535     // exception because domain name is well formed.
536     EXPECT_NO_THROW(
537         OptionDataTypeUtil::writeFqdn("mydomain.example.com", buf)
538     );
539     // The length of the data is 22 (8 bytes for "mydomain" label,
540     // 7 bytes for "example" label, 3 bytes for "com" label and
541     // finally 4 bytes positions between labels where length
542     // information is stored.
543     ASSERT_EQ(22, buf.size());
544 
545     // Verify that length fields between labels hold valid values.
546     EXPECT_EQ(8, buf[0]);  // length of "mydomain"
547     EXPECT_EQ(7, buf[9]);  // length of "example"
548     EXPECT_EQ(3, buf[17]); // length of "com"
549     EXPECT_EQ(0, buf[21]); // zero byte at the end.
550 
551     // Verify that labels are valid.
552     std::string label0(buf.begin() + 1, buf.begin() + 9);
553     EXPECT_EQ("mydomain", label0);
554 
555     std::string label1(buf.begin() + 10, buf.begin() + 17);
556     EXPECT_EQ("example", label1);
557 
558     std::string label2(buf.begin() + 18, buf.begin() + 21);
559     EXPECT_EQ("com", label2);
560 
561     // The tested function is supposed to append data to a buffer
562     // so let's check that it is a case by appending another domain.
563     OptionDataTypeUtil::writeFqdn("hello.net", buf);
564 
565     // The buffer length should be now longer.
566     ASSERT_EQ(33, buf.size());
567 
568     // Check the length fields for new labels being appended.
569     EXPECT_EQ(5, buf[22]);
570     EXPECT_EQ(3, buf[28]);
571 
572     // And check that labels are ok.
573     std::string label3(buf.begin() + 23, buf.begin() + 28);
574     EXPECT_EQ("hello", label3);
575 
576     std::string label4(buf.begin() + 29, buf.begin() + 32);
577     EXPECT_EQ("net", label4);
578 
579     // Check that invalid (empty) FQDN is rejected and expected
580     // exception type is thrown.
581     buf.clear();
582     EXPECT_THROW(
583         OptionDataTypeUtil::writeFqdn("", buf),
584         isc::dhcp::BadDataTypeCast
585     );
586 
587     // Check another invalid domain name (with repeated dot).
588     buf.clear();
589     EXPECT_THROW(
590         OptionDataTypeUtil::writeFqdn("example..com", buf),
591         isc::dhcp::BadDataTypeCast
592     );
593 }
594 
595 // The purpose of this test is to verify that the variable length prefix
596 // can be read from a buffer correctly.
TEST_F(OptionDataTypesTest,readPrefix)597 TEST_F(OptionDataTypesTest, readPrefix) {
598     std::vector<uint8_t> buf;
599 
600     // Prefix 2001:db8::/64
601     writeInt<uint8_t>(64, buf);
602     writeInt<uint32_t>(0x20010db8, buf);
603     writeInt<uint32_t>(0, buf);
604 
605     PrefixTuple prefix(ZERO_PREFIX_TUPLE);
606     ASSERT_NO_THROW(prefix = OptionDataTypeUtil::readPrefix(buf));
607     EXPECT_EQ(64, prefix.first.asUnsigned());
608     EXPECT_EQ("2001:db8::", prefix.second.toText());
609 
610     buf.clear();
611 
612     // Prefix 2001:db8::/63
613     writeInt<uint8_t>(63, buf);
614     writeInt<uint32_t>(0x20010db8, buf);
615     writeInt<uint32_t>(0, buf);
616 
617     ASSERT_NO_THROW(prefix = OptionDataTypeUtil::readPrefix(buf));
618     EXPECT_EQ(63, prefix.first.asUnsigned());
619     EXPECT_EQ("2001:db8::", prefix.second.toText());
620 
621     buf.clear();
622 
623     // Prefix 2001:db8:c0000. Note that the last four bytes are filled with
624     // 0xFF (all bits set). When the prefix is read those non-significant
625     // bits (beyond prefix length) should be ignored (read as 0). Only first
626     // two bits of 0xFFFFFFFF should be read, thus 0xC000, rather than 0xFFFF.
627     writeInt<uint8_t>(34, buf);
628     writeInt<uint32_t>(0x20010db8, buf);
629     writeInt<uint32_t>(0xFFFFFFFF, buf);
630 
631     ASSERT_NO_THROW(prefix = OptionDataTypeUtil::readPrefix(buf));
632     EXPECT_EQ(34, prefix.first.asUnsigned());
633     EXPECT_EQ("2001:db8:c000::", prefix.second.toText());
634 
635     buf.clear();
636 
637     // Prefix having a length of 0.
638     writeInt<uint8_t>(0, buf);
639     writeInt<uint16_t>(0x2001, buf);
640 
641     ASSERT_NO_THROW(prefix = OptionDataTypeUtil::readPrefix(buf));
642     EXPECT_EQ(0, prefix.first.asUnsigned());
643     EXPECT_EQ("::", prefix.second.toText());
644 
645     buf.clear();
646 
647     // Prefix having a maximum length of 128.
648     writeInt<uint8_t>(128, buf);
649     buf.insert(buf.end(), 16, 0x11);
650 
651     ASSERT_NO_THROW(prefix = OptionDataTypeUtil::readPrefix(buf));
652     EXPECT_EQ(128, prefix.first.asUnsigned());
653     EXPECT_EQ("1111:1111:1111:1111:1111:1111:1111:1111",
654               prefix.second.toText());
655 
656     buf.clear();
657 
658     // Prefix length is greater than 128. This should result in an
659     // error.
660     writeInt<uint8_t>(129, buf);
661     writeInt<uint16_t>(0x3000, buf);
662     buf.resize(17);
663 
664     EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPrefix(buf)),
665                  BadDataTypeCast);
666 
667     buf.clear();
668 
669     // Buffer truncated. Prefix length of 10 requires at least 2 bytes,
670     // but there is only one byte.
671     writeInt<uint8_t>(10, buf);
672     writeInt<uint8_t>(1, buf);
673 
674     EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPrefix(buf)),
675                  BadDataTypeCast);
676 }
677 
678 // The purpose of this test is to verify that the variable length prefix
679 // is written to a buffer correctly.
TEST_F(OptionDataTypesTest,writePrefix)680 TEST_F(OptionDataTypesTest, writePrefix) {
681     // Initialize a buffer and store some value in it. We'll want to make
682     // sure that the prefix being written will not override this value, but
683     // will rather be appended.
684     std::vector<uint8_t> buf(1, 1);
685 
686     // Prefix 2001:db8:FFFF::/34 is equal to 2001:db8:C000::/34 because
687     // there are only 34 significant bits. All other bits must be zeroed.
688     ASSERT_NO_THROW(OptionDataTypeUtil::writePrefix(PrefixLen(34),
689                                                     IOAddress("2001:db8:FFFF::"),
690                                                     buf));
691     ASSERT_EQ(7, buf.size());
692 
693     EXPECT_EQ(1, static_cast<unsigned>(buf[0]));
694     EXPECT_EQ(34, static_cast<unsigned>(buf[1]));
695     EXPECT_EQ(0x20, static_cast<unsigned>(buf[2]));
696     EXPECT_EQ(0x01, static_cast<unsigned>(buf[3]));
697     EXPECT_EQ(0x0D, static_cast<unsigned>(buf[4]));
698     EXPECT_EQ(0xB8, static_cast<unsigned>(buf[5]));
699     EXPECT_EQ(0xC0, static_cast<unsigned>(buf[6]));
700 
701     buf.clear();
702 
703     // Prefix length is 0. The entire prefix should be ignored.
704     ASSERT_NO_THROW(OptionDataTypeUtil::writePrefix(PrefixLen(0),
705                                                     IOAddress("2001:db8:FFFF::"),
706                                                     buf));
707     ASSERT_EQ(1, buf.size());
708     EXPECT_EQ(0, static_cast<unsigned>(buf[0]));
709 
710     buf.clear();
711 
712     // Prefix having a maximum length of 128.
713     ASSERT_NO_THROW(OptionDataTypeUtil::writePrefix(PrefixLen(128),
714                                                     IOAddress("2001:db8::FF"),
715                                                     buf));
716 
717     // We should now have a 17 bytes long buffer. 1 byte goes for a prefix
718     // length field, the remaining ones hold the prefix.
719     ASSERT_EQ(17, buf.size());
720     // Because the prefix is 16 bytes long, we can simply use the
721     // IOAddress convenience function to read it back and compare
722     // it with the textual representation. This is simpler than
723     // comparing each byte separately.
724     IOAddress prefix_read = IOAddress::fromBytes(AF_INET6, &buf[1]);
725     EXPECT_EQ("2001:db8::ff", prefix_read.toText());
726 
727     buf.clear();
728 
729     // It is illegal to use IPv4 address as prefix.
730     EXPECT_THROW(OptionDataTypeUtil::writePrefix(PrefixLen(4),
731                                                  IOAddress("10.0.0.1"), buf),
732                  BadDataTypeCast);
733 }
734 
735 // The purpose of this test is to verify that the
736 // PSID-len/PSID tuple can be read from a buffer.
TEST_F(OptionDataTypesTest,readPsid)737 TEST_F(OptionDataTypesTest, readPsid) {
738     std::vector<uint8_t> buf;
739 
740     // PSID length is 6 (bits)
741     writeInt<uint8_t>(6, buf);
742     // 0xA400 is represented as 1010010000000000b, which is equivalent
743     // of portset 0x29 (101001b).
744     writeInt<uint16_t>(0xA400, buf);
745 
746     PSIDTuple psid;
747     ASSERT_NO_THROW(psid = OptionDataTypeUtil::readPsid(buf));
748     EXPECT_EQ(6, psid.first.asUnsigned());
749     EXPECT_EQ(0x29, psid.second.asUint16());
750 
751     buf.clear();
752 
753     // PSID length is 16 (bits)
754     writeInt<uint8_t>(16, buf);
755     // 0xF000 is represented as 1111000000000000b, which is equivalent
756     // of portset 0xF000.
757     writeInt<uint16_t>(0xF000, buf);
758 
759     ASSERT_NO_THROW(psid = OptionDataTypeUtil::readPsid(buf));
760     EXPECT_EQ(16, psid.first.asUnsigned());
761     EXPECT_EQ(0xF000, psid.second.asUint16());
762 
763     buf.clear();
764 
765     // PSID length is 0, in which case PSID should be ignored.
766     writeInt<uint8_t>(0, buf);
767     // Let's put some junk into the PSID field to make sure it will
768     // be ignored.
769     writeInt<uint16_t>(0x1234, buf);
770     ASSERT_NO_THROW(psid = OptionDataTypeUtil::readPsid(buf));
771     EXPECT_EQ(0, psid.first.asUnsigned());
772     EXPECT_EQ(0, psid.second.asUint16());
773 
774     buf.clear();
775 
776     // PSID length greater than 16 is not allowed.
777     writeInt<uint8_t>(17, buf);
778     writeInt<uint16_t>(0, buf);
779     EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPsid(buf)),
780                  BadDataTypeCast);
781 
782     buf.clear();
783 
784     // PSID length is 3 bits, but the PSID value is 11 (1011b), so it
785     // is encoded on 4 bits, rather than 3.
786     writeInt<uint8_t>(3, buf);
787     writeInt<uint16_t>(0xB000, buf);
788     EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPsid(buf)),
789                  BadDataTypeCast);
790 
791     buf.clear();
792 
793     // Buffer is truncated - 2 bytes instead of 3.
794     writeInt<uint8_t>(4, buf);
795     writeInt<uint8_t>(0xF0, buf);
796     EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPsid(buf)),
797                  BadDataTypeCast);
798 
799     // Check for out of range values.
800     for (int i = 1; i < 16; ++i) {
801         buf.clear();
802         writeInt<uint8_t>(i, buf);
803         writeInt<uint16_t>(0xFFFF << (15 - i), buf);
804         EXPECT_THROW(static_cast<void>(OptionDataTypeUtil::readPsid(buf)),
805                      BadDataTypeCast);
806     }
807 
808 }
809 
810 // The purpose of this test is to verify that the PSID-len/PSID
811 // tuple is written to a buffer correctly.
TEST_F(OptionDataTypesTest,writePsid)812 TEST_F(OptionDataTypesTest, writePsid) {
813     // Let's create a buffer with some data in it. We want to make
814     // sure that the existing data remain untouched when we write
815     // PSID to the buffer.
816     std::vector<uint8_t> buf(1, 1);
817     // PSID length is 4 (bits), PSID value is 8.
818     ASSERT_NO_THROW(OptionDataTypeUtil::writePsid(PSIDLen(4), PSID(8), buf));
819     ASSERT_EQ(4, buf.size());
820     // The byte which existed in the buffer should still hold the
821     // same value.
822     EXPECT_EQ(1, static_cast<unsigned>(buf[0]));
823     // PSID length should be written as specified in the function call.
824     EXPECT_EQ(4, static_cast<unsigned>(buf[1]));
825     // The PSID structure is as follows:
826     // UUUUPPPPPPPPPPPP, where "U" are useful bits on which we code
827     // the PSID. "P" are zero padded bits. The PSID value 8 is coded
828     // on four useful bits as '1000b'. That means that the PSID value
829     // encoded in the PSID field is: '1000000000000000b', which is
830     // 0x8000. The next two EXPECT_EQ statements verify that.
831     EXPECT_EQ(0x80, static_cast<unsigned>(buf[2]));
832     EXPECT_EQ(0x00, static_cast<unsigned>(buf[3]));
833 
834     // Clear the buffer to make sure we don't append to the
835     // existing data.
836     buf.clear();
837 
838     // The PSID length of 0 causes the PSID value (of 6) to be ignored.
839     // As a result, the buffer should hold only zeros.
840     ASSERT_NO_THROW(OptionDataTypeUtil::writePsid(PSIDLen(0), PSID(6), buf));
841     ASSERT_EQ(3, buf.size());
842     EXPECT_EQ(0, static_cast<unsigned>(buf[0]));
843     EXPECT_EQ(0, static_cast<unsigned>(buf[1]));
844     EXPECT_EQ(0, static_cast<unsigned>(buf[2]));
845 
846     buf.clear();
847 
848     // Another test case, to verify that we can use the maximum length
849     // of PSID (16 bits).
850     ASSERT_NO_THROW(OptionDataTypeUtil::writePsid(PSIDLen(16), PSID(5), buf));
851     ASSERT_EQ(3, buf.size());
852     // PSID length should be written with no change.
853     EXPECT_EQ(16, static_cast<unsigned>(buf[0]));
854     // Check PSID value.
855     EXPECT_EQ(0x00, static_cast<unsigned>(buf[1]));
856     EXPECT_EQ(0x05, static_cast<unsigned>(buf[2]));
857 
858     // PSID length of 17 exceeds the maximum allowed value of 16.
859     EXPECT_THROW(OptionDataTypeUtil::writePsid(PSIDLen(17), PSID(1), buf),
860                  OutOfRange);
861 
862     // Check for out of range values.
863     for (int i = 1; i < 16; ++i) {
864         EXPECT_THROW(OptionDataTypeUtil::writePsid(PSIDLen(i), PSID(1 << i), buf),
865                      BadDataTypeCast);
866     }
867 }
868 
869 // The purpose of this test is to verify that the string
870 // can be read from a buffer correctly.
TEST_F(OptionDataTypesTest,readString)871 TEST_F(OptionDataTypesTest, readString) {
872 
873     // Prepare a buffer with some string in it.
874     std::vector<uint8_t> buf;
875     writeString("hello world", buf);
876 
877     // Read the string from the buffer.
878     std::string value;
879     ASSERT_NO_THROW(
880         value = OptionDataTypeUtil::readString(buf);
881     );
882     // Check that it is valid.
883     EXPECT_EQ("hello world", value);
884 
885     // Only nulls should throw.
886     OptionBuffer buffer = { 0, 0 };
887     ASSERT_THROW(OptionDataTypeUtil::readString(buffer), isc::OutOfRange);
888 
889     // One trailing null should trim off.
890     buffer = {'o', 'n', 'e', 0 };
891     ASSERT_NO_THROW(value = OptionDataTypeUtil::readString(buffer));
892     EXPECT_EQ(3, value.length());
893     EXPECT_EQ(value, std::string("one"));
894 
895     // More than one trailing null should trim off.
896     buffer = { 't', 'h', 'r', 'e', 'e', 0, 0, 0 };
897     ASSERT_NO_THROW(value = OptionDataTypeUtil::readString(buffer));
898     EXPECT_EQ(5, value.length());
899     EXPECT_EQ(value, std::string("three"));
900 
901     // Embedded null should be left in place.
902     buffer = { 'e', 'm', 0, 'b', 'e', 'd' };
903     ASSERT_NO_THROW(value = OptionDataTypeUtil::readString(buffer));
904     EXPECT_EQ(6, value.length());
905     EXPECT_EQ(value, (std::string{"em\0bed", 6}));
906 
907     // Leading null should be left in place.
908     buffer = { 0, 'l', 'e', 'a', 'd', 'i', 'n', 'g' };
909     ASSERT_NO_THROW(value = OptionDataTypeUtil::readString(buffer));
910     EXPECT_EQ(8, value.length());
911     EXPECT_EQ(value, (std::string{"\0leading", 8}));
912 }
913 
914 // The purpose of this test is to verify that a string can be
915 // stored in a buffer correctly.
TEST_F(OptionDataTypesTest,writeString)916 TEST_F(OptionDataTypesTest, writeString) {
917     // Prepare a buffer with a reference data.
918     std::vector<uint8_t> buf_ref;
919     writeString("hello world!", buf_ref);
920     // Create empty buffer we will write to.
921     std::vector<uint8_t> buf;
922     ASSERT_NO_THROW(OptionDataTypeUtil::writeString("hello world!", buf));
923     // Compare two buffers.
924     ASSERT_EQ(buf_ref.size(), buf.size());
925     EXPECT_TRUE(std::equal(buf_ref.begin(), buf_ref.end(), buf.begin()));
926 }
927 
928 } // anonymous namespace
929