[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

Communications Programming Concepts


DHCP Server API

The DHCP server lets you define modules that can be linked to the DHCP Server and called at specified checkpoints during DHCP or BOOTP message processing. This section describes the following:

Note: Because the DHCP server is run with root-user authority, user-defined objects can introduce security vulnerabilities and performance degradation. Especially protect against buffer overrun exploitations and enforce security measures when an object writes to temporary files or executes system commands. Also, since many of the routines that can be defined by the object are executed during the normal processing path of each DHCP client's message, monitor the response time to the DHCP client for any impacts on performance.

Loading User Objects

The DHCP server loads any user-defined object referenced in the configuration file with the UserObject configuration line or stanza. For example:

  UserObject myobject

or

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

For both of these examples, the dynamically loadable shared object myobject.dhcpo is loaded from the /usr/sbin directory. In the second case, the object's Initialize subroutine is passed a file pointer; the object must parse and handle its own configuration stanza.

Predefined Structures

The operating system provides the following structures through the dhcp_api.h file. The structures are more thoroughly described in the following sections.

dhcpmessage

dhcpmessage defines the structure and fields of a basic DHCP message. The options field is variable in length and every routine that references a DHCP message also specifies the total length of the message. The content of the structure follows:

  struct dhcpmessage
  {
         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];
  };

dhcpoption

dhcpoption defines the framework of a DHCP option encoded in its type, length, data format. The content of the structure follows:

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

dhcpclientid

dhcpclientid uniquely identifies a DHCP client. You can define it using the DHCP Client Identifier Option or it can be created from the hardware type, hardware length, and hardware address of a DHCP or BOOTP message that does not contain a Client Identifier Option. The DHCP message option and client identifier references always point to network byte-ordered data. The content of the structure follows:

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

dhcplogseverity

The enumerated type dhcplogseverity assigns a log severity level to a user-defined object's error messages. An object's error message is displayed to the DHCP server's log file through the exported dhcpapi_logmessage routine, provided that logging severity level has been enabled.

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

User-Defined Object Requirements

The following are required for any user-defined object to conform to this API:

  1. The object must use the Initialize routine.
  2. The object must use the Shutdown routine.
  3. The object must contain at least one of the checkpoint routines defined in the API.
  4. The object must never alter any data provided by a const pointer reference to the routine.

Initialize

The Initialize 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.

The following is the structure of the Initialize routine:

int Initialize       ( FILE *fp,
                       caddr_t *hObjectInstance               ) ;

Where:

fp Points to the configuration block for the loaded UserObject. The value of the pointer is NULL if no configuration block exists following the UserObject definition in the DHCP Server configuration file.
hObjectInstance Is set by the loaded object if the object requires private data to be returned to it through each invocation. One handle is created for each configuration instance of the loaded object.

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 continue only as far as an unmatched close brace (}), which indicates the end of the configuration block.

The Initialize routine does not require setting the hObjectInstance handle. However, it is required that the routine return specific codes, depending on whether the initialization succeeded or failed. The required codes and their meanings follow:

0 (zero) Instance is successfully initialized. The server can continue to link to each symbol.
!= 0 (non-zero) Instance failed to initialize. The server can free its resources and continue to load, ignoring this section of the configuration file.

Shutdown

The Shutdown routine is used to reverse the effects of initialization: to deallocate data and to destroy threads. The Shutdown routine is called before shutting down the server and again before reloading the configuration file at each server reinitialization. The routine must return execution to the server so the server can reinitialize and properly shut down. The following is the structure of the Shutdown routine:

void Shutdown        ( caddr_t hObjectInstance                ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.

Checkpoint Routines

A user-defined object must implement at least one of the following checkpoint routines. The routines are more thoroughly described in the following sections.

messageReceived

The messageReceived routine lets you add an external means of authentication to each received DHCP or BOOTP message. The routine is called just as the message is received by the protocol processor and before any parsing of the message itself.

In addition to the message, the server passes three IP addresses to the routine. These addresses, when used together, can determine whether the client is on a locally attached network or a remotely routed network and whether the server is receiving a broadcast message.

Additionally, you can use the messageReceived routine to alter the received message. Because changes directly affect the remainder of message processing, use this ability rarely and only under well-understood circumstances.

The following is the structure of the messageReceived routine:

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         ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
inMessage Is a pointer to the unaltered, incoming DHCP or BOOTP message.
messageSize Is the total length, in bytes, of the received DHCP or BOOTP message.
receivingIP Is the IP address of the interface receiving the DHCP or BOOTP message.
destinationIP Is the destination IP address taken from the IP header of the received DHCP or BOOTP message.
sourceIP Is the source IP address taken from the IP header of the received DHCP or BOOTP message.

The messageReceived routine returns one of the following values:

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) The source client of this message is not to be given any response from this server. This server remains silent to the client.

addressOffered

The addressOffered routine is used for accounting. Parameters passed to the routine are read-only. The routine has no return code to prevent sending the outgoing message. It is called when a DHCP client is ready to be sent an address OFFER message. The following is the structure of the addressOffered routine:

void addressOffered  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const struct dhcpmessage *outMessage,
                       size_t messageSize                     ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address to be offered to the client.
outMessage Is the outgoing message that is ready to be sent to the client.
messageSize Is the length, in bytes, of the outgoing message that is ready to be sent to the client.

addressAssigned

The addressAssigned 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.

The addressAssigned routine is called after the database has associated the address with the client and just before sending the BOOTP response or DHCP ACK to the client. If a DNS update is configured, the addressAssigned routine is called after the update has occurred or, at least, has been queued.

Parameters offered to the routine are read-only. The routine has no return code to prevent address and client binding. The structure of the addressAssigned routine follows:

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                     ) ;


hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address selected for the client.
hostname Is the host name which is (or should have been) associated with the client.
domain Is the domain in which the host name for the client was (or should have been) updated.
outMessage Is the outgoing message that is ready to be sent to the client.
messageSize Is the length, in bytes, of the outgoing message that is ready to be sent to the client.

addressReleased

The addressReleased routine is used for accounting when DHCP clients are ready to be sent an address OFFER message. Parameters given to the routine are read-only.

The routine is called just after the database has been instructed to disassociate the client identifier and address binding. If so configured, the routine is called after the DNS server has been indicated to disassociate the name and address binding.

The structure of the addressReleased routine follows:

void addressReleased ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address previously used by the client.
hostname Is the hostname previously associated with this client and address binding.
domain Is the domain in which the hostname for the client was (or should have been) previously updated.

addressExpired

The addressExpired routine is used for accounting when any DHCP database detects an association must be cancelled because the address and client identifier association has existed beyond the end of the offered lease. Parameters given to the routine are read-only.

The structure of the addressExpired routine follows:

void addressExpired  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address previously used by the client.
hostname Is the hostname previously associated with this client and address binding.
domain Is the domain in which the hostname for the client was (or should have been) previously updated.

addressDeleted

The addressDeleted routine is used for accounting when any address association is explicitly deleted from lack of interaction with the client or because of a lease expired. Most commonly, this routine is invoked when the DHCP server is reinitialized, when a new configuration might cause a previous client and address association to become invalid, or when the administrator explicitly deletes an address using the dadmin command. Parameters given to the routine are read-only.

The structure of the addressDeleted routine follows:

void addressDeleted  ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address previously used by the client.
hostname Is the hostname previously associated with this client and address binding.
domain Is the domain in which the hostname for the client was (or should have been) previously updated.

addressDeclined

The addressDeclined routine is used for accounting purposes when a DHCP client indicates to the server (through the DHCP DECLINE message type) that the given address is in use on the network. The routine is called immediately after the database has been instructed to disassociate the client identifier and address binding. If so configured, the routine is called after the DNS server has been indicated to disassociate the name and address binding. Parameters given to the routine are read-only.

The structure of the addressDeclined routine follows:

void addressDeclined ( caddr_t hObjectInstance,
                       const struct dhcpclientid *cid,
                       const struct in_addr *addr,
                       const char *hostname,
                       const char *domain                     ) ;

Where:

hObjectInstance Is the same configuration instance handle created when this object was initialized.
cid Is the client identifier of the client.
addr Is the address that was declined by the client.
hostname Is the hostname previously associated with this client and address binding.
domain Is the domain in which the hostname for the client was (or should have been) previously updated.

User-Defined Object Optional Routine

The dhcpapi_logmessage routine is available to the user-defined object programmer. A prototype is available in dhcpapi.h with the symbol defined for linking in /usr/lib/dhcp_api.exp.

The routine specifies a message that is logged to the DHCP server's configured log file, provided that message severity level, which specified by the s parameter, has been enabled. The structure of the dhcpapi_logmessage routine follows:

void dhcpapi_logmessage ( enum dhcplogseverity s,
                          char *format,
                          ...                                              ) ;


s Is the severity level 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 Is the typical printf format string.


[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]