[ Next Article | Previous Article | Book Contents | Library Home | Legal | Search ]
Communications Programming Concepts

DHCP Server API

The DHCP Server allows administrators and third parties to develop modules to be linked to the DHCP Server and be called at specific checkpoints throughout the processing of a DHCP or BOOTP message.

This API specifies the routines, their prototypes, and the desired function of each symbol to be exported by the user-defined module. Additionally, this document mentions the structures used by the DHCP server and any User-Defined Object and the symbols exported by the DHCP server as utilities to the API Programmer.

General

It is noted that security and performance degredation may be introduced by any User-Defined Object.

Because the DHCP server is run with root user authority, special care should be taken to ensure no security vulnerabilities are introduced by the User-Defined Object. This includes taking steps to protect against buffer overrun exploitations, and every possible security measure when writing to temporary files on the disk or executing system commands.

Also, as many of the routines that can be defined by the User Object are executed during the normal processing path of each DHCP client's message, care should be taken to not slow the possible response to the DHCP client.

Configuration

A User-Defined Object can be referenced and loaded by the DHCP server if specified in the configuration file with the "UserObject" configuration line or stanza. For example:

  UserObject myobject

or

  UserObject myobject
  {
         file /tmp/myobject.log;
  }

In both cases, the dynamically loadable shared object "myobject.dhcpo" will be loaded from the /usr/sbin directory. In the second case, the object's Initialize() routine will be passed a file pointer as it is the responsibility of the object to parse and handle its own configuration stanza.

Structures

dhcpmsg

  struct dhcpmsg
  {
         uint8_t        op;
         uint8_t        htype;
         uint8_t        hlen;
         uint8_t        hops;
         uint32_t       xid;
         uint16_t       secs;
         uint16_t       flags;
         uint32_t       ciaddr;
         uint32_t       yiaddr;
         uint32_t       siaddr;
         uint32_t       giaddr;
         uint8_t        chaddr[16];
         uint8_t        sname[64];
         uint8_t        file[128];
         uint8_t        options[1];
  };

dhcpmsg defines the structure and fields of the basic DHCP message. The options field is variable in length and every routine referencing a DHCP message will also specify the total length of the message.

dhcpoption

  struct dhcpoption
  {
         uint8_t        code;
         uint8_t        len;
         uint8_t        data[1];
  };

dhcpoption defines the framework of a DHCP option encoded in its type, length, data format.

dhcpclientid

struct dhcpclientid
  {
          uint8_t         type;
          uint8_t         len;
          uint8_t         id[64];
  };

dhcpclientid uniquely identifies a DHCP client. It either defines the DHCP Client Identifier Option or it is created from the hardware type, hardware length, and harware address of a DHCP or BOOTP message that does not contain a Client Identifier Option. Both the DHCP message option and client identifier references will always point to network byte-ordered data.

dhcplogseverity

enum dhcplogseverity
  {
          dhcplog_syserr = 1 ,
          dhcplog_objerr ,
          dhcplog_protocol ,
          dhcplog_warning ,
          dhcplog_event ,
          dhcplog_action ,
          dhcplog_info ,
          dhcplog_accounting ,
          dhcplog_stats ,
          dhcplog_trace
  };

The enumerated type dhcplogseverity is used to indicate to the DHCP server what log severity should be used when displaying a User-Defined Object's error message to the DHCP server's log file through the exported routine dhcpapi_logmessage(). The severity must be enabled for logging for the message to be displayed.

Routines

A few requirements exist to conform to this API. The User-Defined Object MUST:

  1. provide the initialization routine, Initialize().
  2. provide the shutdown routine, Shutdown().
  3. provide at least one of the checkpoint functions defined in the API.
  4. NEVER alter any data given through reference to the routine when the reference is a "const" pointer.

Required Routines

Initialize
int Initialize       ( FILE *fp,
                       caddr_t *hObjectInstance               ) ;
Parameter Meaning
fp An open FILE pointer in which the next line to be read is the configuration block for the UserObject that is loaded. The pointer will be NULL if no configuration block exists following the UserObject definition in the DHCP Server configuration file.
hObjectInstance To be set by the loaded object if the object requires private data to be returned to it through each invocation. A handle is created per configuration instance of the loaded object, not once per the loading of the object.
Return Meaning
0 (zero) Object instance is successfully initialized. The server should continue to link to each symbol.
!= 0 (non-zero) Object instance failed to initialize. The server can free its resources and continue to load, ignoring this section of the configuration file.

This routine must be defined by the object to be loaded by the server. It is used each time the server is started, including restarts, and is called each time the object is referenced in the DHCP server's configuration file. It is not a requirement that the Initialize() routine set the hObjectInstance handle. However, it is required that the routine return a zero if successful and a non-zero if failure. Failure indicates that the object's checkpoint routines cannot and will not be used by the server.

If the file pointer, fp, is not NULL, its initial value references the first line of contained data within the configuration block of the User-Defined Object. Parsing should only continue to as far as an unmatched } (close brace) is read, as this indicates the end of the configuration block.

Shutdown
void Shutdown        ( caddr_t hObjectInstance                ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
This routine is called prior to the shutdown of the server and prior to reloading the configuration file at each reinitialization of the server. It should be used to deallocate all data allocated on an initialization including the destruction of any threads created during initialization. Execution must be returned to the server or the server will fail to reinitialize and properly shut down.

Checkpoint Routines

Only one of the following routines must be implemented by the Extension Object.

messageReceived
int messageReceived  ( caddr_t hObjectInstance,
                       struct dhcpmessage **inMessage,
                       size_t *messageSize,
                       const struct in_addr *receivingIP,
                       const struct in_addr *destinationIP,
                       const struct in_addr *sourceIP         ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
inMessage Points to the incoming DHCP or BOOTP message, unaltered.
messageSize Total length, in bytes, of the received DHCP or BOOTP message.
receivingIP Interface IP address receiving the DHCP or BOOTP message.
destinationIP Destination IP address taken from the IP header of the received DHCP or BOOTP message.
sourceIP Source IP address taken from the IP header of the received DHCP or BOOTP message.
Return Meaning
0 (zero) The received message can continue to be parsed and the client possibly offered or given an address through the regular means of the DHCP server.
!= 0 (non-zero) It is determined that the source client of this message not be given any response from this server. The server will remain silent to the client.
The messageReceived() routine is a mechanism through which the programmer can add an external means of authentication to each received DHCP or BOOTP message. It is called just as the message is received by the protocol processor prior to any parsing of the message.

The routine is passed not only the message itself but three IP addresses in addition; these addresses used together can determine whether the client is on a locally attached network, a remotely routed network, and whether the server is receiving a broadcast message.

Additionally, the programmer has the ability to alter the received message, but because this directly affects the remainder of message processing, great care should be taken to only use this ability in rare and well- understood occasions.

addressOffered
void addressOffered  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const struct dhcpmessage *outMessage,
                       size_t messageSize                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address to be offered to the client.
outMessage The outgoing message ready to be sent to the client.
messageSize The length, in bytes, of the outgoing message ready to be sent to the client.
The addressOffered() routine is called with DHCP clients are ready to be sent an address OFFER message. Its main purpose is to be used for accounting as all the parameters only given to the routine Read-Only, and the routine has no return code to prevent the outgoing message to be sent.
addressAssigned
void addressAssigned ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain,
                       const struct dhcpmessage *outMessage,
                       size_t messageSize                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address selected for the client.
hostname The hostname which was or should have been associated with the client.
domain The domain in which the hostname for the client was or should have been be updated.
outMessage The outgoing message ready to be sent to the client.
messageSize The length, in bytes, of the outgoing message ready to be sent to the client.
The addressAssigned() routine is called after the database has associated the address with the client and just prior to sending the BOOTP response or DHCP ACK to the client. If configured, a DNS update has already been queued or has already occured.

This routine can be used for accounting purposes or to add an external means of name and address association. The hostname and domain arguments are selected based upon the A record proxy update policy and the append domain policy (configured in the db_file database through the keywords proxyARec and appendDomain, respectively), as well as the defined and suggested hostname and domain options for the client.

All parameters are offered to the user-defined routine as Read-Only, and no return value is presented as a means of preventing the address and client binding.

address Released
void addressReleased ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address previously in use by the client.
hostname The hostname previously associated by the server with this client and address binding.
domain The domain in which the hostname for the client was previously or should have previously been updated.
The addressReleased() routine is called when DHCP clients are ready to be sent an address OFFER message. Its main purpose is to be used for accounting as all the parameters are only given to the routine Read-Only. The routine is called just after the database has been instructured to disassociate the client identifier and address binding, and if configured, after the DNS server has been indicated to disassociate the name and address binding.
addressExpired
void addressExpired  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address previously in use by the client.
hostname The hostname previously associated by the server with this client and address binding.
domain The domain in which the hostname for the client was previously or should have previously been updated.
The addressExpired() routine is called when any DHCP database has determined that the address and client identifier association has existed beyond the end of any offered lease, and therefore the association has been canceled. Its main purpose is to be used for accounting as all the parameters are only given to the routine Read-Only.
addressDeleted
void addressDeleted  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address previously in use by the client.
hostname The hostname previously associated by the server with this client and address binding.
domain The domain in which the hostname for the client was previously or should have previously been updated.
The addressDeleted() routine is called when any address association is explicitly deleted without any interaction from the client or because of any lease expiration. The most common cases in which this routine will be invoked include the reinitialization of the DHCP server, when realizing a new configuration may cause a previous client and address association to become invalid, and when the administrator explicitly deletes an address by using the dadmin command. Its main purpose is to be used for accounting as all the parameters are only given to the routine Read-Only.
addressDeclined
void addressDeclined ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;
Parameter Meaning
hObjectInstance The configuration instance handle created when this object was initialized.
cid The client identifier of the client.
addr The address that was declined by the client.
hostname The hostname previously associated by the server with this client and address binding.
domain The domain in which the hostname for the client was previously or should have previously been updated.
The addressDeclined() routine is used when a DHCP client indicates to the server that the given address is in use on the network. The DHCP client does this through the DHCP DECLINE message type. The main purpose of this routine is to be used for accounting as all the parameters are only given to the routine Read-Only. The routine is called just after the database has been instructured to disassociate the client identifier and address binding, and if configured, after the DNS server has been indicated to disassociate the name and address binding.

Exported Routines

The following routine is available to the user-defined object programmer. The prototype is available in <dhcpapi.h> with the symbol defined for linking in /usr/lib/dhcp_api.exp.
dhcpapi_logmessage
void dhcpapi_logmessage ( enum dhcplogseverity s,
                          char *format,
                          ...                                              ) ;
Parameter Meaning
s Severity of the message to be logged. Message severities are defined in the dhcpapi.h header file and correspond directly to the DHCP server configuration logItem levels of logging.
format Typical printf() format string.
Specifies a message to be logged to the DHCP server's configured log file. The message severity specified by the s parameter must be enabled in the logging configuration of the server for the message will not be displayed.

[ Next Article | Previous Article | Book Contents | Library Home | Legal | Search ]