Browse Source

[3207] Added callouts for packet receive and send to user check hooks lib

Initial checkin creates callout functions for packet receive and send
hooks for IPv4 and IPv6.  This sets thes stage for outputting user specific
options in outbound packet.
Thomas Markwalder 11 years ago
parent
commit
327d9ff442

+ 3 - 0
src/hooks/dhcp/user_chk/Makefile.am

@@ -34,8 +34,11 @@ CLEANFILES = *.gcno *.gcda
 lib_LTLIBRARIES = libdhcp_user_chk.la
 libdhcp_user_chk_la_SOURCES  =
 libdhcp_user_chk_la_SOURCES += load_unload.cc
+libdhcp_user_chk_la_SOURCES += pkt_receive_co.cc
+libdhcp_user_chk_la_SOURCES += pkt_send_co.cc
 libdhcp_user_chk_la_SOURCES += subnet_select_co.cc
 libdhcp_user_chk_la_SOURCES += user.cc user.h
+libdhcp_user_chk_la_SOURCES += user_chk.h
 # Until logging in dynamically loaded libraries is fixed, exclude these.
 #libdhcp_user_chk_la_SOURCES += user_chk_log.cc user_chk_log.h
 libdhcp_user_chk_la_SOURCES += user_data_source.h

+ 6 - 0
src/hooks/dhcp/user_chk/load_unload.cc

@@ -38,6 +38,12 @@ const char* registry_fname = "/tmp/user_chk_registry.txt";
 /// @todo Hard-coded for now, this should be configurable.
 const char* user_chk_output_fname = "/tmp/user_chk_outcome.txt";
 
+/// @brief Text label of user id in the inbound query in callout context
+const char* query_user_id_label = "query_user_id_label";
+
+/// @brief Text label of registered user pointer in callout context
+const char* registered_user_label = "registered_user";
+
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // mangling that accompanies use of the C++ compiler as well as to avoid
 // issues related to namespaces.

+ 131 - 0
src/hooks/dhcp/user_chk/pkt_receive_co.cc

@@ -0,0 +1,131 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// @file Defines the pkt4_receive and pkt6_receive callout functions.
+
+#include <hooks/hooks.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/pkt6.h>
+#include <user_chk.h>
+
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace std;
+
+// Functions accessed by the hooks framework use C linkage to avoid the name
+// mangling that accompanies use of the C++ compiler as well as to avoid
+// issues related to namespaces.
+extern "C" {
+
+/// @brief  This callout is called at the "pkt4_receive" hook.
+///
+/// This function searches the UserRegistry for the client indicated by the
+/// inbound IPv4 DHCP packet. If the client is found  @todo
+///
+/// @param handle CalloutHandle which provides access to context.
+///
+/// @return 0 upon success, non-zero otherwise.
+int pkt4_receive(CalloutHandle& handle) {
+    if (!user_registry) {
+        std::cout << "DHCP UserCheckHook : pkt4_receive UserRegistry is null"
+                  << std::endl;
+        return (1);
+    }
+
+    try {
+        // Refresh the registry.
+        user_registry->refresh();
+
+        // Get the HWAddress to use as the user identifier.
+        Pkt4Ptr query;
+        handle.getArgument("query4", query);
+        HWAddrPtr hwaddr = query->getHWAddr();
+
+        // Store the id we search with.
+        handle.setContext(query_user_id_label, hwaddr);
+
+        // Look for the user in the registry.
+        UserPtr registered_user = user_registry->findUser(*hwaddr);
+
+        // store user regardless, empty user pointer means non-found
+        // cheaper than exception throw overhead
+        handle.setContext(registered_user_label, registered_user);
+        std::cout << "DHCP UserCheckHook : pkt4_receive user : "
+                  << hwaddr->toText() << " is " 
+                  << (registered_user ? " registered" : " not registere")
+                  << std::endl;
+    } catch (const std::exception& ex) {
+        std::cout << "DHCP UserCheckHook : pkt4_receive unexpected error: "
+                  << ex.what() << std::endl;
+        return (1);
+    }
+
+    return (0);
+}
+
+/// @brief  This callout is called at the "pkt6_receive" hook.
+///
+/// This function searches the UserRegistry for the client indicated by the
+/// inbound IPv6 DHCP packet. If the client is found  @todo
+///
+/// @param handle CalloutHandle which provides access to context.
+///
+/// @return 0 upon success, non-zero otherwise.
+int pkt6_receive(CalloutHandle& handle) {
+    if (!user_registry) {
+        std::cout << "DHCP UserCheckHook : pkt6_receive UserRegistry is null"
+                  << std::endl;
+        return (1);
+    }
+
+    try {
+        // Refresh the registry.
+        user_registry->refresh();
+
+        // Fetch the inbound packet.
+        Pkt6Ptr query;
+        handle.getArgument("query6", query);
+
+        // Get the DUID to use as the user identifier.
+        OptionPtr opt_duid = query->getOption(D6O_CLIENTID);
+        if (!opt_duid) {
+            std::cout << "DHCP6 query is missing DUID" << std::endl;
+            return (1);
+        }
+        DuidPtr duid = DuidPtr(new DUID(opt_duid->getData()));
+
+        // Store the id we search with.
+        handle.setContext(query_user_id_label, duid);
+
+        // Look for the user in the registry.
+        UserPtr registered_user = user_registry->findUser(*duid);
+
+        // store user regardless, empty user pointer means non-found
+        // cheaper than exception throw overhead
+        handle.setContext(registered_user_label, registered_user);
+        std::cout << "DHCP UserCheckHook : pkt6_receive user : "
+                  << duid->toText() << " is " 
+                  << (registered_user ? " registered" : " not registere")
+                  << std::endl;
+    } catch (const std::exception& ex) {
+        std::cout << "DHCP UserCheckHook : pkt6_receive unexpected error: "
+                  << ex.what() << std::endl;
+        return (1);
+    }
+
+    return (0);
+}
+
+} // end extern "C"

+ 193 - 0
src/hooks/dhcp/user_chk/pkt_send_co.cc

@@ -0,0 +1,193 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+/// @file Defines the pkt4_send and pkt6_send callout functions.
+
+#include <asiolink/io_address.h>
+#include <hooks/hooks.h>
+#include <dhcp/pkt4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/pkt6.h>
+#include <user_chk.h>
+
+using namespace isc::dhcp;
+using namespace isc::hooks;
+using namespace std;
+
+// Functions accessed by the hooks framework use C linkage to avoid the name
+// mangling that accompanies use of the C++ compiler as well as to avoid
+// 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=<id type>
+/// client=<id str>
+/// subnet=<subnet str>
+/// registered=<is registered>"
+///
+/// where:
+/// <id type> text label of the id type: "HW_ADDR" or "DUID"
+/// <id str> user's id formatted as either isc::dhcp::Hwaddr.toText() or
+/// isc::dhcp::DUID.toText()
+/// <subnet str> selected subnet formatted as isc::dhcp::Subnet4::toText() or
+/// isc::dhcp::Subnet6::toText() as appropriate.
+/// <is registered> "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  This callout is called at the "pkt4_send" hook.
+///
+/// This function searches the UserRegistry for the client indicated by the
+/// inbound IPv4 DHCP packet. If the client is found  @todo
+///
+/// @param handle CalloutHandle which provides access to context.
+///
+/// @return 0 upon success, non-zero otherwise.
+int pkt4_send(CalloutHandle& handle) {
+    try {
+        Pkt4Ptr response;
+        handle.getArgument("response4", response);
+
+        // Get the user id saved from the query packet.
+        HWAddrPtr hwaddr;
+        handle.setContext(query_user_id_label, hwaddr);
+
+        // Get registered_user pointer.
+        UserPtr registered_user;
+        handle.getContext(registered_user_label, registered_user);
+
+        // Fetch the lease address.
+        isc::asiolink::IOAddress addr = response->getYiaddr();
+
+        if (registered_user) {
+            // add options based on user
+            // then generate registered output record
+            std::cout << "DHCP UserCheckHook : pkt4_send registered_user is: "
+                      << registered_user->getUserId() << std::endl;
+
+            // Add the outcome entry to the output file.
+            generate_output_record(UserId::HW_ADDRESS_STR, hwaddr->toText(),
+                                   addr.toText(), true);
+        } else {
+            // add default options based 
+            // then generate not registered output record
+            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(),
+                                   addr.toText(), false);
+        }
+    } catch (const std::exception& ex) {
+        std::cout << "DHCP UserCheckHook : pkt4_send unexpected error: "
+                  << ex.what() << std::endl;
+        return (1);
+    }
+
+    return (0);
+}
+
+/// @brief  This callout is called at the "pkt6_send" hook.
+///
+/// This function searches the UserRegistry for the client indicated by the
+/// inbound IPv6 DHCP packet. If the client is found  @todo
+///
+/// @param handle CalloutHandle which provides access to context.
+///
+/// @return 0 upon success, non-zero otherwise.
+int pkt6_send(CalloutHandle& handle) {
+    try {
+        Pkt6Ptr response;
+        handle.getArgument("response6", response);
+
+        // Fetch the lease address. @todo
+        isc::asiolink::IOAddress addr("0.0.0.0");
+
+        // Get the user id saved from the query packet.
+        DuidPtr duid;
+        handle.setContext(query_user_id_label, duid);
+
+        // Get registered_user pointer.
+        UserPtr registered_user;
+        handle.getContext(registered_user_label, registered_user);
+
+        if (registered_user) {
+            // add options based on user
+            // then generate registered output record
+            std::cout << "DHCP UserCheckHook : pkt6_send registered_user is: "
+                      << registered_user->getUserId() << std::endl;
+            // Add the outcome entry to the output file.
+            generate_output_record(UserId::DUID_STR, duid->toText(),
+                                   addr.toText(), true);
+        } else {
+            // add default options based 
+            // then generate not registered output record
+            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);
+        }
+    } catch (const std::exception& ex) {
+        std::cout << "DHCP UserCheckHook : pkt6_send unexpected error: "
+                  << ex.what() << std::endl;
+        return (1);
+    }
+
+    return (0);
+}
+
+} // end extern "C"

+ 7 - 105
src/hooks/dhcp/user_chk/subnet_select_co.cc

@@ -19,83 +19,17 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
 #include <dhcpsrv/subnet.h>
-#include <user_registry.h>
-
-#include <fstream>
-#include <string>
+#include <user_chk.h>
 
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace std;
 
-extern UserRegistryPtr user_registry;
-extern std::fstream user_chk_output;
-extern const char* registry_fname;
-extern const char* user_chk_output_fname;
-
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // mangling that accompanies use of the C++ compiler as well as to avoid
 // 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=<id type>
-/// client=<id str>
-/// subnet=<subnet str>
-/// registered=<is registered>"
-///
-/// where:
-/// <id type> text label of the id type: "HW_ADDR" or "DUID"
-/// <id str> user's id formatted as either isc::dhcp::Hwaddr.toText() or
-/// isc::dhcp::DUID.toText()
-/// <subnet str> selected subnet formatted as isc::dhcp::Subnet4::toText() or
-/// isc::dhcp::Subnet6::toText() as appropriate.
-/// <is registered> "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& subnet_str,
-                            const bool& registered)
-{
-    user_chk_output << "id_type=" << id_type_str << std::endl
-                    << "client=" << id_val_str << std::endl
-                    << "subnet=" << subnet_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  This callout is called at the "subnet4_select" hook.
 ///
 /// This function searches the UserRegistry for the client indicated by the
@@ -125,32 +59,20 @@ int subnet4_select(CalloutHandle& handle) {
             return 0;
         }
 
-        // Refresh the registry.
-        user_registry->refresh();
-
-        // Get the HWAddress as the user identifier.
-        Pkt4Ptr query;
-        handle.getArgument("query4", query);
-        HWAddrPtr hwaddr = query->getHWAddr();
+        // Get registered_user pointer.
+        UserPtr registered_user;
+        handle.getContext(registered_user_label, registered_user);
 
-        // Look for the user.
-        UserPtr registered_user = user_registry->findUser(*hwaddr);
         if (registered_user) {
             // User is in the registry, so leave the pre-selected subnet alone.
             Subnet4Ptr subnet;
             handle.getArgument("subnet4", subnet);
-            // Add the outcome entry to the output file.
-            generate_output_record(UserId::HW_ADDRESS_STR, hwaddr->toText(),
-                                   subnet->toText(), true);
         } else {
             // User is not in the registry, so assign them to the last subnet
             // in the collection.  By convention we are assuming this is the
             // restricted subnet.
             Subnet4Ptr subnet = subnets->back();
             handle.setArgument("subnet4", subnet);
-            // Add the outcome entry to the output file.
-            generate_output_record(UserId::HW_ADDRESS_STR, hwaddr->toText(),
-                                   subnet->toText(), false);
         }
     } catch (const std::exception& ex) {
         std::cout << "DHCP UserCheckHook : subnet6_select unexpected error: "
@@ -190,40 +112,20 @@ int subnet6_select(CalloutHandle& handle) {
             return 0;
         }
 
-        // Refresh the registry.
-        user_registry->refresh();
-
-        // Get the HWAddress as the user identifier.
-        Pkt6Ptr query;
-        handle.getArgument("query6", query);
-
-        DuidPtr duid;
-        OptionPtr opt_duid = query->getOption(D6O_CLIENTID);
-        if (!opt_duid) {
-            std::cout << "DHCP6 query is missing DUID" << std::endl;
-            return (1);
-        }
-
-        duid = DuidPtr(new DUID(opt_duid->getData()));
+        // Get registered_user pointer. 
+        UserPtr registered_user;
+        handle.getContext(registered_user_label, registered_user);
 
-        // Look for the user.
-        UserPtr registered_user = user_registry->findUser(*duid);
         if (registered_user) {
             // User is in the registry, so leave the pre-selected subnet alone.
             Subnet6Ptr subnet;
             handle.getArgument("subnet6", subnet);
-            // Add the outcome entry to the output file.
-            generate_output_record(UserId::DUID_STR, duid->toText(),
-                                   subnet->toText(), true);
         } else {
             // User is not in the registry, so assign them to the last subnet
             // in the collection.  By convention we are assuming this is the
             // restricted subnet.
             Subnet6Ptr subnet = subnets->back();
             handle.setArgument("subnet6", subnet);
-            // Add the outcome entry to the output file.
-            generate_output_record(UserId::DUID_STR, duid->toText(),
-                                   subnet->toText(), false);
         }
     } catch (const std::exception& ex) {
         std::cout << "DHCP UserCheckHook : subnet6_select unexpected error: "

+ 3 - 0
src/hooks/dhcp/user_chk/tests/Makefile.am

@@ -34,9 +34,12 @@ TESTS += libdhcp_user_chk_unittests
 
 libdhcp_user_chk_unittests_SOURCES  = 
 libdhcp_user_chk_unittests_SOURCES += ../load_unload.cc
+libdhcp_user_chk_unittests_SOURCES += ../pkt_receive_co.cc
+libdhcp_user_chk_unittests_SOURCES += ../pkt_send_co.cc
 libdhcp_user_chk_unittests_SOURCES += ../subnet_select_co.cc
 libdhcp_user_chk_unittests_SOURCES += ../version.cc
 libdhcp_user_chk_unittests_SOURCES += ../user.cc ../user.h
+libdhcp_user_chk_unittests_SOURCES += ../user_chk.h
 # Until logging in dynamically loaded libraries is fixed, exclude these.
 #libdhcp_user_chk_unittests_SOURCES += ../user_chk_log.cc ../user_chk_log.h
 #libdhcp_user_chk_unittests_SOURCES += ../user_chk_messages.cc ../user_chk_messages.h

+ 30 - 0
src/hooks/dhcp/user_chk/user_chk.h

@@ -0,0 +1,30 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+#ifndef USER_CHK_H
+#define USER_CHK_H
+
+#include <user_registry.h>
+#include <fstream>
+#include <string>
+
+using namespace std;
+
+extern UserRegistryPtr user_registry;
+extern std::fstream user_chk_output;
+extern const char* registry_fname;
+extern const char* user_chk_output_fname;
+extern const char* query_user_id_label;
+extern const char* registered_user_label;
+
+#endif