From: Marcin Siodelski Date: Mon, 18 May 2015 12:52:32 +0000 (+0200) Subject: [3807] Implemented Pkt6::getLabel and Pkt6::getClientId. X-Git-Tag: trac3732a_base~19^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fe8f693b28ee89faf7ca2bc25e71f4464d7b205a;p=thirdparty%2Fkea.git [3807] Implemented Pkt6::getLabel and Pkt6::getClientId. --- diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 0fdd23f207..c5f4f9de66 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -224,25 +224,11 @@ Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const { return (true); } -DuidPtr -Dhcpv6Srv::extractClientId(const Pkt6Ptr& pkt) { - // Let's find client's DUID. Client is supposed to include its client-id - // option almost all the time (the only exception is an anonymous inf-request, - // but that is mostly a theoretical case). Our allocation engine needs DUID - // and will refuse to allocate anything to anonymous clients. - OptionPtr opt_duid = pkt->getOption(D6O_CLIENTID); - if (opt_duid) { - return (DuidPtr(new DUID(opt_duid->getData()))); - } else { - return (DuidPtr()); - } -} - AllocEngine::ClientContext6 Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) { AllocEngine::ClientContext6 ctx; ctx.subnet_ = selectSubnet(pkt); - ctx.duid_ = extractClientId(pkt); + ctx.duid_ = pkt->getClientId(); ctx.hwaddr_ = getMAC(pkt); alloc_engine_->findReservation(ctx); diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 0099b7ea86..ecad163f9e 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -737,12 +737,6 @@ private: const std::string& hostname, bool do_fwd, bool do_rev); - /// @brief Utility method that extracts DUID from client-id option - /// - /// @param pkt the message that contains client-id option - /// @return extracted DUID (or NULL if client-id is missing) - DuidPtr extractClientId(const Pkt6Ptr& pkt); - /// @brief Allocation Engine. /// Pointer to the allocation engine that we are currently using /// It must be a pointer, because we will support changing engines diff --git a/src/lib/dhcp/pkt6.cc b/src/lib/dhcp/pkt6.cc index e2c5ff8ec4..a62726fcce 100644 --- a/src/lib/dhcp/pkt6.cc +++ b/src/lib/dhcp/pkt6.cc @@ -495,6 +495,36 @@ Pkt6::getMACFromDUID() { } } +std::string +Pkt6::makeLabel(const DuidPtr duid, const uint32_t transid, + const HWAddrPtr& hwaddr) { + std::stringstream label; + // DUID should be present at all times, so explicitly inform when + // it is no present (no info). + label << "duid=[" << (duid ? duid->toText() : "no info") + << "],"; + + // HW address is typically not carried in the DHCPv6 mmessages + // and can be extracted using various, but not fully reliable, + // techniques. If it is not present, don't print anything. + if (hwaddr) { + label << " [" << hwaddr->toText() << "],"; + } + + // Transaction id is always there. + label << " tid=0x" << std::hex << transid << std::dec; + + return (label.str()); +} + +std::string +Pkt6::getLabel() const { + /// @todo Do not print HW address as it is unclear how it should + /// be retrieved if there is no access to user configuration which + /// specifies the order of various techniques to be used to retrieve + /// it. + return (makeLabel(getClientId(), getTransid(), HWAddrPtr()));} + std::string Pkt6::toText() const { stringstream tmp; @@ -511,6 +541,12 @@ Pkt6::toText() const { return tmp.str(); } +DuidPtr +Pkt6::getClientId() const { + OptionPtr opt_duid = getOption(D6O_CLIENTID); + return (opt_duid ? DuidPtr(new DUID(opt_duid->getData())) : DuidPtr()); +} + isc::dhcp::OptionCollection Pkt6::getOptions(uint16_t opt_type) { isc::dhcp::OptionCollection found; diff --git a/src/lib/dhcp/pkt6.h b/src/lib/dhcp/pkt6.h index fe3943c562..92a63a9e53 100644 --- a/src/lib/dhcp/pkt6.h +++ b/src/lib/dhcp/pkt6.h @@ -16,6 +16,7 @@ #define PKT6_H #include +#include #include #include @@ -157,6 +158,34 @@ public: proto_ = proto; } + /// @brief Returns text representation of the given packet identifiers. + /// + /// @note The parameters are ordered from the one that should be available + /// almost at all times, to the one that is optional. This allows for + /// providing default values for the parameters that may not be available + /// in some places in the code where @c Pkt6::makeLabel is called. + /// + /// @param duid Pointer to the client identifier or NULL. + /// @param transid Numeric transaction id to include in the string. + /// @param hwaddr Hardware address to include in the string or NULL. + /// + /// @return String with text representation of the packet identifiers. + static std::string makeLabel(const DuidPtr duid, const uint32_t transid, + const HWAddrPtr& hwaddr); + + /// @brief Returns text representation of the primary packet identifiers + /// + /// This method is intended to be used to provide a consistent way to + /// identify packets within log statements. It is an instance-level + /// wrapper around static makeLabel(). See this method for string + /// content. + /// + /// @note Currently this method doesn't include the HW address in the + /// returned text. + /// + /// @return string with text representation + virtual std::string getLabel() const; + /// @brief Returns text representation of the packet. /// /// This function is useful mainly for debugging. @@ -186,6 +215,11 @@ public: /// @param type message type to be set virtual void setType(uint8_t type) { msg_type_=type; }; + /// @brief Retrieves the DUID from the Client Identifier option. + /// + /// @return Pointer to the DUID or NULL if the option doesn't exist. + DuidPtr getClientId() const; + /// @brief returns option inserted by relay /// /// Returns an option from specified relay scope (inserted by a given relay diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc index 256edd45b2..6b8087bd2b 100755 --- a/src/lib/dhcp/tests/pkt6_unittest.cc +++ b/src/lib/dhcp/tests/pkt6_unittest.cc @@ -129,9 +129,9 @@ public: /// length as an input. This constructor is normally used to parse /// received packets. It stores the packet in a data_ field and /// therefore unpack() can be called to parse it. - Pkt6Ptr packAndClone() { - Pkt6Ptr parent(new Pkt6(DHCPV6_SOLICIT, 0x020304)); - + /// + /// @param parent Packet from which the new packet should be created. + Pkt6Ptr packAndClone(Pkt6Ptr& parent) { OptionPtr opt1(new Option(Option::V6, 1)); OptionPtr opt2(new Option(Option::V6, 2)); OptionPtr opt3(new Option(Option::V6, 100)); @@ -141,17 +141,8 @@ public: parent->addOption(opt2); parent->addOption(opt3); - EXPECT_EQ(DHCPV6_SOLICIT, parent->getType()); - - // Calculated length should be 16 - EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN, - parent->len()); - EXPECT_NO_THROW(parent->pack()); - EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN, - parent->len()); - // Create second packet,based on assembled data from the first one Pkt6Ptr clone(new Pkt6(static_cast (parent->getBuffer().getData()), @@ -306,7 +297,8 @@ TEST_F(Pkt6Test, unpack_solicit1) { TEST_F(Pkt6Test, packUnpack) { // Create an on-wire representation of the test packet and clone it. - Pkt6Ptr clone = packAndClone(); + Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x020304)); + Pkt6Ptr clone = packAndClone(pkt); // Now recreate options list ASSERT_NO_THROW(clone->unpack()); @@ -383,7 +375,8 @@ TEST_F(Pkt6Test, unpackMalformed) { // the option parsing algorithm by installing a callback function. TEST_F(Pkt6Test, packUnpackWithCallback) { // Create an on-wire representation of the test packet and clone it. - Pkt6Ptr clone = packAndClone(); + Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x020304)); + Pkt6Ptr clone = packAndClone(pkt); // Install the custom callback function. We expect that this function // will be called to parse options in the packet instead of @@ -1327,5 +1320,82 @@ TEST_F(Pkt6Test, rsoo) { } +// Verify that the DUID can be extracted from the DHCPv6 packet +// holding Client Identifier option. +TEST_F(Pkt6Test, getClientId) { + // Create a packet. + Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x2312)); + // Initially, the packet should hold no DUID. + EXPECT_FALSE(pkt->getClientId()); + + // Create DUID and add it to the packet. + const uint8_t duid_data[] = { 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 0 }; + OptionBuffer duid_vec(duid_data, duid_data + sizeof(duid_data) - 1); + pkt->addOption(OptionPtr(new Option(Option::V6, D6O_CLIENTID, + duid_vec.begin(), + duid_vec.end()))); + + // Simulate the packet transmission over the wire, i.e. create on + // wire representation of the packet, and then parse it. + Pkt6Ptr pkt_clone = packAndClone(pkt); + ASSERT_NO_THROW(pkt_clone->unpack()); + + // This time the DUID should be returned. + DuidPtr duid = pkt_clone->getClientId(); + ASSERT_TRUE(duid); + + // And it should be equal to the one that we used to create + // the packet. + EXPECT_TRUE(duid->getDuid() == duid_vec); +} + +// This test verfies that it is possible to obtain the packet +// identifiers (DUID, HW Address, transaction id) in the textual +// format. +TEST_F(Pkt6Test, makeLabel) { + DuidPtr duid(new DUID(DUID::fromText("0102020202030303030303"))); + HWAddrPtr hwaddr(new HWAddr(HWAddr::fromText("01:02:03:04:05:06", + HTYPE_ETHER))); + + // Specify DUID and no HW Address. + EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], tid=0x123", + Pkt6::makeLabel(duid, 0x123, HWAddrPtr())); + + // Specify HW Address and no DUID. + EXPECT_EQ("duid=[no info], [hwtype=1 01:02:03:04:05:06], tid=0x123", + Pkt6::makeLabel(DuidPtr(), 0x123, hwaddr)); + + // Specify both DUID and HW Address. + EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], " + "[hwtype=1 01:02:03:04:05:06], tid=0x123", + Pkt6::makeLabel(duid, 0x123, hwaddr)); + + // Specify neither DUID nor HW Address. + EXPECT_EQ("duid=[no info], tid=0x0", + Pkt6::makeLabel(DuidPtr(), 0x0, HWAddrPtr())); +} + +// This test verifies that it is possible to obtain the packet +// identifiers in the textual format from the packet instance. +TEST_F(Pkt6Test, getLabel) { + // Create a packet. + Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x2312)); + EXPECT_EQ("duid=[no info], tid=0x2312", + pkt->getLabel()); + + DuidPtr duid(new DUID(DUID::fromText("0102020202030303030303"))); + pkt->addOption(OptionPtr(new Option(Option::V6, D6O_CLIENTID, + duid->getDuid().begin(), + duid->getDuid().end()))); + + // Simulate the packet transmission over the wire, i.e. create on + // wire representation of the packet, and then parse it. + Pkt6Ptr pkt_clone = packAndClone(pkt); + ASSERT_NO_THROW(pkt_clone->unpack()); + + EXPECT_EQ("duid=[01:02:02:02:02:03:03:03:03:03:03], tid=0x2312", + pkt_clone->getLabel()); + +} }