From: Thomas Markwalder Date: Fri, 25 Oct 2013 10:31:05 +0000 (-0400) Subject: [3207] Replaced selected subnet with lease address in user check output X-Git-Tag: bind10-1.2.0beta1-release~167^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d130cf2cb4c0d294a43d47d989732e466a8be24a;p=thirdparty%2Fkea.git [3207] Replaced selected subnet with lease address in user check output User check hook library's outcome output is now generated in pkt_send callout allowing the output of lease address (or prefix) in place of selected subnet. --- diff --git a/src/hooks/dhcp/user_chk/pkt_send_co.cc b/src/hooks/dhcp/user_chk/pkt_send_co.cc index 7be256284a..4e9c6b6145 100644 --- a/src/hooks/dhcp/user_chk/pkt_send_co.cc +++ b/src/hooks/dhcp/user_chk/pkt_send_co.cc @@ -16,8 +16,12 @@ #include #include -#include #include +#include +#include +#include +#include +#include #include #include @@ -30,64 +34,14 @@ using namespace std; // issues related to namespaces. extern "C" { -/// @brief Adds an entry to the end of the user check outcome file. -/// -/// Each user entry is written in an ini-like format, with one name-value pair -/// per line as follows: -/// -/// id_type= -/// client= -/// subnet= -/// registered=" -/// -/// where: -/// text label of the id type: "HW_ADDR" or "DUID" -/// user's id formatted as either isc::dhcp::Hwaddr.toText() or -/// isc::dhcp::DUID.toText() -/// selected subnet formatted as isc::dhcp::Subnet4::toText() or -/// isc::dhcp::Subnet6::toText() as appropriate. -/// "yes" or "no" -/// -/// Sample IPv4 entry would like this: -/// -/// @code -/// id_type=DUID -/// client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04 -/// subnet=2001:db8:2::/64 -/// registered=yes -/// id_type=duid -/// @endcode -/// -/// Sample IPv4 entry would like this: -/// -/// @code -/// id_type=DUID -/// id_type=HW_ADDR -/// client=hwtype=1 00:0c:01:02:03:05 -/// subnet=152.77.5.0/24 -/// registered=no -/// @endcode -/// -/// @param id_type_str text label identify the id type -/// @param id_val_str text representation of the user id -/// @param subnet_str text representation of the selected subnet -/// @param registered boolean indicating if the user is registered or not -void generate_output_record(const std::string& id_type_str, +extern void generate_output_record(const std::string& id_type_str, const std::string& id_val_str, const std::string& addr_str, - const bool& registered) -{ - user_chk_output << "id_type=" << id_type_str << std::endl - << "client=" << id_val_str << std::endl - << "addr=" << addr_str << std::endl - << "registered=" << (registered ? "yes" : "no") - << std::endl; - - // @todo Flush is here to ensure output is immediate for demo purposes. - // Performance would generally dictate not using it. - flush(user_chk_output); -} - + const bool& registered); +extern std::string getV6AddrStr (Pkt6Ptr response); +extern std::string getAddrStrIA_NA(OptionPtr options); +extern std::string getAddrStrIA_PD(OptionPtr options); +extern bool checkIAStatus(boost::shared_ptr& ia_opt); /// @brief This callout is called at the "pkt4_send" hook. /// @@ -102,9 +56,22 @@ int pkt4_send(CalloutHandle& handle) { Pkt4Ptr response; handle.getArgument("response4", response); + // @todo do we need to filter on type? +#if 0 + uint8_t packet_type = response->getType(); + std::cout << "PACKET TYPE IS: " << + static_cast(packet_type) << std::endl; + + if ((packet_type != DHCPOFFER) && (packet_type != DHCPACK)) { + std::cout << "SKIPPING PACKET TYPE IS: " + << static_cast(packet_type) << std::endl; + return (0); + } +#endif + // Get the user id saved from the query packet. HWAddrPtr hwaddr; - handle.setContext(query_user_id_label, hwaddr); + handle.getContext(query_user_id_label, hwaddr); // Get registered_user pointer. UserPtr registered_user; @@ -123,9 +90,9 @@ int pkt4_send(CalloutHandle& handle) { generate_output_record(UserId::HW_ADDRESS_STR, hwaddr->toText(), addr.toText(), true); } else { - // add default options based + // add default options based // then generate not registered output record - std::cout << "DHCP UserCheckHook : pkt4_send no registered_user" + std::cout << "DHCP UserCheckHook : pkt4_send no registered_user" << std::endl; // Add the outcome entry to the output file. generate_output_record(UserId::HW_ADDRESS_STR, hwaddr->toText(), @@ -153,12 +120,32 @@ int pkt6_send(CalloutHandle& handle) { Pkt6Ptr response; handle.getArgument("response6", response); - // Fetch the lease address. @todo - isc::asiolink::IOAddress addr("0.0.0.0"); + // @todo do we need to filter on type? +#if 0 + uint8_t packet_type = response->getType(); + std::cout << "PACKET TYPE IS: " << + static_cast(packet_type) << std::endl; + + if ((packet_type != DHCPV6_ADVERTISE) && + (packet_type != DHCPV6_REPLY)) { + std::cout << "SKIPPING PACKET TYPE IS: " + << static_cast(packet_type) << std::endl; + return (0); + } +#endif + + // Fetch the lease address as a string + std::string addr_str = getV6AddrStr(response); + if (addr_str.empty()) { + // packet did not contain an address, must be failed. + std::cout << "pkt6_send: Skipping packet address is blank" + << std::endl; + return (0); + } // Get the user id saved from the query packet. DuidPtr duid; - handle.setContext(query_user_id_label, duid); + handle.getContext(query_user_id_label, duid); // Get registered_user pointer. UserPtr registered_user; @@ -171,15 +158,15 @@ int pkt6_send(CalloutHandle& handle) { << registered_user->getUserId() << std::endl; // Add the outcome entry to the output file. generate_output_record(UserId::DUID_STR, duid->toText(), - addr.toText(), true); + addr_str, true); } else { - // add default options based + // add default options based // then generate not registered output record - std::cout << "DHCP UserCheckHook : pkt6_send no registered_user" + std::cout << "DHCP UserCheckHook : pkt6_send no registered_user" << std::endl; // Add the outcome entry to the output file. generate_output_record(UserId::DUID_STR, duid->toText(), - addr.toText(), false); + addr_str, false); } } catch (const std::exception& ex) { std::cout << "DHCP UserCheckHook : pkt6_send unexpected error: " @@ -190,4 +177,162 @@ int pkt6_send(CalloutHandle& handle) { return (0); } +/// @brief Adds an entry to the end of the user check outcome file. +/// +/// Each user entry is written in an ini-like format, with one name-value pair +/// per line as follows: +/// +/// id_type= +/// client= +/// subnet= +/// registered=" +/// +/// where: +/// text label of the id type: "HW_ADDR" or "DUID" +/// user's id formatted as either isc::dhcp::Hwaddr.toText() or +/// isc::dhcp::DUID.toText() +/// selected subnet formatted as isc::dhcp::Subnet4::toText() or +/// isc::dhcp::Subnet6::toText() as appropriate. +/// "yes" or "no" +/// +/// Sample IPv4 entry would like this: +/// +/// @code +/// id_type=DUID +/// client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04 +/// subnet=2001:db8:2::/64 +/// registered=yes +/// id_type=duid +/// @endcode +/// +/// Sample IPv4 entry would like this: +/// +/// @code +/// id_type=DUID +/// id_type=HW_ADDR +/// client=hwtype=1 00:0c:01:02:03:05 +/// subnet=152.77.5.0/24 +/// registered=no +/// @endcode +/// +/// @param id_type_str text label identify the id type +/// @param id_val_str text representation of the user id +/// @param subnet_str text representation of the selected subnet +/// @param registered boolean indicating if the user is registered or not +void generate_output_record(const std::string& id_type_str, + const std::string& id_val_str, + const std::string& addr_str, + const bool& registered) +{ + user_chk_output << "id_type=" << id_type_str << std::endl + << "client=" << id_val_str << std::endl + << "addr=" << addr_str << std::endl + << "registered=" << (registered ? "yes" : "no") + << std::endl; + + // @todo Flush is here to ensure output is immediate for demo purposes. + // Performance would generally dictate not using it. + flush(user_chk_output); +} + +/// @brief Stringify the lease address or prefix IPv6 response packet +std::string getV6AddrStr (Pkt6Ptr response) { + OptionPtr tmp = response->getOption(D6O_IA_NA); + if (tmp) { + return(getAddrStrIA_NA(tmp)); + } + + // IA_NA not there so try IA_PD + tmp = response->getOption(D6O_IA_PD); + if (!tmp) { + isc_throw (isc::BadValue, "Response has neither IA_NA nor IA_PD"); + } + + return(getAddrStrIA_PD(tmp)); +} + +/// @brief Stringify the lease address in an D6O_IA_NA option set +/// @todo fill out this out +std::string getAddrStrIA_NA(OptionPtr options) { + boost::shared_ptr ia = + boost::dynamic_pointer_cast(options); + + if (!ia) { + isc_throw (isc::BadValue, "D6O_IA_NA option invalid"); + } + + // If status indicates a failure return a blank string. + if (!checkIAStatus(ia)) { + return (std::string("")); + } + + options = ia->getOption(D6O_IAADDR); + if (!options) { + isc_throw (isc::BadValue, "D6O_IAADDR option missing"); + } + + boost::shared_ptr addr_option; + addr_option = boost::dynamic_pointer_cast(options); + if (!addr_option) { + isc_throw (isc::BadValue, "D6O_IAADDR Option6IAAddr missing"); + } + + isc::asiolink::IOAddress addr = addr_option->getAddress(); + return (addr.toText()); +} + +/// @brief Stringify the delegated prefix in an D6O_IA_DP option set +std::string getAddrStrIA_PD(OptionPtr options) { + boost::shared_ptr ia = + boost::dynamic_pointer_cast(options); + + if (!ia) { + isc_throw (isc::BadValue, "D6O_IA_PD option invalid"); + } + + // If status indicates a failure return a blank string. + if (!checkIAStatus(ia)) { + return (std::string("")); + } + + options = ia->getOption(D6O_IAPREFIX); + if (!options) { + isc_throw(isc::BadValue, "D60_IAPREFIX option is missing"); + } + + boost::shared_ptr addr_option; + addr_option = boost::dynamic_pointer_cast(options); + if (!addr_option) { + isc_throw (isc::BadValue, "D6O_IA_PD addr option bad"); + } + + isc::asiolink::IOAddress addr = addr_option->getAddress(); + uint8_t prefix_len = addr_option->getLength(); + + stringstream buf; + buf << addr.toText() << "/" << static_cast(prefix_len); + return (buf.str()); +} + +/// @brief Tests given IA option set for successful status. +/// @todo fill out this out +bool checkIAStatus(boost::shared_ptr& ia) { + OptionCustomPtr status = + boost::dynamic_pointer_cast + (ia->getOption(D6O_STATUS_CODE)); + + // If a non-zero status is present, bail. + if (status) { + int status_val = status->readInteger(0); + if (status_val != 0) { + std::cout << "SKIPPING PACKET STATUS is not success:" + << status_val << std::endl; + return (false); + } + } + + return (true); +} + + } // end extern "C"