// Copyright (C) 2011-2023 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/. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; // Don't import the entire boost namespace. It will unexpectedly hide uint8_t // for some systems. using boost::scoped_ptr; namespace { /// V4 Options being used for pack/unpack testing. /// For test simplicity, all selected options have /// variable length data so as there are no restrictions /// on a length of their data. static uint8_t v4_opts[] = { 53, 1, 2, // Message Type (required to not throw exception during unpack) 12, 3, 0, 1, 2, // Hostname 14, 3, 10, 11, 12, // Merit Dump File 60, 3, 20, 21, 22, // Class Id 128, 3, 30, 31, 32, // Vendor specific 254, 3, 40, 41, 42, // Reserved }; // Sample data const uint8_t dummyOp = BOOTREQUEST; const uint8_t dummyHtype = 6; const uint8_t dummyHlen = 6; const uint8_t dummyHops = 13; const uint32_t dummyTransid = 0x12345678; const uint16_t dummySecs = 42; const uint16_t dummyFlags = BOOTP_BROADCAST; const IOAddress dummyCiaddr("192.0.2.1"); const IOAddress dummyYiaddr("1.2.3.4"); const IOAddress dummySiaddr("192.0.2.255"); const IOAddress dummyGiaddr("255.255.255.255"); // a dummy MAC address const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5}; // A dummy MAC address, padded with 0s const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Let's use some creative test content here (128 chars + \0) const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur " "adipiscing elit. Proin mollis placerat metus, at " "lacinia orci ornare vitae. Mauris amet."; // Yet another type of test content (64 chars + \0) const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur " "adipiscing elit posuere."; BOOST_STATIC_ASSERT(sizeof(dummyFile) == Pkt4::MAX_FILE_LEN + 1); BOOST_STATIC_ASSERT(sizeof(dummySname) == Pkt4::MAX_SNAME_LEN + 1); class Pkt4Test : public ::testing::Test { public: Pkt4Test() { } /// @brief Generates test packet. /// /// Allocates and generates test packet, with all fixed fields set to non-zero /// values. Content is not always reasonable. /// /// See generateTestPacket2() function that returns exactly the same packet in /// on-wire format. /// /// @return pointer to allocated Pkt4 object. Pkt4Ptr generateTestPacket1() { boost::shared_ptr pkt(new Pkt4(DHCPDISCOVER, dummyTransid)); vector vectorMacAddr(dummyMacAddr, dummyMacAddr + sizeof(dummyMacAddr)); // hwType = 6(ETHERNET), hlen = 6(MAC address len) pkt->setHWAddr(dummyHtype, dummyHlen, vectorMacAddr); pkt->setHops(dummyHops); // 13 relays. Wow! // Transaction-id is already set. pkt->setSecs(dummySecs); pkt->setFlags(dummyFlags); // all flags set pkt->setCiaddr(dummyCiaddr); pkt->setYiaddr(dummyYiaddr); pkt->setSiaddr(dummySiaddr); pkt->setGiaddr(dummyGiaddr); // Chaddr already set with setHWAddr(). pkt->setSname(dummySname, 64); pkt->setFile(dummyFile, 128); return (pkt); } /// @brief Generates test packet. /// /// Allocates and generates on-wire buffer that represents test packet, with all /// fixed fields set to non-zero values. Content is not always reasonable. /// /// See generateTestPacket1() function that returns exactly the same packet as /// Pkt4 object. /// /// @return pointer to allocated Pkt4 object // Returns a vector containing a DHCPv4 packet header. vector generateTestPacket2() { // That is only part of the header. It contains all "short" fields, // larger fields are constructed separately. uint8_t hdr[] = { 1, 6, 6, 13, // op, htype, hlen, hops, 0x12, 0x34, 0x56, 0x78, // transaction-id 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags 192, 0, 2, 1, // ciaddr 1, 2, 3, 4, // yiaddr 192, 0, 2, 255, // siaddr 255, 255, 255, 255, // giaddr }; // Initialize the vector with the header fields defined above. vector buf(hdr, hdr + sizeof(hdr)); // Append the large header fields. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf)); copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf)); copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf)); // Should now have all the header, so check. The "static_cast" is used // to get round an odd bug whereby the linker appears not to find the // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ(). EXPECT_EQ(static_cast(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size()); return (buf); } /// @brief Verify that the options are correct after parsing. /// /// @param pkt A packet holding parsed options. void verifyParsedOptions(const Pkt4Ptr& pkt) { EXPECT_TRUE(pkt->getOption(12)); EXPECT_TRUE(pkt->getOption(60)); EXPECT_TRUE(pkt->getOption(14)); EXPECT_TRUE(pkt->getOption(128)); EXPECT_TRUE(pkt->getOption(254)); // Verify the packet type is correct. ASSERT_EQ(DHCPOFFER, pkt->getType()); // First option after message type starts at 3. uint8_t *opt_data_ptr = v4_opts + 3; // Option 12 is represented by the OptionString class so let's do // the appropriate conversion. boost::shared_ptr