Browse Source

[3207] Addressed review comments.

Addressed review comments which were largely minor. Limited use of
extern C linkage to only the callout functions themselves. Added
a dox page describing the library.  Added namespace user_chk.
Thomas Markwalder 11 years ago
parent
commit
2f2d2cfd4d

+ 1 - 0
doc/Doxyfile

@@ -667,6 +667,7 @@ INPUT                  = ../src/bin/auth \
                          ../src/bin/dhcp6 \
                          ../src/bin/dhcp6 \
                          ../src/bin/resolver \
                          ../src/bin/resolver \
                          ../src/bin/sockcreator \
                          ../src/bin/sockcreator \
+                         ../src/hooks/dhcp/user_chk \
                          ../src/lib/acl \
                          ../src/lib/acl \
                          ../src/lib/asiolink \
                          ../src/lib/asiolink \
                          ../src/lib/bench \
                          ../src/lib/bench \

+ 1 - 0
doc/devel/mainpage.dox

@@ -46,6 +46,7 @@
  * - @subpage dhcpv6Hooks
  * - @subpage dhcpv6Hooks
  * - @subpage hooksComponentDeveloperGuide
  * - @subpage hooksComponentDeveloperGuide
  * - @subpage hooksmgMaintenanceGuide
  * - @subpage hooksmgMaintenanceGuide
+ * - @subpage libdhcp_user_chk
  *
  *
  * @section dnsMaintenanceGuide DNS Maintenance Guide
  * @section dnsMaintenanceGuide DNS Maintenance Guide
  * - Authoritative DNS (todo)
  * - Authoritative DNS (todo)

+ 1 - 1
src/hooks/dhcp/user_chk/Makefile.am

@@ -25,7 +25,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 BUILT_SOURCES =
 BUILT_SOURCES =
 
 
 # Ensure that the message file is included in the distribution
 # Ensure that the message file is included in the distribution
-EXTRA_DIST =
+EXTRA_DIST = libdhcp_user_chk.dox
 
 
 # Get rid of generated message files on a clean
 # Get rid of generated message files on a clean
 #CLEANFILES = *.gcno *.gcda user_chk_messages.h user_chk_messages.cc s-messages
 #CLEANFILES = *.gcno *.gcda user_chk_messages.h user_chk_messages.cc s-messages

+ 199 - 0
src/hooks/dhcp/user_chk/libdhcp_user_chk.dox

@@ -0,0 +1,199 @@
+// 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.
+
+/**
+@page libdhcp_user_chk DHCP User Check Hooks Library
+
+@section libdhcp_user_chkIntro Libdhcp_user_chk: An Example Hooks Library
+## Introduction
+libdhcp_user_chk is an example hooks library which customizes the DHCP query
+processing provided by BIND X DHCP server modules (b10-dhcp4 and b10-dhcp6).
+Specifically it allows subnet selection and DHCP response option customization
+based upon a registry of DHCP clients.  Note that the words "client" and "user" are used interchangeably herein.  The intent of the custom behavior is three
+fold:
+
+1. To assign "new" or "unregistered" users to a restricted subnet, while "known"
+or "registered" users are assigned to unrestricted subnets.
+
+2. To allow DHCP response options or vendor option values to be customized
+based upon user identity.
+
+3. To provide a real time record of the user registration activity which can be sampled by an external consumer.
+
+## User Registry Classes
+At the heart of the library is a class hierarchy centered around the class,
+user_chk::UserRegistry.  This class represents a maintainable, searchable
+registry of "known" users and their attributes.  It provides services to load,
+clear, and refresh the registry as well as to add, find, and remove users.
+
+Each entry in the registry is an instance of the class, user_chk::User. Users
+are uniquely identified by their user_chk::UserId. UserIds are comprised of
+data taken from the DHCP request. IPv4 users have a type of "HW_ADDR" and
+their id is the hardware address from the request.  IPv6 users have a type of
+"DUID" and their id is the DUID from the request.
+
+The registry may be manually populated or loaded from a source of data which
+implements the UserDataSource interface. Currently, a single implementation has
+been implemented, user_chk::UserFile. UserFile supports reading the registry
+from a text file in which each line is a user entry in JSON format.  Each entry
+contains the id type and user id along with optional attributes.  Attributes are
+essentially name/value pairs whose significance is left up to the calling layer.
+UserFile does not enforce any specific content beyond id type and id.
+(See user_file.h for more details on file content).
+
+## Callout Processing
+The library implements callouts for packet receive, subnet select, and packet
+send for both IPv4 and IPv6.  Regardless of the protocol type, the process
+flow upon receipt of an inbound request is the same and is as follows:
+
+-# pkt_receive callout is invoked
+    -# Refresh the user registry
+    -# Extract user id from DHCP request and store it to context
+    -#  Look up user id in registry and store resultant user pointer to context
+
+    Note that each time a packet is received, the user registry is refreshed.
+    This ensures that the registry content always has the latest external
+    updates.  The primary goal at this stage is check the registry for the
+    user and push the result to the context making it available to subsequent
+    callouts.
+
+-# subnet_select callout is invoked
+    -# Retrieve the user pointer from context
+    -# If pointer is null (i.e. user is not registered), replace subnet
+    selection with restricted subnet
+
+    By convention, the last subnet in the collection of subnets available is
+    assumed to be the "restricted access" subnet. A more sophisticated mechanism    is likely to be needed.
+
+-# pkt_send callout is invoked:
+    -# Retrieve the user id and user pointer from context
+    -# If user is not null add the options based on user's attributes,
+    otherwise use default user's attributes
+    -# Generate user check outcome
+
+    This final step is what produces the real time record, referred to as the
+    "user check outcome" file.
+
+## Using the library
+Two steps are required in order to use the library:
+-# The user registry file must be created and deployed
+-# The BIND10 DHCP module(s) must be configured to load the library
+
+### Creating the Registry File
+Currently, the library uses a hard coded pathname for the user registry defined
+in load_unload.cc:
+
+    const char* registry_fname = "/tmp/user_chk_registry.txt";
+
+Each line in the file is a self-contained JSON snippet which must have the
+following two entries:
+
+    - "type" whose value is "HW_ADDR" for IPv4 users or "DUID" for IPv6 users
+    - "id" whose value is either the hardware address or the DUID from the
+    request formatted as a sring of hex digits, without delimiters.
+
+and may have the one or more of the following entries:
+
+    - "bootfile" whose value is the pathname of the desired file
+    - "tftp_server" whose value is the hostname or IP address of the desired
+    server
+
+Sample user registry file is shown below:
+
+@code
+{ "type" : "HW_ADDR", "id" : "0c0e0a01ff04", "bootfile" : "/tmp/v4bootfile" }
+{ "type" : "HW_ADDR", "id" : "0c0e0a01ff06", "tftp_server" : "tftp.v4.example.com" }
+{ "type" : "DUID", "id" : "0001000119efe63b000c01020304", "bootfile" : "/tmp/v6bootfile" }
+{ "type" : "DUID", "id" : "0001000119efe63b000c01020306", "tftp_server" : "tftp.v6.example.com" }
+@endcode
+
+Note, that it is possible to specify additional attributes. They will be loaded and stored with the user's entry in the registry. This allows the library to be
+extended to perform additional actions based on these attributes.
+
+Upon start up the library will attempt to load this file.  If it does not exist
+the library will unload.
+
+### Configuring the DHCP Modules
+it must be configured as a hook library for the
+desired DHCP server modules.  Note that the user_chk library is installed alongside the BIND10 libraries in "<install-dir>/lib" where <install-dir> is determined by the --prefix option of the configure script.  It defaults to "/usr/local". Assuming the default value then, configuring b10-dhcp4 to load the user_chk
+library could be done with the following BIND10 configuration commands:
+
+@code
+config add Dhcp4/hook_libraries
+config set Dhcp4/hook_libraries[0] "/usr/local/lib/libdhcp_user_chk.so"
+config commit
+@endcode
+
+To configure it for b10-dhcp6, the commands are simply as shown below:
+
+@code
+config add Dhcp6/hook_libraries
+config set Dhcp6/hook_libraries[0] "/usr/local/lib/libdhcp_user_chk.so"
+config commit
+@endcode
+
+## User Check Outcome
+Once up and running, the library should begin adding entries to the outcome
+file.  Currently, the library uses a hard coded pathname for the user registry defined in load_unload.cc:
+
+    const char* user_chk_output_fname = "/tmp/user_chk_outcome.txt";
+
+If the file cannot be created (or opened), the library will unload.
+
+For each lease granted, the library will add the following information to the
+end of the file: the id type, the user id, the lease or prefix granted, and
+whether or not the user was found in the registry.  This information is written
+in the form of "name=value" with one value per line.  (See subnet_callout.cc for details.)
+
+A sample outcome file is shown below:
+
+@code
+id_type=HW_ADDR
+client=hwtype=1 0c:0e:0a:01:ff:04
+addr=175.16.1.100
+registered=yes
+id_type=HW_ADDR
+client=hwtype=1 0c:0e:0a:01:ff:05
+addr=152.0.2.10
+registered=no
+id_type=HW_ADDR
+client=hwtype=1 0c:0e:0a:01:ff:06
+addr=175.16.1.101
+registered=yes
+id_type=HW_ADDR
+client=hwtype=1 0c:0e:0a:01:ff:04
+addr=175.16.1.102
+registered=yes
+id_type=DUID
+client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04
+addr=2001:db8:2::1:0:0/96
+registered=yes
+id_type=DUID
+client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04
+addr=2001:db8:2::
+registered=yes
+id_type=DUID
+client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:05
+addr=5005:778:2::
+registered=no
+id_type=DUID
+client=00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06
+addr=2001:db8:2::1
+registered=yes
+@endcode
+
+Note the library always opens this file in append mode and does not limit its size.
+
+
+*/

+ 9 - 2
src/hooks/dhcp/user_chk/load_unload.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-/// @file This file defines the load and unload hooks library functions.
+/// @file load_unload.cc Defines the load and unload hooks library functions.
 
 
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <user_registry.h>
 #include <user_registry.h>
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <errno.h>
 
 
 using namespace isc::hooks;
 using namespace isc::hooks;
+using namespace user_chk;
 
 
 /// @brief Pointer to the registry instance.
 /// @brief Pointer to the registry instance.
 UserRegistryPtr user_registry;
 UserRegistryPtr user_registry;
@@ -39,15 +40,21 @@ const char* registry_fname = "/tmp/user_chk_registry.txt";
 const char* user_chk_output_fname = "/tmp/user_chk_outcome.txt";
 const char* user_chk_output_fname = "/tmp/user_chk_outcome.txt";
 
 
 /// @brief Text label of user id in the inbound query in callout context
 /// @brief Text label of user id in the inbound query in callout context
-const char* query_user_id_label = "query_user_id_label";
+const char* query_user_id_label = "query_user_id";
 
 
 /// @brief Text label of registered user pointer in callout context
 /// @brief Text label of registered user pointer in callout context
 const char* registered_user_label = "registered_user";
 const char* registered_user_label = "registered_user";
 
 
 /// @brief Text id used to identify the default IPv4 user in the registry
 /// @brief Text id used to identify the default IPv4 user in the registry
+/// The format is a string containing an even number of hex digits.  This
+/// value is to look up the default IPv4 user in the user registry for the
+/// the purpose of retrieving default values for user options.
 const char* default_user4_id_str = "00000000";
 const char* default_user4_id_str = "00000000";
 
 
 /// @brief Text id used to identify the default IPv6 user in the registry
 /// @brief Text id used to identify the default IPv6 user in the registry
+/// The format is a string containing an even number of hex digits.  This
+/// value is to look up the default IPv6 user in the user registry for the
+/// the purpose of retrieving default values for user options.
 const char *default_user6_id_str = "00000000";
 const char *default_user6_id_str = "00000000";
 
 
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // Functions accessed by the hooks framework use C linkage to avoid the name

+ 2 - 1
src/hooks/dhcp/user_chk/pkt_receive_co.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-/// @file Defines the pkt4_receive and pkt6_receive callout functions.
+/// @file pkt_receive.cc Defines the pkt4_receive and pkt6_receive callout functions.
 
 
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
@@ -22,6 +22,7 @@
 
 
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::hooks;
+using namespace user_chk;
 using namespace std;
 using namespace std;
 
 
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // Functions accessed by the hooks framework use C linkage to avoid the name

+ 92 - 93
src/hooks/dhcp/user_chk/pkt_send_co.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-/// @file Defines the pkt4_send and pkt6_send callout functions.
+/// @file pkt_send.cc Defines the pkt4_send and pkt6_send callout functions.
 
 
 #include <asiolink/io_address.h>
 #include <asiolink/io_address.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
@@ -23,40 +23,41 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaprefix.h>
 #include <dhcp/option6_iaprefix.h>
+#include <dhcp/docsis3_option_defs.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/pkt6.h>
 #include <user_chk.h>
 #include <user_chk.h>
 
 
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::hooks;
+using namespace user_chk;
 using namespace std;
 using namespace std;
 
 
+// prototypes for local helper functions
+void generate_output_record(const std::string& id_type_str,
+                            const std::string& id_val_str,
+                            const std::string& addr_str,
+                            const bool& registered);
+std::string getV6AddrStr (Pkt6Ptr response);
+std::string getAddrStrIA_NA(OptionPtr options);
+std::string getAddrStrIA_PD(OptionPtr options);
+bool checkIAStatus(boost::shared_ptr<Option6IA>& ia_opt);
+
+void add4Options(Pkt4Ptr& response, const UserPtr& user);
+void add4Option(Pkt4Ptr& response, uint8_t opt_code, std::string& opt_value);
+void add6Options(Pkt6Ptr& response, const UserPtr& user);
+void add6Option(OptionPtr& vendor, uint8_t opt_code, std::string& opt_value);
+const UserPtr& getDefaultUser4();
+const UserPtr& getDefaultUser6();
+
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // 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
 // mangling that accompanies use of the C++ compiler as well as to avoid
 // issues related to namespaces.
 // issues related to namespaces.
 extern "C" {
 extern "C" {
 
 
-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);
-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<Option6IA>& ia_opt);
-
-extern void add4Options(Pkt4Ptr& response, const UserPtr& user);
-extern void add4Option(Pkt4Ptr& response, uint8_t opt_code,
-                        std::string& opt_value);
-extern void add6Options(Pkt6Ptr& response, const UserPtr& user);
-extern void add6Option(OptionPtr& vendor, uint8_t opt_code,
-                       std::string& opt_value);
-extern const UserPtr& getDefaultUser4();
-extern const UserPtr& getDefaultUser6();
-
 /// @brief  This callout is called at the "pkt4_send" hook.
 /// @brief  This callout is called at the "pkt4_send" hook.
 ///
 ///
-/// This function generates the user check outcome and adds vendor options
+/// This function generates the user check outcome and modifies options
 /// to the IPv4 response packet based on whether the user is registered or not.
 /// to the IPv4 response packet based on whether the user is registered or not.
 ///
 ///
 /// It retrieves a pointer to the registered user from the callout context.
 /// It retrieves a pointer to the registered user from the callout context.
@@ -77,7 +78,6 @@ int pkt4_send(CalloutHandle& handle) {
         Pkt4Ptr response;
         Pkt4Ptr response;
         handle.getArgument("response4", response);
         handle.getArgument("response4", response);
 
 
-        // @todo Determine list of types to process and skip the rest.
         uint8_t packet_type = response->getType();
         uint8_t packet_type = response->getType();
         if (packet_type == DHCPNAK) {
         if (packet_type == DHCPNAK) {
             std::cout << "DHCP UserCheckHook : pkt4_send"
             std::cout << "DHCP UserCheckHook : pkt4_send"
@@ -127,69 +127,9 @@ int pkt4_send(CalloutHandle& handle) {
     return (0);
     return (0);
 }
 }
 
 
-/// @brief Adds IPv4 options to the response packet based on given user
-///
-/// Adds or replaces IPv4 options with values from the given user, if
-/// the user has corresponding properties defined. Currently it supports
-/// the following options:
-///
-/// - DHO_BOOT_FILE_NAME from user property "bootfile"
-/// - DHO_TFTP_SERVER_NAME from user property "tftp_server"
-///
-/// @param response IPv4 response packet
-/// @param user User from whom properties are sourced
-void add4Options(Pkt4Ptr& response, const UserPtr& user) {
-    // If user is null, do nothing.
-    if (!user) {
-        return;
-    }
-
-    // If the user has bootfile property, update it in the response.
-    std::string opt_value = user->getProperty("bootfile");
-    if (!opt_value.empty()) {
-        std::cout << "DHCP UserCheckHook : add4Options "
-              << "adding boot file:" << opt_value << std::endl;
-
-        // Add boot file to packet.
-        add4Option(response, DHO_BOOT_FILE_NAME, opt_value);
-
-        // Boot file also goes in file field.
-        response->setFile((const uint8_t*)(opt_value.c_str()),
-                          opt_value.length());
-    }
-
-    // If the user has tftp server property, update it in the response.
-    opt_value = user->getProperty("tftp_server");
-    if (!opt_value.empty()) {
-        std::cout << "DHCP UserCheckHook : add4Options "
-              << "adding TFTP server:" << opt_value << std::endl;
-
-        // Add tftp server option to packet.
-        add4Option(response, DHO_TFTP_SERVER_NAME, opt_value);
-    }
-    // add next option here
-}
-
-/// @brief Adds/updates are specific IPv4 string option in response packet.
-///
-/// @param response IPV4 response packet to update
-/// @param opt_code DHCP standard numeric code of the option
-/// @param opt_value String value of the option
-void add4Option(Pkt4Ptr& response, uint8_t opt_code, std::string& opt_value) {
-    // Remove the option if it exists.
-    OptionPtr opt = response->getOption(opt_code);
-    if (opt) {
-        response->delOption(opt_code);
-    }
-
-    // Now add the option.
-    opt.reset(new OptionString(Option::V4, opt_code, opt_value));
-    response->addOption(opt);
-}
-
 /// @brief  This callout is called at the "pkt6_send" hook.
 /// @brief  This callout is called at the "pkt6_send" hook.
 ///
 ///
-/// This function generates the user check outcome and adds vendor options
+/// This function generates the user check outcome and modifies options
 /// to the IPv6 response packet based on whether the user is registered or not.
 /// to the IPv6 response packet based on whether the user is registered or not.
 ///
 ///
 /// It retrieves a pointer to the registered user from the callout context.
 /// It retrieves a pointer to the registered user from the callout context.
@@ -263,6 +203,69 @@ int pkt6_send(CalloutHandle& handle) {
     return (0);
     return (0);
 }
 }
 
 
+} // extern C
+
+/// @brief Adds IPv4 options to the response packet based on given user
+///
+/// Adds or replaces IPv4 options with values from the given user, if
+/// the user has corresponding properties defined. Currently it supports
+/// the following options:
+///
+/// - DHO_BOOT_FILE_NAME from user property "bootfile"
+/// - DHO_TFTP_SERVER_NAME from user property "tftp_server"
+///
+/// @param response IPv4 response packet
+/// @param user User from whom properties are sourced
+void add4Options(Pkt4Ptr& response, const UserPtr& user) {
+    // If user is null, do nothing.
+    if (!user) {
+        return;
+    }
+
+    // If the user has bootfile property, update it in the response.
+    std::string opt_value = user->getProperty("bootfile");
+    if (!opt_value.empty()) {
+        std::cout << "DHCP UserCheckHook : add4Options "
+              << "adding boot file:" << opt_value << std::endl;
+
+        // Add boot file to packet.
+        add4Option(response, DHO_BOOT_FILE_NAME, opt_value);
+
+        // Boot file also goes in file field.
+        response->setFile((const uint8_t*)(opt_value.c_str()),
+                          opt_value.length());
+    }
+
+    // If the user has tftp server property, update it in the response.
+    opt_value = user->getProperty("tftp_server");
+    if (!opt_value.empty()) {
+        std::cout << "DHCP UserCheckHook : add4Options "
+              << "adding TFTP server:" << opt_value << std::endl;
+
+        // Add tftp server option to packet.
+        add4Option(response, DHO_TFTP_SERVER_NAME, opt_value);
+    }
+    // add next option here
+}
+
+/// @brief Adds/updates are specific IPv4 string option in response packet.
+///
+/// @param response IPV4 response packet to update
+/// @param opt_code DHCP standard numeric code of the option
+/// @param opt_value String value of the option
+void add4Option(Pkt4Ptr& response, uint8_t opt_code, std::string& opt_value) {
+    // Remove the option if it exists.
+    OptionPtr opt = response->getOption(opt_code);
+    if (opt) {
+        response->delOption(opt_code);
+    }
+
+    // Now add the option.
+    opt.reset(new OptionString(Option::V4, opt_code, opt_value));
+    response->addOption(opt);
+}
+
+
 /// @brief Adds IPv6 vendor options to the response packet based on given user
 /// @brief Adds IPv6 vendor options to the response packet based on given user
 ///
 ///
 /// Adds or replaces IPv6 vendor options with values from the given user, if
 /// Adds or replaces IPv6 vendor options with values from the given user, if
@@ -279,7 +282,7 @@ void add6Options(Pkt6Ptr& response, const UserPtr& user) {
         return;
         return;
     }
     }
 
 
-    /// @todo: no packets have vendor opt... do we need to add it
+    /// @todo: if packets have no vendor opt... do we need to add it
     /// if its not there?  If so how?
     /// if its not there?  If so how?
     OptionPtr vendor = response->getOption(D6O_VENDOR_OPTS);
     OptionPtr vendor = response->getOption(D6O_VENDOR_OPTS);
     if (!vendor) {
     if (!vendor) {
@@ -288,17 +291,12 @@ void add6Options(Pkt6Ptr& response, const UserPtr& user) {
         return;
         return;
     }
     }
 
 
-    /// @todo: Use hard coded values (33,32) until we're merged.
-    /// Unfortunately, 3207 was branched from master before
-    /// 3194 was merged in, so this branch does not have
-    /// src/lib/dhcp/docsis3_option_defs.h.
-
     // If the user defines bootfile, set the option in response.
     // If the user defines bootfile, set the option in response.
     std::string opt_value = user->getProperty("bootfile");
     std::string opt_value = user->getProperty("bootfile");
     if (!opt_value.empty()) {
     if (!opt_value.empty()) {
         std::cout << "DHCP UserCheckHook : add6Options "
         std::cout << "DHCP UserCheckHook : add6Options "
                   << "adding boot file:" << opt_value << std::endl;
                   << "adding boot file:" << opt_value << std::endl;
-        add6Option(vendor, 33, opt_value);
+        add6Option(vendor, DOCSIS3_V6_CONFIG_FILE, opt_value);
     }
     }
 
 
     // If the user defines tftp server, set the option in response.
     // If the user defines tftp server, set the option in response.
@@ -307,7 +305,7 @@ void add6Options(Pkt6Ptr& response, const UserPtr& user) {
         std::cout << "DHCP UserCheckHook : add6Options "
         std::cout << "DHCP UserCheckHook : add6Options "
                   << "adding tftp server:" << opt_value << std::endl;
                   << "adding tftp server:" << opt_value << std::endl;
 
 
-        add6Option(vendor, 32, opt_value);
+        add6Option(vendor, DOCSIS3_V6_TFTP_SERVERS, opt_value);
     }
     }
 
 
     // add next option here
     // add next option here
@@ -390,14 +388,16 @@ void generate_output_record(const std::string& id_type_str,
 /// @brief Stringify the lease address or prefix IPv6 response packet
 /// @brief Stringify the lease address or prefix IPv6 response packet
 ///
 ///
 /// Converts the lease value, either an address or a prefix, into a string
 /// Converts the lease value, either an address or a prefix, into a string
-/// suitable for the user check outcome output.
+/// suitable for the user check outcome output.  Note that this will use
+/// the first address or prefix in the response for responses with more than
+/// one value.
 ///
 ///
 /// @param response IPv6 response packet from which to extract the lease value.
 /// @param response IPv6 response packet from which to extract the lease value.
 ///
 ///
 /// @return A string containing the lease value.
 /// @return A string containing the lease value.
 /// @throw isc::BadValue if the response contains neither an IA_NA nor IA_PD
 /// @throw isc::BadValue if the response contains neither an IA_NA nor IA_PD
 /// option.
 /// option.
-std::string getV6AddrStr (Pkt6Ptr response) {
+std::string getV6AddrStr(Pkt6Ptr response) {
     OptionPtr tmp = response->getOption(D6O_IA_NA);
     OptionPtr tmp = response->getOption(D6O_IA_NA);
     if (tmp) {
     if (tmp) {
         return(getAddrStrIA_NA(tmp));
         return(getAddrStrIA_NA(tmp));
@@ -548,4 +548,3 @@ const UserPtr& getDefaultUser6() {
                                           default_user6_id_str)));
                                           default_user6_id_str)));
 }
 }
 
 
-} // end extern "C"

+ 2 - 1
src/hooks/dhcp/user_chk/subnet_select_co.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-/// @file Defines the subnet4_select and subnet6_select callout functions.
+/// @file subnet_select.cc Defines the subnet4_select and subnet6_select callout functions.
 
 
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
@@ -23,6 +23,7 @@
 
 
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::hooks;
+using namespace user_chk;
 using namespace std;
 using namespace std;
 
 
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // Functions accessed by the hooks framework use C linkage to avoid the name

+ 1 - 0
src/hooks/dhcp/user_chk/tests/user_file_unittests.cc

@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 using namespace std;
 using namespace std;
+using namespace user_chk;
 
 
 namespace {
 namespace {
 
 

+ 1 - 0
src/hooks/dhcp/user_chk/tests/user_registry_unittests.cc

@@ -24,6 +24,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 using namespace std;
 using namespace std;
+using namespace user_chk;
 
 
 namespace {
 namespace {
 
 

+ 1 - 0
src/hooks/dhcp/user_chk/tests/user_unittests.cc

@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 using namespace std;
 using namespace std;
+using namespace user_chk;
 
 
 namespace {
 namespace {
 
 

+ 1 - 0
src/hooks/dhcp/user_chk/tests/userid_unittests.cc

@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 using namespace std;
 using namespace std;
+using namespace user_chk;
 
 
 namespace {
 namespace {
 
 

+ 4 - 0
src/hooks/dhcp/user_chk/user.cc

@@ -22,6 +22,8 @@
 #include <iomanip>
 #include <iomanip>
 #include <sstream>
 #include <sstream>
 
 
+namespace user_chk {
+
 //********************************* UserId ******************************
 //********************************* UserId ******************************
 
 
 const char* UserId::HW_ADDRESS_STR = "HW_ADDR";
 const char* UserId::HW_ADDRESS_STR = "HW_ADDR";
@@ -215,3 +217,5 @@ const UserId&
 User::getUserId() const {
 User::getUserId() const {
     return (user_id_);
     return (user_id_);
 }
 }
+
+} // namespace user_chk

+ 4 - 0
src/hooks/dhcp/user_chk/user.h

@@ -21,6 +21,8 @@
 #include <stdint.h>
 #include <stdint.h>
 #include <vector>
 #include <vector>
 
 
+namespace user_chk {
+
 /// @file user.h This file defines classes: UserId and User.
 /// @file user.h This file defines classes: UserId and User.
 /// @brief These classes are used to describe and recognize DHCP lease
 /// @brief These classes are used to describe and recognize DHCP lease
 /// clients.
 /// clients.
@@ -246,4 +248,6 @@ private:
 /// @brief Defines a smart pointer to a User.
 /// @brief Defines a smart pointer to a User.
 typedef boost::shared_ptr<User> UserPtr;
 typedef boost::shared_ptr<User> UserPtr;
 
 
+} // namespace user_chk
+
 #endif
 #endif

+ 5 - 1
src/hooks/dhcp/user_chk/user_chk.h

@@ -19,6 +19,10 @@
 #include <string>
 #include <string>
 
 
 using namespace std;
 using namespace std;
+using namespace user_chk;
+
+// The following constants are used throughout the library.  They are defined
+// in load_unload.cc
 
 
 /// @brief Pointer to the registry instance.
 /// @brief Pointer to the registry instance.
 extern UserRegistryPtr user_registry;
 extern UserRegistryPtr user_registry;
@@ -42,6 +46,6 @@ extern const char* registered_user_label;
 extern const char* default_user4_id_str;
 extern const char* default_user4_id_str;
 
 
 /// @brief Text id used to identify the default IPv6 user in the registry
 /// @brief Text id used to identify the default IPv6 user in the registry
-extern const char *default_user6_id_str;
+extern const char* default_user6_id_str;
 
 
 #endif
 #endif

+ 4 - 0
src/hooks/dhcp/user_chk/user_chk_log.cc

@@ -15,4 +15,8 @@
 /// Defines the logger used by the user check hooks library.
 /// Defines the logger used by the user check hooks library.
 #include <user_chk_log.h>
 #include <user_chk_log.h>
 
 
+namespace user_chk {
+
 isc::log::Logger user_chk_logger("user_chk");
 isc::log::Logger user_chk_logger("user_chk");
+
+} // namespace user_chk

+ 4 - 0
src/hooks/dhcp/user_chk/user_data_source.h

@@ -18,6 +18,8 @@
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <user.h>
 #include <user.h>
 
 
+namespace user_chk {
+
 /// @brief Thrown if UserDataSource encounters an error
 /// @brief Thrown if UserDataSource encounters an error
 class UserDataSourceError : public isc::Exception {
 class UserDataSourceError : public isc::Exception {
 public:
 public:
@@ -72,4 +74,6 @@ public:
 /// @brief Defines a smart pointer to a UserDataSource.
 /// @brief Defines a smart pointer to a UserDataSource.
 typedef boost::shared_ptr<UserDataSource> UserDataSourcePtr;
 typedef boost::shared_ptr<UserDataSource> UserDataSourcePtr;
 
 
+} // namespace user_chk
+
 #endif
 #endif

+ 3 - 0
src/hooks/dhcp/user_chk/user_file.cc

@@ -20,6 +20,8 @@
 #include <errno.h>
 #include <errno.h>
 #include <iostream>
 #include <iostream>
 
 
+namespace user_chk {
+
 UserFile::UserFile(const std::string& fname) : fname_(fname), file_() {
 UserFile::UserFile(const std::string& fname) : fname_(fname), file_() {
     if (fname_.empty()) {
     if (fname_.empty()) {
         isc_throw(UserFileError, "file name cannot be blank");
         isc_throw(UserFileError, "file name cannot be blank");
@@ -157,3 +159,4 @@ UserFile::close() {
     }
     }
 }
 }
 
 
+} // namespace user_chk

+ 4 - 0
src/hooks/dhcp/user_chk/user_file.h

@@ -25,6 +25,8 @@
 
 
 using namespace std;
 using namespace std;
 
 
+namespace user_chk {
+
 /// @brief Thrown a UserFile encounters an error.
 /// @brief Thrown a UserFile encounters an error.
 /// Note that it derives from UserDataSourceError to comply with the interface.
 /// Note that it derives from UserDataSourceError to comply with the interface.
 class UserFileError : public UserDataSourceError {
 class UserFileError : public UserDataSourceError {
@@ -133,4 +135,6 @@ private:
 /// @brief Defines a smart pointer to a UserFile.
 /// @brief Defines a smart pointer to a UserFile.
 typedef boost::shared_ptr<UserFile> UserFilePtr;
 typedef boost::shared_ptr<UserFile> UserFilePtr;
 
 
+} // namespace user_chk
+
 #endif
 #endif

+ 3 - 0
src/hooks/dhcp/user_chk/user_registry.cc

@@ -15,6 +15,8 @@
 #include <user_registry.h>
 #include <user_registry.h>
 #include <user.h>
 #include <user.h>
 
 
+namespace user_chk {
+
 UserRegistry::UserRegistry() {
 UserRegistry::UserRegistry() {
 }
 }
 
 
@@ -120,3 +122,4 @@ const UserDataSourcePtr& UserRegistry::getSource() {
     return (source_);
     return (source_);
 }
 }
 
 
+} // namespace user_chk

+ 4 - 0
src/hooks/dhcp/user_chk/user_registry.h

@@ -26,6 +26,8 @@
 
 
 using namespace std;
 using namespace std;
 
 
+namespace user_chk {
+
 /// @brief Thrown UserRegistry encounters an error
 /// @brief Thrown UserRegistry encounters an error
 class UserRegistryError : public isc::Exception {
 class UserRegistryError : public isc::Exception {
 public:
 public:
@@ -125,4 +127,6 @@ private:
 /// @brief Define a smart pointer to a UserRegistry.
 /// @brief Define a smart pointer to a UserRegistry.
 typedef boost::shared_ptr<UserRegistry> UserRegistryPtr;
 typedef boost::shared_ptr<UserRegistry> UserRegistryPtr;
 
 
+} // namespace user_chk
+
 #endif
 #endif