// Copyright (C) 2011-2015 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 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 { /// @brief A class which contains a custom callback function to unpack options. /// /// This is a class used by the tests which verify that the custom callback /// functions can be installed to unpack options from a message. When the /// callback function is called, the executed_ member is set to true to allow /// verification that the callback was really called. Internally, this class /// uses libdhcp++ to unpack options so the options parsing algorithm remains /// unchanged after installation of the callback. class CustomUnpackCallback { public: /// @brief Constructor /// /// Marks that callback hasn't been called. CustomUnpackCallback() : executed_(false) { } /// @brief A callback /// /// Contains custom implementation of the callback. /// /// @param buf a A buffer holding options in on-wire format. /// @param option_space A name of the option space being encapsulated by /// the option being parsed. /// @param [out] options A reference to the collection where parsed options /// will be stored. /// @return An offset to the first byte after last parsed option. size_t execute(const OptionBuffer& buf, const std::string& option_space, isc::dhcp::OptionCollection& options) { // Set the executed_ member to true to allow verification that the // callback has been actually called. executed_ = true; // Use default implementation of the unpack algorithm to parse options. return (LibDHCP::unpackOptions4(buf, option_space, options)); } /// A flag which indicates if callback function has been called. bool executed_; }; /// 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[] = { 12, 3, 0, 1, 2, // Hostname 14, 3, 10, 11, 12, // Merit Dump File 53, 1, 2, // Message Type (required to not throw exception during unpack) 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)); boost::shared_ptr