|
@@ -12,10 +12,14 @@
|
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
+// Note: the prefix "hooksdg" to all labels is an abbreviation for "Hooks
|
|
|
+// Developer's Guide" and is used to prevent a clash with symbols in any
|
|
|
+// other Doxygen file.
|
|
|
+
|
|
|
/**
|
|
|
- @page hookDevelopersGuide Hook Developer's Guide
|
|
|
+ @page hooksdgDevelopersGuide Hook Developer's Guide
|
|
|
|
|
|
- @section hookIntroduction Introduction
|
|
|
+ @section hooksdgIntroduction Introduction
|
|
|
|
|
|
Although the BIND 10 framework and its associated DNS and DHCP programs
|
|
|
provide comprehensive functionality, there will be times when it does
|
|
@@ -31,7 +35,7 @@ understanding how it works will take a significant amount of time. In
|
|
|
addition, despite the fact that its object-oriented design keeps the
|
|
|
coupling between modules to a minimum, an inappropriate change to one
|
|
|
part of the program during the extension could cause another to
|
|
|
-behave oddly or to stop working altogether, adding to development time.
|
|
|
+behave oddly or to stop working altogether.
|
|
|
|
|
|
- The change may need to be re-applied or re-written with every new
|
|
|
version of BIND 10. As new functionality is added or bugs are fixed,
|
|
@@ -39,59 +43,59 @@ the code or algorithms in the core software may change - and may change
|
|
|
significantly.
|
|
|
|
|
|
To overcome these problems, BIND 10 provides the "Hooks" interface -
|
|
|
-a defined interface for third-party or user-written code (for ease of
|
|
|
-reference in the rest of this document, such code will be referred to
|
|
|
-as "user-written code"). At specific points in its processing ("hook
|
|
|
-points") BIND 10 will make a call to this code. The call passes data
|
|
|
-that the user can examine and, if required, modify. BIND 10 used the
|
|
|
-modified code in the remainder of its processing.
|
|
|
-
|
|
|
-In order to minimise the interaction between BIND 10 and the
|
|
|
+a defined interface for third-party or user-written code. (For ease of
|
|
|
+reference in the rest of this document, all such code will be referred
|
|
|
+to as "user code".) At specific points in its processing
|
|
|
+("hook points") BIND 10 will make a call to this code. The call passes
|
|
|
+data that the user code can examine and, if required, modify.
|
|
|
+BIND 10 uses the modified data in the remainder of its processing.
|
|
|
+
|
|
|
+In order to minimise the interaction between BIND 10 and the user
|
|
|
code, the latter is built independently of BIND 10 in the form of
|
|
|
a shared library (or libraries). These are made known to BIND 10
|
|
|
through its configuration mechanism, and BIND 10 loads the library at
|
|
|
run time. Libraries can be unloaded and reloaded as needed while BIND
|
|
|
10 is running.
|
|
|
|
|
|
-Use of a defined API and BIND 10 configuration mechanism means that as
|
|
|
-new versions of BIND 10 are released, there is no need to modify the
|
|
|
-user-written code. Unless there is a major change in an interface
|
|
|
-(which will be clearly documented) all that will be required is a
|
|
|
-rebuild of the libraries.
|
|
|
+Use of a defined API and the BIND 10 configuration mechanism means that
|
|
|
+as new versions of BIND 10 are released, there is no need to modify
|
|
|
+the user code. Unless there is a major change in an interface
|
|
|
+(which will be clearly documented), all that will be required is a rebuild
|
|
|
+of the libraries.
|
|
|
|
|
|
@note Although the defined interface should not change, the internals
|
|
|
-of some of the classes and structures referenced by the user-written
|
|
|
-code may alter. These changes will need to be reflected in the compiled
|
|
|
-version of the software, hence the need for a rebuild.
|
|
|
+of some of the classes and structures referenced by the user code may
|
|
|
+change between versions of BIND 10. These changes have to be reflected
|
|
|
+in the compiled version of the software, hence the need for a rebuild.
|
|
|
|
|
|
-@subsection hookLanguages Languages
|
|
|
+@subsection hooksdgLanguages Languages
|
|
|
|
|
|
The core of BIND 10 is written in C++. While it is the intention to
|
|
|
-provide interfaces into user code written into other languages, the
|
|
|
-initial versions of the Hooks system requires that user code be written
|
|
|
-in C++. All examples in this guide are in that language.
|
|
|
+provide interfaces into user code written in other languages, the initial
|
|
|
+versions of the Hooks system requires that user code be written in C++.
|
|
|
+All examples in this guide are in that language.
|
|
|
|
|
|
-@subsection hookTerminology Terminology
|
|
|
+@subsection hooksdgTerminology Terminology
|
|
|
|
|
|
In the remainder of this guide, the following terminology is used:
|
|
|
|
|
|
- Hook/Hook Point - used interchageably, this is a point in the code at
|
|
|
-which a call to user-written functions is made. Each hook has a name and
|
|
|
-each hook can have any number (including 0) of user-written functions
|
|
|
+which a call to user functions is made. Each hook has a name and
|
|
|
+each hook can have any number (including 0) of user functions
|
|
|
attached to it.
|
|
|
|
|
|
-- Callout - a user-written function called by the server at a hook
|
|
|
+- Callout - a user function called by the server at a hook
|
|
|
point. This is so-named because the server "calls out" to the library
|
|
|
-to execute a user-written function.
|
|
|
+to execute a user function.
|
|
|
|
|
|
-- Framework function - the functions that a user-written library needs to
|
|
|
-supply in order for the hooks framework for load and unload the library.
|
|
|
+- Framework function - the functions that a user library needs to
|
|
|
+supply in order for the hooks framework to load and unload the library.
|
|
|
|
|
|
- User code/user library - non-BIND 10 code that is compiled into a
|
|
|
shared library and loaded by BIND 10 into its address space.
|
|
|
|
|
|
|
|
|
-@section hookTutorial Tutorial
|
|
|
+@section hooksdgTutorial Tutorial
|
|
|
|
|
|
To illustrate how to write code that integrates with BIND 10, we will
|
|
|
use the following (rather contrived) example:
|
|
@@ -103,14 +107,14 @@ IPv4 addresses according to their hardware address, and want to log both
|
|
|
the hardware address and allocated IP address for the clients of interest.
|
|
|
|
|
|
The following sections describe how to implement these requirements.
|
|
|
-The code presented here is not efficient and there are better ways
|
|
|
-of doing the task. The aim is to illustrate the main features of
|
|
|
-user-written hook code rather than provide an optimal solution.
|
|
|
+The code presented here is not efficient and there are better ways of
|
|
|
+doing the task. The aim however, is to illustrate the main features of
|
|
|
+user hook code not to provide an optimal solution.
|
|
|
|
|
|
|
|
|
-@subsection hookFrameworkFunctions Framework Functions
|
|
|
+@subsection hooksdgFrameworkFunctions Framework Functions
|
|
|
|
|
|
-Loading an initializing a library holding user-written code makes use
|
|
|
+Loading and initializing a library holding user code makes use
|
|
|
of three (user-supplied) functions:
|
|
|
|
|
|
- version - defines the version of BIND 10 code with which the user-library
|
|
@@ -118,10 +122,10 @@ is built
|
|
|
- load - called when the library is loaded by the server.
|
|
|
- unload - called when the library is unloaded by the server.
|
|
|
|
|
|
-Of these, only "version" is mandatory, although our in out example, all three
|
|
|
+Of these, only "version" is mandatory, although our in our example, all three
|
|
|
are used.
|
|
|
|
|
|
-@subsubsection hookVersionFunction The "version" Function
|
|
|
+@subsubsection hooksdgVersionFunction The "version" Function
|
|
|
|
|
|
"version" is used by the hooks framework to check that the libraries
|
|
|
it is loading are compatible with the version of BIND 10 being run.
|
|
@@ -129,14 +133,14 @@ Although the hooks system allows BIND 10 and user code to interface
|
|
|
through a defined API, the relationship is somewhat tight in that the
|
|
|
user code will depend on the internal structures of BIND 10. If these
|
|
|
change - as they can between BIND 10 releases - and BIND 10 is run with
|
|
|
-a version of user-written code built against an earlier version of BIND
|
|
|
+a version of user code built against an earlier version of BIND
|
|
|
10, a program crash could result.
|
|
|
|
|
|
-To guard against this, the "version" function must be provided in
|
|
|
-every library. It returns a constant defined in the version of header
|
|
|
-files against which it was built. The hooks framework checks this for
|
|
|
-compatibility with the running version of BIND 10 before proceeding with
|
|
|
-the library load.
|
|
|
+To guard against this, the "version" function must be provided in every
|
|
|
+library. It returns a constant defined in header files of the version
|
|
|
+of BIND 10 against which it was built. The hooks framework checks this
|
|
|
+for compatibility with the running version of BIND 10 before loading
|
|
|
+the library.
|
|
|
|
|
|
In this tutorial, we'll put "version" in its own file, version.cc. The
|
|
|
contents are:
|
|
@@ -155,10 +159,11 @@ int version() {
|
|
|
};
|
|
|
@endcode
|
|
|
|
|
|
-The file "hooks/hooks.h" is specified relative to the BIND 10 libraries source
|
|
|
-directory - this is covered later in the section @ref hookBuild. It defines the
|
|
|
-symbol BIND10_HOOKS_VERSION, which has a value that changes on every release
|
|
|
-of BIND 10: this is the value that needs to be returned to the hooks framework.
|
|
|
+The file "hooks/hooks.h" is specified relative to the BIND 10 libraries
|
|
|
+source directory - this is covered later in the section @ref hooksdgBuild.
|
|
|
+It defines the symbol BIND10_HOOKS_VERSION, which has a value that changes
|
|
|
+on every release of BIND 10: this is the value that needs to be returned
|
|
|
+to the hooks framework.
|
|
|
|
|
|
A final point to note is that the definition of "version" is enclosed
|
|
|
within 'extern "C"' braces. All functions accessed by the hooks
|
|
@@ -166,31 +171,36 @@ framework use C linkage, mainly to avoid the name mangling that
|
|
|
accompanies use of the C++ compiler, but also to avoid issues related
|
|
|
to namespaces.
|
|
|
|
|
|
-@subsubsection hookLoadUnloadFunctions The "load" and "unload" Functions
|
|
|
+@subsubsection hooksdgLoadUnloadFunctions The "load" and "unload" Functions
|
|
|
|
|
|
As the names suggest, "load" is called when a library is loaded and
|
|
|
-"unload" called when it is unloaded. (It is always guaranteed that "load"
|
|
|
-is called: "unload" may not be called in some circumstances, e.g. if the
|
|
|
-system shuts down abnormally.) These functions are the places where any
|
|
|
-library-wide resources are allocated and deallocated. "load" is also
|
|
|
-the place where any callouts with non-standard names can be registered:
|
|
|
-this is covered further in the section @ref hookCalloutRegistration.
|
|
|
+"unload" called when it is unloaded. (It is always guaranteed that
|
|
|
+"load" is called: "unload" may not be called in some circumstances,
|
|
|
+e.g. if the system shuts down abnormally.) These functions are the
|
|
|
+places where any library-wide resources are allocated and deallocated.
|
|
|
+"load" is also the place where any callouts with non-standard names
|
|
|
+(names that are not hook point names) can be registered:
|
|
|
+this is covered further in the section @ref hooksdgCalloutRegistration.
|
|
|
|
|
|
The example does not make any use callouts with non-standard names. However,
|
|
|
as our design requires that the log file be open while BIND 10 is active
|
|
|
and the library loaded, we'll open the file in the "load" function and close
|
|
|
-it in "unload". We create two files, one for the file handle declaration:
|
|
|
+it in "unload".
|
|
|
+
|
|
|
+We create two files, one for the file handle declaration:
|
|
|
|
|
|
@code
|
|
|
// library_common.h
|
|
|
|
|
|
#ifndef LIBRARY_COMMON_H
|
|
|
#define LIBRARY_COMMON_H
|
|
|
+
|
|
|
#include <fstream>
|
|
|
|
|
|
// "Interesting clients" log file handle declaration.
|
|
|
extern std::fstream interesting;
|
|
|
-#endif
|
|
|
+
|
|
|
+#endif // LIBRARY_COMMON_H
|
|
|
@endcode
|
|
|
|
|
|
... and one to hold the "load" and "unload" functions:
|
|
@@ -227,37 +237,40 @@ Notes:
|
|
|
outside of any function. This means it can be accessed by any function
|
|
|
within the user library. For convenience, the definition is in the
|
|
|
load_unload.cc file.
|
|
|
-- "load" is called with a LibraryHandle argument, used in the registration
|
|
|
-of functions. As no functions are being called in this example,
|
|
|
-the argument specification omits the variable name (whilst retaining the type)
|
|
|
-to avoid an "unused variable" compiler warning. (The LibraryHandle is
|
|
|
-discussed in the section @ref hookLibraryHandle.)
|
|
|
+- "load" is called with a LibraryHandle argument, this being used in
|
|
|
+the registration of functions. As no functions are being registered
|
|
|
+in this example, the argument specification omits the variable name
|
|
|
+(whilst retaining the type) to avoid an "unused variable" compiler
|
|
|
+warning. (The LibraryHandle and its use is discussed in the section
|
|
|
+@ref hooksdgLibraryHandle.)
|
|
|
- In the current version of the hooks framework, it is not possible to pass
|
|
|
any configuration information to the "load" function. The name of the log
|
|
|
-file must therefore be hard-coded as an absolute path name, or communicated
|
|
|
-to the user-written code by some other means.
|
|
|
-- "load" returns 0 on success and non-zero on error. The hooks framework
|
|
|
+file must therefore be hard-coded as an absolute path name or communicated
|
|
|
+to the user code by some other means.
|
|
|
+- "load" must 0 on success and non-zero on error. The hooks framework
|
|
|
will abandon the loading of the library if "load" returns an error status.
|
|
|
(In this example, "interesting" can be tested as a boolean value,
|
|
|
returning "true" if the file opened successfully.)
|
|
|
- "unload" closes the log file if it is open and is a no-op otherwise. As
|
|
|
-with "load", a zero value is returned on success and a non-zero value
|
|
|
+with "load", a zero value must be returned on success and a non-zero value
|
|
|
on an error. The hooks framework will record a non-zero status return
|
|
|
as an error in the current BIND 10 log but otherwise ignore it.
|
|
|
- As before, the function definitions are enclosed in 'extern "C"' braces.
|
|
|
|
|
|
-@subsection hookCallouts Callouts
|
|
|
+@subsection hooksdgCallouts Callouts
|
|
|
|
|
|
Having sorted out the framework, we now come to the functions that
|
|
|
actually do something. These functions are known as "callouts" because
|
|
|
-the BIND 10 code "calls out" to them. Each BIND 10 server has a number
|
|
|
-of hooks to which callouts can be attached: the purpose of the hooks
|
|
|
-and the data passed to callouts is documented elsewhere.
|
|
|
+the BIND 10 code "calls out" to them. Each BIND 10 server has a number of
|
|
|
+hooks to which callouts can be attached: server-specific documentation
|
|
|
+describes in detail the points in the server at which the hooks are
|
|
|
+present together with the data passed to callouts attached to them.
|
|
|
|
|
|
Before we continue with the example, we'll discuss how arguments are
|
|
|
-passed to callouts and how information can be moved between them.
|
|
|
+passed to callouts and information is returned to the server. We will
|
|
|
+also discuss how information can be moved between callouts.
|
|
|
|
|
|
-@subsubsection hookCalloutSignature The Callout Signature
|
|
|
+@subsubsection hooksdgCalloutSignature The Callout Signature
|
|
|
|
|
|
All callouts are declared with the signature:
|
|
|
@code
|
|
@@ -279,7 +292,7 @@ log an error, specifying both the library and hook that generated it.
|
|
|
Effectively the return status provides a quick way for a callout to log
|
|
|
error information to the BIND 10 logging system.
|
|
|
|
|
|
-@subsubsection hookArguments Callout Arguments
|
|
|
+@subsubsection hooksdgArguments Callout Arguments
|
|
|
|
|
|
The CalloutHandle object provides two methods to get and set the
|
|
|
arguments passed to the callout. These methods are called (naturally
|
|
@@ -296,7 +309,7 @@ following code snippets.
|
|
|
handle.setArgument("data_count", count);
|
|
|
handle.setArgument("inpacket", pktptr);
|
|
|
|
|
|
- // Call the hook code...
|
|
|
+ // Call the callouts attached to the hook
|
|
|
...
|
|
|
|
|
|
// Retrieve the modified values
|
|
@@ -342,15 +355,13 @@ be thrown if an attempt is made to retrieve it into a variable of type
|
|
|
"const char*". (However, if an argument is set as a "const int", it can
|
|
|
be retrieved into an "int".) The documentation of each hook point will
|
|
|
detail the data type of each argument.
|
|
|
-
|
|
|
- Although all arguments can be modified, some altered values may not
|
|
|
be read by the server. (These would be ones that the server considers
|
|
|
"read-only".) Consult the documentation of each hook to see whether an
|
|
|
argument can be used to transfer data back to the server.
|
|
|
-
|
|
|
- If a pointer to an object is passed to a callout (either a "raw"
|
|
|
pointer, or a boost smart pointer (as in the example above), and the
|
|
|
-underlying object altered through that pointer, the change will be
|
|
|
+underlying object is altered through that pointer, the change will be
|
|
|
reflected in the server even if no call is made to setArgument.
|
|
|
|
|
|
In all cases, consult the documentation for the particular hook to see whether
|
|
@@ -361,10 +372,54 @@ the server.
|
|
|
- If you alter an argument, call CalloutHandle::setArgument to update the
|
|
|
value in the CalloutHandle object.
|
|
|
|
|
|
-@subsubsection hookCalloutContext Per-Request Context
|
|
|
+@subsubsection hooksdgSkipFlag The "Skip" Flag
|
|
|
+
|
|
|
+When a to callouts attached to a hook returns, the server will usually continue
|
|
|
+its processing. However, a callout might have done something that means that
|
|
|
+the server should follow another path. Possible actions a server could take
|
|
|
+include:
|
|
|
+
|
|
|
+- Skip the next stage of processing because the callout has already
|
|
|
+done it. For example, a hook is located just before the DHCP server
|
|
|
+allocates an address to the client. A callout may decide to allocate
|
|
|
+special addresses for certain clients, in which case it needs to tell
|
|
|
+the server not to allocate an address in this case.
|
|
|
+- Drop the packet and continue with the next request. A possible scenario
|
|
|
+is a DNS server where a callout inspects the source address of an incoming
|
|
|
+packet and compares it against a black list; if the address is on it,
|
|
|
+the callout notifies the server to drop the packet.
|
|
|
+
|
|
|
+To handle these common cases, the CalloutHandle has a "skip" flag.
|
|
|
+This is set by a callout when it wishes the server to skip normal
|
|
|
+processing. It is set false by the hooks framework before callouts on a
|
|
|
+hook are called. If the flag is set on return, the server will take the
|
|
|
+"skip" action relevant for the hook.
|
|
|
+
|
|
|
+The methods to get and set the "skip" flag are getSkip and setSkip. Their
|
|
|
+usage is intuitive:
|
|
|
+
|
|
|
+@code
|
|
|
+ // Get the current setting of the skip flag.
|
|
|
+ bool skip = handle.getSkip();
|
|
|
+
|
|
|
+ // Do some processing...
|
|
|
+ :
|
|
|
+ if (lease_allocated) {
|
|
|
+ // Flag the server to skip the next step of the processing as we
|
|
|
+ // already have an address.
|
|
|
+ handle.setSkip(true);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+
|
|
|
+@endcode
|
|
|
+
|
|
|
+Like arguments, the "skip" flag is passed to all callouts on a hook. Callouts
|
|
|
+later in the list are able to examine (and modify) the settings of earlier ones.
|
|
|
+
|
|
|
+@subsubsection hooksdgCalloutContext Per-Request Context
|
|
|
|
|
|
Although many of the BIND 10 modules can be characterised as handling
|
|
|
-a single packet - e.g. the DHCPv4 server receives a DISCOVER packet,
|
|
|
+singles packet - e.g. the DHCPv4 server receives a DISCOVER packet,
|
|
|
processes it and responds with an OFFER, this is not true in all cases.
|
|
|
The principal exception is the recursive DNS resolver: this receives a
|
|
|
packet from a client but that packet may itself generate multiple packets
|
|
@@ -381,9 +436,8 @@ per-request basis.
|
|
|
Context only exists only for the duration of the request: when a request
|
|
|
is completed, the context is destroyed. A new request starts with no
|
|
|
context information. Context is particularly useful in servers that may
|
|
|
-be processing multiple requests simultaneously: callouts are effectively
|
|
|
-attaching data to a request and that data follows the request around the
|
|
|
-system.
|
|
|
+be processing multiple requests simultaneously: callouts can effectively
|
|
|
+attach data to a request that follows the request around the system.
|
|
|
|
|
|
Context information is held as name/value pairs in the same way
|
|
|
as arguments, being accessed by the pair of methods setContext and
|
|
@@ -391,11 +445,9 @@ getContext. They have the same restrictions as the setArgument and
|
|
|
getArgument methods - the type of data retrieved from context must
|
|
|
<B>exactly</B> match the type of the data set.
|
|
|
|
|
|
-As the example in the tutorial uses per-request context, no separate
|
|
|
-example is given here.
|
|
|
+The example in the next section illustrates their use.
|
|
|
|
|
|
-
|
|
|
-@subsection hookExampleCallouts Example Callouts
|
|
|
+@subsection hooksdgExampleCallouts Example Callouts
|
|
|
|
|
|
Continuing with the tutorial, the requirements need us to retrieve the
|
|
|
hardware address of the incoming packet, classify it, and write it,
|
|
@@ -409,14 +461,14 @@ We will do the classification here.
|
|
|
|
|
|
- v4_lease_write_post - called when the lease (an assignment of an IPv4
|
|
|
address to a client for a fixed period of time) has been written to the
|
|
|
-database. It is passed two (constant) arguments, the query ("query")
|
|
|
+database. It is passed two arguments, the query ("query")
|
|
|
and the response (called "reply"). This is the point at which the
|
|
|
example code will write the hardware and IP addresses to the log file.
|
|
|
|
|
|
The standard for naming callouts is to give them the same name as
|
|
|
the hook. If this is done, the callouts will be automatically found
|
|
|
by the Hooks system (this is discussed further in section @ref
|
|
|
-hookCalloutRegistration). For our example, we will assume this is the
|
|
|
+hooksdgCalloutRegistration). For our example, we will assume this is the
|
|
|
case, so the code for the first callout (used to classify the client's
|
|
|
hardware address) is:
|
|
|
|
|
@@ -435,7 +487,6 @@ using namespace std;
|
|
|
extern "C" {
|
|
|
|
|
|
// This callout is called at the "pkt_rcvd" hook.
|
|
|
-
|
|
|
int pkt_rcvd(CalloutHandle& handle) {
|
|
|
|
|
|
// A pointer to the packet is passed to the callout via a "boost" smart
|
|
@@ -485,7 +536,6 @@ using namespace std;
|
|
|
extern "C" {
|
|
|
|
|
|
// This callout is called at the "v4_lease_write_post" hook.
|
|
|
-
|
|
|
int v4_lease_write_post(CalloutHandle& handle) {
|
|
|
|
|
|
// Obtain the hardware address of the "interesting" client. We have to
|
|
@@ -495,10 +545,10 @@ int v4_lease_write_post(CalloutHandle& handle) {
|
|
|
try (handle.getArgument("hwaddr", hwaddr) {
|
|
|
|
|
|
// getArgument didn't throw so the client is interesting. Get a pointer
|
|
|
- // to the reply. This is read-only so is passed through a smart pointer
|
|
|
- // const Pkt4 object. Note that the argument list also contains a
|
|
|
- // pointer to the query: we don't need to access that in this example.
|
|
|
- ConstPkt4Ptr reply;
|
|
|
+ // to the reply. Note that the argument list for this hook also
|
|
|
+ // contains a pointer to the query: we don't need to access that in this
|
|
|
+ // example.
|
|
|
+ Pkt4Ptr reply;
|
|
|
handle.getArgument("reply", reply);
|
|
|
|
|
|
// Get the string form of the IP address.
|
|
@@ -523,13 +573,13 @@ int v4_lease_write_post(CalloutHandle& handle) {
|
|
|
};
|
|
|
@endcode
|
|
|
|
|
|
-@subsection hookBuild Building the Library
|
|
|
+@subsection hooksdgBuild Building the Library
|
|
|
|
|
|
Building the code requires building a shareable library. This requires
|
|
|
the the code be compiled as positition-independent code (using the
|
|
|
-compiler's -fpic switch) and linked as a shared library (with the linker's
|
|
|
--shared switch). The build command also needs to point to the BIND 10 include
|
|
|
-directory and link in the appropriate libraries.
|
|
|
+compiler's "-fpic" switch) and linked as a shared library (with the
|
|
|
+linker's "-shared" switch). The build command also needs to point to
|
|
|
+the BIND 10 include directory and link in the appropriate libraries.
|
|
|
|
|
|
Assuming that BIND 10 has been installed in the default location, the
|
|
|
command line needed to create the library using the Gnu C++ compiler on a
|
|
@@ -542,20 +592,18 @@ g++ -I /usr/include/bind10 -L /usr/lib/bind10 -fpic -shared -o example.so \
|
|
|
@endcode
|
|
|
|
|
|
Notes:
|
|
|
-- the compilation command and switches required may vary depending on
|
|
|
+- The compilation command and switches required may vary depending on
|
|
|
your operating system and compiler - consult the relevant documentation
|
|
|
for details.
|
|
|
-- the values for the -I and -L switches depend on where you have installed
|
|
|
-BIND 10.
|
|
|
-- the list of libraries that need to be included in the command line
|
|
|
+- The values for the "-I" and "-L" switches depend on where you have
|
|
|
+installed BIND 10.
|
|
|
+- The list of libraries that need to be included in the command line
|
|
|
depends on the functionality used by the hook code and the module to
|
|
|
which they are attached (e.g. hook code for DNS will need to link against
|
|
|
the libb10-dns++ library). Depending on operating system, you may also need
|
|
|
-to explicitly list libraries on which the BIND 10 libraries depend, e.g.
|
|
|
-in the command line above, libb10-exceptions depends on log4cplus, so it
|
|
|
-is possible that "-llog4cplus" may need to be appended to the command line.
|
|
|
+to explicitly list libraries on which the BIND 10 libraries depend.
|
|
|
|
|
|
-@subsection hookConfiguration Configuring the Hook Library
|
|
|
+@subsection hooksdgConfiguration Configuring the Hook Library
|
|
|
|
|
|
The final step is to make the library known to BIND 10. All BIND 10 modules to
|
|
|
which hooks can be added contain the "hook_library" element, and user
|
|
@@ -565,17 +613,17 @@ To add the example library (assumed to be in /usr/local/lib) to the DHCPv4
|
|
|
module, the following bindctl commands must be executed:
|
|
|
|
|
|
@code
|
|
|
-> config add Dhcp4/hook_library
|
|
|
-> config set Dhcp4/hook_library[0]/name "/usr/local/lib/example.so"
|
|
|
+> config add Dhcp4/hook_libraries
|
|
|
+> config set Dhcp4/hook_libraries[0] "/usr/local/lib/example.so"
|
|
|
> config commit
|
|
|
@endcode
|
|
|
|
|
|
The DHCPv4 server will load the library and execute the callouts each time a
|
|
|
request is received.
|
|
|
|
|
|
-@section hookAdvancedTopics Advanced Topics
|
|
|
+@section hooksdgAdvancedTopics Advanced Topics
|
|
|
|
|
|
-@subsection hookContextCreateDestroy Context Creation and Destruction
|
|
|
+@subsection hooksdgContextCreateDestroy Context Creation and Destruction
|
|
|
|
|
|
As well as the hooks defined by the server, the hooks framework defines
|
|
|
two hooks of its own, "context_create" and "context_destroy". The first
|
|
@@ -585,14 +633,14 @@ to initialize per-request context. The second is called after all
|
|
|
server-defined hooks have been processed, and is to allow a library to
|
|
|
tidy up.
|
|
|
|
|
|
-As an example, the v4_lease_write
|
|
|
-example above required that the code check for an exception being
|
|
|
-thrown when accessing the "hwaddr" context item in case it was not set.
|
|
|
-An alternative strategy would have been to provide a callout for the
|
|
|
-"context_create" hook and set the context item "hwaddr" to an empty
|
|
|
-string. Instead of needing to handle an exception, v4_lease_write would
|
|
|
-be guaranteed to get something when looking for the hwaddr item and so
|
|
|
-could write or not write the output depending on the value.
|
|
|
+As an example, the v4_lease_write example above required that the code
|
|
|
+check for an exception being thrown when accessing the "hwaddr" context
|
|
|
+item in case it was not set. An alternative strategy would have been to
|
|
|
+provide a callout for the "context_create" hook and set the context item
|
|
|
+"hwaddr" to an empty string. Instead of needing to handle an exception,
|
|
|
+v4_lease_write would be guaranteed to get something when looking for
|
|
|
+the hwaddr item and so could write or not write the output depending on
|
|
|
+the value.
|
|
|
|
|
|
In most cases, "context_destroy" is not needed as the Hooks system
|
|
|
automatically deletes context. An example where it could be required
|
|
@@ -600,32 +648,143 @@ is where memory has been allocated by a callout during the processing
|
|
|
of a request and a raw pointer to it stored in the context object. On
|
|
|
destruction of the context, that memory will not be automatically
|
|
|
released. Freeing in the memory in the "context_destroy callout will solve
|
|
|
-that problem. (Actually, when the context is destroyed, the destructor
|
|
|
+that problem.
|
|
|
+
|
|
|
+Actually, when the context is destroyed, the destructor
|
|
|
associated with any objects stored in it are run. Rather than point to
|
|
|
allocated memory with a raw pointer, a better idea would be to point to
|
|
|
it with a boost "smart" pointer and store that pointer in the context.
|
|
|
When the context is destroyed, the smart pointer's destructor is run,
|
|
|
-which will automatically delete the pointed-to object.)
|
|
|
+which will automatically delete the pointed-to object.
|
|
|
|
|
|
+These approaches are illustrated in the following examples.
|
|
|
+Here it is assumed that the hooks library is performing some form of
|
|
|
+security checking on the packet and needs to maintain information in
|
|
|
+a user-specified "SecurityInformation" object. (The details of this
|
|
|
+fictitious object are of no concern here.) The object is created in
|
|
|
+the context_create callout and used in both the pkt4_rcvd and the
|
|
|
+v4_lease_write_post callouts.
|
|
|
|
|
|
-@subsection hookCalloutRegistration Registering Callouts
|
|
|
+@code
|
|
|
+// Storing information in a "raw" pointer. Assume that the
|
|
|
|
|
|
-As briefly mentioned in @ref hookExampleCallouts, the standard is for
|
|
|
-callouts in the user library to have the same name as the name of the hook
|
|
|
-to which they are being attached. This was followed in the tutorial, e.g.
|
|
|
-the callout that needed to be attached to the "pkt_rcvd" hook was named
|
|
|
-pkt_rcvd.
|
|
|
+#include <hooks/hooks.h>
|
|
|
+ :
|
|
|
+
|
|
|
+extern "C" {
|
|
|
|
|
|
-The reason for this standard is that when the library is loaded, the
|
|
|
-hook framework automatically searches the library for functions with the
|
|
|
-same names as the server hooks. When it finds one, it attaches it to
|
|
|
-that hook point. This simplifies the loading process and bookkeeping
|
|
|
-required to create a library of callouts.
|
|
|
+// context_create callout - called when the request is created.
|
|
|
+int context_create(CalloutHandle& handle) {
|
|
|
+ // Create the security information and store it in the context
|
|
|
+ // for this packet.
|
|
|
+ SecurityInformation* si = new SecurityInformation();
|
|
|
+ handle.setContext("security_information", si);
|
|
|
+}
|
|
|
+
|
|
|
+// Callouts that use the context
|
|
|
+int pktv_rcvd(CalloutHandle& handle) {
|
|
|
+ // Retrieve the pointer to the SecurityInformation object
|
|
|
+ SecurityInformation si;
|
|
|
+ handle.getContext("security_information", si);
|
|
|
+ :
|
|
|
+ :
|
|
|
+ // Set the security information
|
|
|
+ si->setSomething(...);
|
|
|
+
|
|
|
+ // The pointed-to information has been updated but the pointer has not been
|
|
|
+ // altered, so there is no need to call setContext() again.
|
|
|
+}
|
|
|
+
|
|
|
+int v4_lease_write_post(CalloutHandle& handle) {
|
|
|
+ // Retrieve the pointer to the SecurityInformation object
|
|
|
+ SecurityInformation si;
|
|
|
+ handle.getContext("security_information", si);
|
|
|
+ :
|
|
|
+ :
|
|
|
+ // Retrieve security information
|
|
|
+ bool active = si->getSomething(...);
|
|
|
+ :
|
|
|
+}
|
|
|
+
|
|
|
+// Context destruction. We need to delete the pointed-to SecurityInformation
|
|
|
+// object because we will lose the pointer to it when the CalloutHandle is
|
|
|
+// destroyed.
|
|
|
+int context_destroy(CalloutHandle& handle) {
|
|
|
+ // Retrieve the pointer to the SecurityInformation object
|
|
|
+ SecurityInformation si;
|
|
|
+ handle.getContext("security_information", si);
|
|
|
+
|
|
|
+ // Delete the pointed-to memory.
|
|
|
+ delete si;
|
|
|
+}
|
|
|
+@endcode
|
|
|
+
|
|
|
+The requirement for the context_destroy callout can be eliminated if
|
|
|
+a Boost shared ptr is used to point to the allocated memory:
|
|
|
+
|
|
|
+@code
|
|
|
+// Storing information in a "raw" pointer. Assume that the
|
|
|
+
|
|
|
+#include <hooks/hooks.h>
|
|
|
+#include <boost/shared_ptr.hpp>
|
|
|
+ :
|
|
|
+
|
|
|
+extern "C" {
|
|
|
+
|
|
|
+// context_create callout - called when the request is created.
|
|
|
+
|
|
|
+int context_create(CalloutHandle& handle) {
|
|
|
+ // Create the security information and store it in the context for this
|
|
|
+ // packet.
|
|
|
+ boost::shared_ptr<SecurityInformation> si(new SecurityInformation());
|
|
|
+ handle.setContext("security_information", si);
|
|
|
+}
|
|
|
+
|
|
|
+// Other than the data type, a shared pointer has similar semantics to a "raw"
|
|
|
+// pointer. Only the code from pkt_rcvd is shown here.
|
|
|
+
|
|
|
+int pktv_rcvd(CalloutHandle& handle) {
|
|
|
+ // Retrieve the pointer to the SecurityInformation object
|
|
|
+ boost::shared_ptr<SecurityInformation> si;
|
|
|
+ handle.setContext("security_information", si);
|
|
|
+ :
|
|
|
+ :
|
|
|
+ // Modify the security information
|
|
|
+ si->setSomething(...);
|
|
|
+
|
|
|
+ // The pointed-to information has been updated but the pointer has not
|
|
|
+ // altered, so theree is no need to reset the context.
|
|
|
+}
|
|
|
+
|
|
|
+// No context_destroy callout is needed to delete the allocated
|
|
|
+// SecurityInformation object. When the CalloutHandle is destroyed, the shared
|
|
|
+// pointer object will be destroyed. If that is the last shared pointer to the
|
|
|
+// allocated memory, then it too will be deleted.
|
|
|
+@endcode
|
|
|
+
|
|
|
+(Note that a Boost shared pointer - rather than any other Boost smart pointer -
|
|
|
+should be used, as the pointer objects are copied within the hooks framework and
|
|
|
+only shared pointers have the correct behavior for the copy operation.)
|
|
|
+
|
|
|
+
|
|
|
+@subsection hooksdgCalloutRegistration Registering Callouts
|
|
|
+
|
|
|
+As briefly mentioned in @ref hooksdgExampleCallouts, the standard is for
|
|
|
+callouts in the user library to have the same name as the name of the
|
|
|
+hook to which they are being attached. This convention was followed
|
|
|
+in the tutorial, e.g. the callout that needed to be attached to the
|
|
|
+"pkt_rcvd" hook was named pkt_rcvd.
|
|
|
+
|
|
|
+The reason for this convention is that when the library is loaded, the
|
|
|
+hook framework automatically searches the library for functions with
|
|
|
+the same names as the server hooks. When it finds one, it attaches it
|
|
|
+to the appropriate hook point. This simplifies the loading process and
|
|
|
+bookkeeping required to create a library of callouts.
|
|
|
|
|
|
However, the hooks system is flexible in this area: callouts can have
|
|
|
non-standard names, and multiple callouts can be registered on a hook.
|
|
|
|
|
|
-@subsubsection hookLibraryHandle The LibraryHandle Object
|
|
|
+@subsubsection hooksdgLibraryHandle The LibraryHandle Object
|
|
|
|
|
|
The way into the part of the hooks framework that allows callout
|
|
|
registration is through the LibraryHandle object. This was briefly
|
|
@@ -642,11 +801,11 @@ The LibraryHandle provides three methods to manipulate callouts:
|
|
|
|
|
|
The following sections cover some of the ways in which these can be used.
|
|
|
|
|
|
-@subsubsection hookNonstandardCalloutNames Non-Standard Callout Names
|
|
|
+@subsubsection hooksdgNonstandardCalloutNames Non-Standard Callout Names
|
|
|
|
|
|
The example in the tutorial used standard names for the callouts. As noted
|
|
|
above, it is possible to use non-standard names. Suppose, instead of the
|
|
|
-callout names "pkt_rcvd" and "v4_lease_write", we had named out callouts
|
|
|
+callout names "pkt_rcvd" and "v4_lease_write", we had named our callouts
|
|
|
"classify" and "write_data". The hooks framework would not have registered
|
|
|
these callouts, so we would have needed to do it ourself. The place to
|
|
|
do this is the "load" framework function, and its code would have had to
|
|
@@ -670,7 +829,7 @@ It is possible for a library to contain callouts with both standard and
|
|
|
non-standard names: ones with standard names will be registered automatically,
|
|
|
ones with non-standard names need to be registered manually.
|
|
|
|
|
|
-@subsubsection hookMultipleCallouts Multiple Callouts on a Hook
|
|
|
+@subsubsection hooksdgMultipleCallouts Multiple Callouts on a Hook
|
|
|
|
|
|
The BIND 10 hooks framework allows multiple callouts to be attached to
|
|
|
a hook point. Although it is likely to be rare for user code to need to
|
|
@@ -684,16 +843,16 @@ LibraryHandle::registerCallout multiple times on the same hook, e.g.
|
|
|
libhandle.registerCallout("pkt_rcvd", write_data);
|
|
|
@endcode
|
|
|
|
|
|
-The hooks framework will call the callouts in the order they are registered.
|
|
|
-The same CalloutHandle is passed between them, so any change made to the
|
|
|
-CalloutHandle's arguments or per-request context by the first is visible
|
|
|
-to the second.
|
|
|
+The hooks framework will call the callouts in the order they are
|
|
|
+registered. The same CalloutHandle is passed between them, so any
|
|
|
+change made to the CalloutHandle's arguments, "skip" flag, or per-request
|
|
|
+context by the first is visible to the second.
|
|
|
|
|
|
-@subsubsection hookDynamicRegistration Dynamic Registration and Reregistration of Callouts
|
|
|
+@subsubsection hooksdgDynamicRegistration Dynamic Registration and Reregistration of Callouts
|
|
|
|
|
|
The previous sections have dealt with callouts being registered during
|
|
|
the call to "load". The hooks framework is more flexible than that
|
|
|
-in that callouts and be registered and deregistered within a callout.
|
|
|
+in that callouts can be registered and deregistered within a callout.
|
|
|
In fact, a callout is able to register or deregister itself, and a callout
|
|
|
is able to be registered on a hook multiple times.
|
|
|
|
|
@@ -716,7 +875,11 @@ int pkt_rcvd(CalloutHandle& handle) {
|
|
|
|
|
|
// Classify it.
|
|
|
if (sum % 4 == 0) {
|
|
|
- // Interesting, register the callback to log the data.
|
|
|
+ // Store the text form of the hardware address in the context to pass
|
|
|
+ // to the next callout.
|
|
|
+ handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
|
|
|
+
|
|
|
+ // Register the callback to log the data.
|
|
|
handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
|
|
|
}
|
|
|
|
|
@@ -758,7 +921,7 @@ int write_data(CalloutHandle& handle) {
|
|
|
@endcode
|
|
|
|
|
|
Note that the above example used a non-standard name for the callout
|
|
|
-that wronte the data. Had the name been a standard one, it would have been
|
|
|
+that wrote the data. Had the name been a standard one, it would have been
|
|
|
registered when the library was loaded and called for the first request,
|
|
|
regardless of whether that was defined as "interesting". (Although as
|
|
|
callouts with standard names are always registered before "load" gets called,
|
|
@@ -768,15 +931,14 @@ callout in the "load" function.)
|
|
|
|
|
|
@note Deregistration of a callout on the hook that is currently
|
|
|
being called only takes effect when the server next calls the hook.
|
|
|
-To illustrate this, suppose the callouts attached to a hook are A,
|
|
|
-B and C (in that order), and during execution, A deregisters B and C
|
|
|
-and adds D. When callout A returns, B and C will still run. The next
|
|
|
-time the server calls the callouts attached to the hook, callouts
|
|
|
-A and D will run (in that order).
|
|
|
+To illustrate this, suppose the callouts attached to a hook are A, B and C
|
|
|
+(in that order), and during execution, A deregisters B and C and adds D.
|
|
|
+When callout A returns, B and C will still run. The next time the server
|
|
|
+calls the hook's callouts, A and D will run (in that order).
|
|
|
|
|
|
-@subsection hookMultipleLibraries Multiple User Libraries
|
|
|
+@subsection hooksdgMultipleLibraries Multiple User Libraries
|
|
|
|
|
|
-As alluded to in the section @ref hookConfiguration, BIND 10 can load
|
|
|
+As alluded to in the section @ref hooksdgConfiguration, BIND 10 can load
|
|
|
multiple libraries. The libraries are loaded in the order specified in
|
|
|
the configuration, and the callouts attached to the hooks in the order
|
|
|
presented by the libraries.
|
|
@@ -818,7 +980,7 @@ It is stressed that the context for callouts associated with different
|
|
|
libraries is entirely separate. For example, suppose "authorize" sets
|
|
|
the CalloutHandle's context item "foo" to 2 and "logpkt" sets an item of
|
|
|
the same name to the string "bar". When "check" accesses the context
|
|
|
-item "foo", it gets a value of 2: when "validate" accesses an item of
|
|
|
+item "foo", it gets a value of 2; when "validate" accesses an item of
|
|
|
the same name, it gets the value "bar".
|
|
|
|
|
|
It is also stressed that all this context exists only for the life of the
|
|
@@ -831,7 +993,7 @@ without worrying about the presence of other libraries. Other libraries
|
|
|
may be present, but will not affect the context values set by a library's
|
|
|
callouts.
|
|
|
|
|
|
-@subsection hookInterLibraryData Passing Data Between Libraries
|
|
|
+@subsection hooksdgInterLibraryData Passing Data Between Libraries
|
|
|
|
|
|
In rare cases, it is possible that one library may want to pass
|
|
|
data to another. This can be done in a limited way by means of the
|
|
@@ -850,7 +1012,7 @@ the dollar symbol or percent sign. In this way there is no danger that
|
|
|
a name will conflict with any existing or future BIND 10 argument names.
|
|
|
|
|
|
|
|
|
-@subsection hookRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
|
|
|
+@subsection hooksdgRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
|
|
|
|
|
|
On a particular hook, callouts are called in the order the libraries appear
|
|
|
in the configuration and, within a library, in the order the callouts
|