All about the DHCP server callout API functions.

Ah now for the best part. I had always wanted to test this callout API thing. This is perhaps the most powerful way to leverage your Windows DHCP server. With the DHCP server callout, in a way, the whole DHCP server source code is before you for you to change and fine tune to your specific needs. In reality you really don't get the source code access but you do get all the power you would get had you really had the source code access. This is perhaps the best way to encourage people to build upon and extend your software's capability while still staying in the commercial realm and without throwing open the product's source code. I won't discuss the nitty-gritties of this callout technique as it has been properly documented here: DHCP Server callout API.

Possiblities unlimited:

Some of the exciting things that are possible with the DHCP Callout DLL:
1) Create a parallel lease database in your favorite DB say SQLServer. With this you get the power to monitor the leasing process in a very flexible way (say using SQL, you can run a query to list all those machines which got an IP address in the last 2 hours).
2) Create customized extensions to the DHCP server: This is a pretty loaded sentence. What this fact implies is that with the callout DLL, you can prevent giving IP address unless the client satifies some policy: like membership to a given user class or a given vendor class. This is pretty usefull if you want to enforce minimum security to your enterprise, just ensure that only the authenticaled users are let known the user class say 'xyz'. Now prevent leasing out IP address unless the client belongs to this user class. This can be done when you implement the function DhcpNewPktHook and set the ProcessIt flag to FALSE when you don't see the right user class in the Packet. For this you need to parse the packet which is a BYTE *. :-(

Now for the hard part: Even though this callout DLL support has been there for a while, I really don't see people using this. (Prove me wrong!) Even though the online documentation has clearly explained the technology in some good detail, there is no sample code which people can readily use. So here I am to give you exactly these: A sample implementation of the callout DLL and the registry settings to enable the callout DLL's functioning.

Sample Code:

//Mind you this is a very simple implementation of the callout DLL.

//Our callout function just logs the various states into a file (and that too incompletely..)

//But I guess you people should take it from here......

#include <windows.h>
#include <stdio.h>
#include "dhcpssdk.h"

FILE * CalloutFile;

DWORD CALLBACK DhcpAddressDelHook
(LPBYTE Packet,DWORD PacketSize,DWORD ControlCode,DWORD IpAddress,DWORD AltAddress,LPVOID Reserved,LPVOID PktContext)
{
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpAddressOfferHook
(LPBYTE Packet,DWORD PacketSize,DWORD ControlCode, DWORD IpAddress,DWORD AltAddress,DWORD AddrType,DWORD LeaseTime,LPVOID Reserved,LPVOID PktContext)
{
char PacketBuff[4096];
if(ControlCode==DHCP_GIVE_ADDRESS_NEW)
{
fprintf(CalloutFile,"Offering new address %x %d on interface %x for %d seconds\n",AltAddress,AltAddress,IpAddress,LeaseTime);
}
else if(ControlCode==DHCP_GIVE_ADDRESS_OLD)
{
fprintf(CalloutFile,"Offering old address %x %d on interface %x for %d seconds\n",AltAddress,AltAddress,IpAddress,LeaseTime);
}
if(PacketSize<4096)
{
memcpy(PacketBuff,Packet,PacketSize);
PacketBuff[PacketSize]='\0';
fprintf(CalloutFile,"Packet: %s\n",PacketBuff);
}
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpControlHook(DWORD dwControlCode,LPVOID lpReserved)
{
switch (dwControlCode)
{
case DHCP_CONTROL_START:
{
CalloutFile=fopen("callout.txt","w");
fprintf(CalloutFile,"The DHCP server has successfully started.\n");
break;
}
case DHCP_CONTROL_STOP:
{
fprintf(CalloutFile,"The DHCP server has successfully stoped.\n");
fclose(CalloutFile);
break;
}
case DHCP_CONTROL_PAUSE:
{
fprintf(CalloutFile,"The DHCP server has been paused.\n");
break;
}
case DHCP_CONTROL_CONTINUE:
{
fprintf(CalloutFile,"The DHCP server has been continued.\n");
break;
}
}
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpDeleteClientHook(DWORD IpAddress, LPBYTE HwAddress,ULONG HwAddressLength, DWORD Reserved,DWORD ClientType)
{
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpNewPktHook(LPBYTE* Packet,DWORD* PacketSize,DWORD IpAddress,LPVOID Reserved,LPVOID* PktContext,LPBOOL ProcessIt)
{
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpPktDropHook(LPBYTE* Packet,DWORD* PacketSize,DWORD ControlCode, DWORD IpAddress,LPVOID Reserved,LPVOID PktContext)
{
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpPktSendHook(LPBYTE* Packet,DWORD* PacketSize,DWORD ControlCode,DWORD IpAddress,LPVOID Reserved,LPVOID PktContext)
{
return ERROR_SUCCESS;
}

DWORD CALLBACK DhcpServerCalloutEntry(LPWSTR ChainDlls,DWORD CalloutVersion,LPDHCP_CALLOUT_TABLE CalloutTbl)
{
CalloutTbl->DhcpAddressDelHook=DhcpAddressDelHook;
CalloutTbl->DhcpControlHook=DhcpControlHook;
CalloutTbl->DhcpDeleteClientHook=DhcpDeleteClientHook;
CalloutTbl->DhcpPktDropHook=DhcpPktDropHook;
CalloutTbl->DhcpAddressDelHook=DhcpAddressDelHook;
CalloutTbl->DhcpNewPktHook=DhcpNewPktHook;
CalloutTbl->DhcpPktSendHook=DhcpPktSendHook;
return ERROR_SUCCESS;
}

The DHCP callout Cookbook:
1) After writing your program for creating the callout DLL, make sure that your DLL exports the functions DhcpServerCalloutEntry, DhcpAddressDelHook, DhcpControlHook, DhcpPktDropHook, DhcpAddressDelHook, DhcpNewPktHook and DhcpPktSendHook. These functions should be GetProcAddress'able once the DHCP Server LoadLibrary's your DLL. Otherwise you would be seeing the event 1034 logged on to your system event log.
2)One more thing, to compile this code you should be needing the Platform SDK. This is required as the header file which contains all the relevant callout data structures, dhcpssdk.h comes along with the Platform SDK. Don't forget to set your compiler's include path to the place where dhcpssdk.h is copied.
3) Last but not the least once you have created the DLL, you can copy it to any place (say c:\callout\callout.dll) in your Windows server (Windows Server 2003 or Windows 2000 Server.)
4) Now comes the registry nibbling part. As usual backup your registry. The following are the two registry entries which should be created and which are located within:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\DHCPServer\Parameters
1)
Name : CalloutDlls
Value : list of path/filenames for the dlls to be loaded. In our case it is c:\callout\callout.dll
Type : REG_MULTI_SZ
2)
Name : CalloutEnabled
Value :
0 = DHCP Server does not attempt load of callout.dlls
1 = DHCP Server attempts to load callout.dlls
Type : DWORD
BTW, This information is not available in the MSDN.
Now restart the DHCP service. If everything went well you should see the event 1033 logged on in your system event log: "The DHCP service has successfully loaded one or more callout DLLs." Congrats!