DHCP Server Callout API usage

Microsoft DHCP Server Callout API provides a way for developers to access the critical phases of DHCP protocol processing in Windows Server 2003 family and later. This enables developers to:

· Create customized extensions to the Microsoft DHCP Server

· Monitor statistics

· Create parallel lease databases

· Provide other customized solutions

Refer this link for a description of the callout API interface.

There are few things one should keep in mind when implementing the callout dll

1. If a callout DLL needs to modify the new packet (packet received by the DHCP server from a DHCP client or a relay agent) or send packet (response packet being sent by DHCP server to a DHCP client or a relay agent), the packet buffer should be modified in place. The packet buffer passed in as parameter to the callback functions should not be freed. The size of the packet buffer passed in is 4096 bytes.

2. If a callout DLL needs store additional information, related to the packet, which should persist across various callbacks, it can provide a packet context in PktContext parameter. One may use malloc/free or HeapAlloc/HeapFree APIs for allocating and de-allocating buffer for the pointer.

3. The buffer allocated for packet context must be freed to avoid any memory leaks. One may choose to free it in

· DhcpPktSendHook and DhcpPktDropHook (when control code is not DHCP_DROP_PROCESSED), or

· DhcpPktDropHook (when control code is DHCP_DROP_PROCESSED)

4. A callout DLL should not be making calls to DHCP server management APIs as this may lead to deadlock situation while accessing shared resources like the database, registry and internal data structures. The DHCP Server management APIs are documented here.

Below is a sample callout code which enables option 82 support with Microsoft DHCP Server. DHCP option 82 is “DHCP Relay Agent Information Option” and allows a DHCP Relay Agent to insert circuit specific information into a request that is being forwarded to a DHCP Server.

Microsoft DHCP Server currently drops option 82 in the response packets. This callout DLL stores option 82 inside packet context in DhcpNewPktHook and then adds the option back in the DhcpPktSendHook using the information stored in packet context.

We thank Mr Aki Tuomi, the author of this sample callout code (“Sample Code”), for contributing this sample and for letting us publish it here. This Sample Code is published here “as is” and is for informational purposes only. MICROSOFT MAKES NO CLAIMS OF OWNERSHIP OF THIS SAMPLE CODE AND MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE ACCURACY , SUITABILITY OR CORRECTNESS OF THIS SAMPLE CODE. For any questions regarding this Sample Code, please contact Mt. Aki Tuomi at 'cmouse AT desteem DOT org'.

Note: This sample code does not enable IP address or any other network configuration assignment to a DHCP client based on the relay agent information contained in option 82.

#include "stdafx.h"

#include <stdio.h>

#include "dhcpssdk.h"

DWORD CALLBACK DhcpControlHook(DWORD dwControlCode,LPVOID lpReserved)

{

      switch (dwControlCode)

      {

      case DHCP_CONTROL_START:

            {

   CalloutFile = fopen("callout.txt", "w");

                  if (CalloutFile != NULL) fprintf(CalloutFile,"The DHCP server has successfully started.rn");

                        break;

            }

            case DHCP_CONTROL_STOP:

            {

                  if (CalloutFile != NULL) fprintf(CalloutFile,"The DHCP server has successfully stopped.rn");

                  if (CalloutFile != NULL) fclose(CalloutFile);

                  break;

            }

            case DHCP_CONTROL_PAUSE:

            {

                  if (CalloutFile != NULL) fprintf(CalloutFile,"The DHCP server has been paused.rn");

                  break;

            }

            case DHCP_CONTROL_CONTINUE:

            {

                  if (CalloutFile != NULL) fprintf(CalloutFile,"The DHCP server has been continued.n");

                  break;

            }

      }

      return ERROR_SUCCESS;

}

DWORD CALLBACK DhcpNewPktHook(LPBYTE* Packet,DWORD* PacketSize,DWORD IpAddress,LPVOID Reserved,LPVOID* PktContext,LPBOOL ProcessIt)

{

      int guard;

      DWORD pos;

      LPBYTE pkt = (*Packet);

      (*PktContext) = NULL;

      if (CalloutFile != NULL) fprintf(CalloutFile, "Received packet size %drn", *PacketSize);

      // packet size must be > 237

      if (*PacketSize < 241) return ERROR_SUCCESS;

      // capture possible option 82 in packet and store in PktContext

      // find where option 82 is, and then capture it

      for(pos = 240, guard = 0; pos < *PacketSize && guard < 20; guard++)

      {

            fprintf(CalloutFile, "Found option %d, len %drn", pkt[pos], pkt[pos+1]);

            // scan option code

            if (static_cast<char>(pkt[pos]) == DHCP_OPTION_82)

            {

                  DWORD len = static_cast<DWORD>(pkt[pos+1]);

                  if (pos + len < *PacketSize)

                  {

                        if (CalloutFile != NULL) fprintf(CalloutFile, "Found Option82 on position %d, len %drn", pos, len);

                        // Allocate buffer for packet context, where option 82 information will be stored.

                        LPBYTE ctx = static_cast<LPBYTE>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+3));

                        ctx[0] = static_cast<BYTE>(len+2);

                        memcpy_s(ctx+1, len+2, &pkt[pos], len+2);

           &n