Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

872 lines
21 KiB

/*++
Copyright (C) 1999-2002 Microsoft Corporation
Module Name:
isdhcp.c
Abstract:
test program to see if a DHCP server is around or not.
Environment:
Win2K+
History:
Code provided by JRuan on May 8, 2002 and integrated into
CYS by JeffJon
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <dhcpcapi.h>
#include <iprtrmib.h>
#include <iphlpapi.h>
#include <stdio.h>
#define OPTION_PAD 0
#define OPTION_HOST_NAME 12
#define OPTION_MESSAGE_TYPE 53
#define OPTION_SERVER_IDENTIFIER 54
#define OPTION_PARAMETER_REQUEST_LIST 55
#define OPTION_CLIENT_ID 61
#define OPTION_END 255
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVR_PORT 67
BYTE HardwareAddress[16];
BYTE HardwareAddressLength = 6;
#define SOCKET_RECEIVE_BUFFER_SIZE 1024 * 4 // 4K max.
#define AUTH_SERVERS_MAX 64
#define SMALL_BUFFER_SIZE 32
#define ALERT_INTERVAL 5 * 60 // 5 mins
#define ALERT_MESSAGE_LENGTH 256
#define MAX_ALERT_NAMES 256
#define BOOT_REQUEST 1
#define DHCP_BROADCAST 0x8000
#define DHCP_DISCOVER_MESSAGE 1
#define DHCP_INFORM_MESSAGE 8
#define DHCP_MESSAGE_SIZE 576
#define DHCP_RECV_MESSAGE_SIZE 4096
#define BOOT_FILE_SIZE 128
#define BOOT_SERVER_SIZE 64
#define DHCP_MAGIC_COOKIE_BYTE1 99
#define DHCP_MAGIC_COOKIE_BYTE2 130
#define DHCP_MAGIC_COOKIE_BYTE3 83
#define DHCP_MAGIC_COOKIE_BYTE4 99
#include <packon.h>
typedef struct _OPTION {
BYTE OptionType;
BYTE OptionLength;
BYTE OptionValue[1];
} OPTION, *POPTION, *LPOPTION;
typedef struct _DHCP_MESSAGE {
BYTE Operation;
BYTE HardwareAddressType;
BYTE HardwareAddressLength;
BYTE HopCount;
DWORD TransactionID;
WORD SecondsSinceBoot;
WORD Reserved;
ULONG ClientIpAddress;
ULONG YourIpAddress;
ULONG BootstrapServerAddress;
ULONG RelayAgentIpAddress;
BYTE HardwareAddress[16];
BYTE HostName[ BOOT_SERVER_SIZE ];
BYTE BootFileName[BOOT_FILE_SIZE];
OPTION Option;
} DHCP_MESSAGE, *PDHCP_MESSAGE, *LPDHCP_MESSAGE;
#include <packoff.h>
LPOPTION
DhcpAppendOption(
LPOPTION Option,
BYTE OptionType,
PVOID OptionValue,
ULONG OptionLength,
LPBYTE OptionEnd
)
/*++
Routine Description:
This function writes a DHCP option to message buffer.
Arguments:
Option - A pointer to a message buffer.
OptionType - The option number to append.
OptionValue - A pointer to the option data.
OptionLength - The length, in bytes, of the option data.
OptionEnd - End of Option Buffer.
Return Value:
A pointer to the end of the appended option.
--*/
{
if (!Option)
{
return Option;
}
if ( OptionType == OPTION_END ) {
//
// we should alway have atleast one BYTE space in the buffer
// to append this option.
//
Option->OptionType = OPTION_END;
return( (LPOPTION) ((LPBYTE)(Option) + 1) );
}
if ( OptionType == OPTION_PAD ) {
//
// add this option only iff we have enough space in the buffer.
//
if(((LPBYTE)Option + 1) < (OptionEnd - 1) ) {
Option->OptionType = OPTION_PAD;
return( (LPOPTION) ((LPBYTE)(Option) + 1) );
}
return Option;
}
//
// add this option only iff we have enough space in the buffer.
//
if(((LPBYTE)Option + 2 + OptionLength) >= (OptionEnd - 1) ) {
return Option;
}
if( OptionLength <= 0xFF ) {
// simple option.. no need to use OPTION_MSFT_CONTINUED
Option->OptionType = OptionType;
Option->OptionLength = (BYTE)OptionLength;
memcpy( Option->OptionValue, OptionValue, OptionLength );
return( (LPOPTION) ((LPBYTE)(Option) + Option->OptionLength + 2) );
}
// option size is > 0xFF --> need to continue it using multiple ones..
// there are OptionLenght / 0xFF occurances using 0xFF+2 bytes + one
// using 2 + (OptionLength % 0xFF ) space..
// check to see if we have the space first..
if( 2 + (OptionLength%0xFF) + 0x101*(OptionLength/0xFF)
+ (LPBYTE)Option >= (OptionEnd - 1) ) {
return Option;
}
return Option;
}
LPBYTE
DhcpAppendMagicCookie(
LPBYTE Option,
LPBYTE OptionEnd
)
/*++
Routine Description:
This routine appends magic cookie to a DHCP message.
Arguments:
Option - A pointer to the place to append the magic cookie.
OptionEnd - End of Option buffer.
Return Value:
A pointer to the end of the appended cookie.
Note : The magic cookie is :
--------------------
| 99 | 130 | 83 | 99 |
--------------------
--*/
{
if( (Option + 4) < (OptionEnd - 1) ) {
*Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE1;
*Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE2;
*Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE3;
*Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE4;
}
return( Option );
}
LPOPTION
DhcpAppendClientIDOption(
LPOPTION Option,
BYTE ClientHWType,
LPBYTE ClientHWAddr,
BYTE ClientHWAddrLength,
LPBYTE OptionEnd
)
/*++
Routine Description:
This routine appends client ID option to a DHCP message.
History:
8/26/96 Frankbee Removed 16 byte limitation on the hardware
address
Arguments:
Option - A pointer to the place to append the option request.
ClientHWType - Client hardware type.
ClientHWAddr - Client hardware address
ClientHWAddrLength - Client hardware address length.
OptionEnd - End of Option buffer.
Return Value:
A pointer to the end of the newly appended option.
Note : The client ID option will look like as below in the message:
-----------------------------------------------------------------
| OpNum | Len | HWType | HWA1 | HWA2 | ..... | HWAn |
-----------------------------------------------------------------
--*/
{
struct _CLIENT_ID {
BYTE bHardwareAddressType;
BYTE pbHardwareAddress[1];
} *pClientID;
LPOPTION lpNewOption = 0;
pClientID = LocalAlloc(LMEM_FIXED, sizeof( struct _CLIENT_ID ) + ClientHWAddrLength);
//
// currently there is no way to indicate failure. simply return unmodified option
// list
//
if ( !pClientID )
return Option;
pClientID->bHardwareAddressType = ClientHWType;
memcpy( pClientID->pbHardwareAddress, ClientHWAddr, ClientHWAddrLength );
lpNewOption = DhcpAppendOption(
Option,
OPTION_CLIENT_ID,
(LPBYTE)pClientID,
(BYTE)(ClientHWAddrLength + sizeof(BYTE)),
OptionEnd );
LocalFree( pClientID );
return lpNewOption;
}
DWORD
OpenSocket(
SOCKET *Socket,
unsigned long IpAddress,
unsigned short Port
)
{
DWORD Error = 0;
SOCKET Sock;
DWORD OptValue = TRUE;
struct sockaddr_in SocketName;
//
// Create a socket
//
Sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( Sock == INVALID_SOCKET ) {
Error = WSAGetLastError();
goto error;
}
//
// Make the socket share-able
//
Error = setsockopt(
Sock,
SOL_SOCKET,
SO_REUSEADDR,
(char*)&OptValue,
sizeof(OptValue) );
if ( Error != ERROR_SUCCESS ) {
Error = WSAGetLastError();
goto error;
}
OptValue = TRUE;
Error = setsockopt(
Sock,
SOL_SOCKET,
SO_BROADCAST,
(char*)&OptValue,
sizeof(OptValue) );
if ( Error != ERROR_SUCCESS ) {
Error = WSAGetLastError();
goto error;
}
OptValue = SOCKET_RECEIVE_BUFFER_SIZE;
Error = setsockopt(
Sock,
SOL_SOCKET,
SO_RCVBUF,
(char*)&OptValue,
sizeof(OptValue) );
if ( Error != ERROR_SUCCESS ) {
Error = WSAGetLastError();
goto error;
}
SocketName.sin_family = PF_INET;
SocketName.sin_port = Port;
SocketName.sin_addr.s_addr = IpAddress;
RtlZeroMemory( SocketName.sin_zero, 8);
//
// Bind this socket to the DHCP server port
//
Error = bind(
Sock,
(struct sockaddr FAR *)&SocketName,
sizeof( SocketName )
);
if ( Error != ERROR_SUCCESS ) {
Error = WSAGetLastError();
goto error;
}
*Socket = Sock;
Error = ERROR_SUCCESS;
error:
if( Error != ERROR_SUCCESS ) {
//
// if we aren't successful, close the socket if it is opened.
//
if( Sock != INVALID_SOCKET ) {
closesocket( Sock );
}
}
return( Error );
}
DWORD
SendInformOrDiscover(
SOCKET Sock,
ULONG uClientIp,
BYTE ucMessageType,
PBYTE pMessageBuffer,
ULONG uMessageBufferSize,
ULONG DestIp,
PULONG puXid
)
{
DWORD Error = 0;
PDHCP_MESSAGE dhcpMessage = (PDHCP_MESSAGE)pMessageBuffer;
LPOPTION option = 0;
LPBYTE OptionEnd = 0;
BYTE value = 0;
ULONG uXid = 0;
LPSTR HostName = "detective";
ULONG uNumOfRequestOptions = 0;
UCHAR ucRequestOptions[256];
struct sockaddr_in socketName;
DWORD i;
uXid = (rand() & 0xff);
uXid <<= 8;
uXid |= (rand() & 0xff);
uXid <<= 8;
uXid |= (rand() & 0xff);
uXid <<= 8;
uXid |= (rand() & 0xff);
HardwareAddressLength = 6;
for (i = 0; i < HardwareAddressLength; i++) {
HardwareAddress[i] = (BYTE)(rand() & 0xff);
}
//
// prepare message.
//
RtlZeroMemory( dhcpMessage, uMessageBufferSize );
dhcpMessage->Operation = BOOT_REQUEST;
dhcpMessage->ClientIpAddress = uClientIp;
dhcpMessage->HardwareAddressType = 1;
dhcpMessage->SecondsSinceBoot = 60; // random value ??
dhcpMessage->Reserved = htons(DHCP_BROADCAST);
dhcpMessage->TransactionID = uXid;
*puXid = uXid;
memcpy(
dhcpMessage->HardwareAddress,
HardwareAddress,
HardwareAddressLength
);
dhcpMessage->HardwareAddressLength = (BYTE)HardwareAddressLength;
option = &dhcpMessage->Option;
OptionEnd = (LPBYTE)dhcpMessage + uMessageBufferSize;
//
// always add magic cookie first
//
option = (LPOPTION) DhcpAppendMagicCookie( (LPBYTE) option, OptionEnd );
value = ucMessageType;
option = DhcpAppendOption(
option,
OPTION_MESSAGE_TYPE,
&value,
1,
OptionEnd );
//
// Add client ID Option.
//
option = DhcpAppendClientIDOption(
option,
1,
HardwareAddress,
HardwareAddressLength,
OptionEnd );
//
// add Host name and comment options.
//
option = DhcpAppendOption(
option,
OPTION_HOST_NAME,
(LPBYTE)HostName,
(BYTE)((strlen(HostName) + 1) * sizeof(CHAR)),
OptionEnd );
//
// Add requested option
//
uNumOfRequestOptions = 0;
ucRequestOptions[uNumOfRequestOptions++] = 3;
option = DhcpAppendOption(
option,
OPTION_PARAMETER_REQUEST_LIST,
ucRequestOptions,
uNumOfRequestOptions,
OptionEnd
);
//
// Add END option.
//
option = DhcpAppendOption( option, OPTION_END, NULL, 0, OptionEnd );
//
// Initialize the outgoing address.
//
socketName.sin_family = PF_INET;
socketName.sin_port = htons( DHCP_SERVR_PORT );
socketName.sin_addr.s_addr = DestIp;
for ( i = 0; i < 8 ; i++ ) {
socketName.sin_zero[i] = 0;
}
Error = sendto(
Sock,
(char*)pMessageBuffer,
(int)(((PBYTE)option) - pMessageBuffer),
0,
(struct sockaddr *)&socketName,
sizeof( struct sockaddr )
);
if ( Error == SOCKET_ERROR ) {
Error = WSAGetLastError();
return( Error );
}
return( ERROR_SUCCESS );
}
DWORD
GetSpecifiedMessage(
SOCKET Sock,
PBYTE pMessageBuffer,
ULONG uMessageBufferSize,
ULONG uXid,
ULONG uTimeout,
ULONG * pServerIpAddress
)
{
DWORD Error = 0;
fd_set readSocketSet;
struct timeval timeout;
struct sockaddr socketName;
int socketNameSize = sizeof( socketName );
PDHCP_MESSAGE dhcpMessage = (PDHCP_MESSAGE)pMessageBuffer;
time_t start_time = 0, now = 0;
PUCHAR pucOption = NULL;
ULONG uBytesRemain = 0;
ULONG uOptionSize = 0;
BOOL bWellFormedPacket = FALSE;
ULONG uRemainingTime = 0;
BOOL continueLooping = TRUE;
BOOL continueInternalLoop = TRUE;
BOOL continueInternalLoop2 = FALSE;
BYTE ReqdCookie[] = {
(BYTE)DHCP_MAGIC_COOKIE_BYTE1,
(BYTE)DHCP_MAGIC_COOKIE_BYTE2,
(BYTE)DHCP_MAGIC_COOKIE_BYTE3,
(BYTE)DHCP_MAGIC_COOKIE_BYTE4
};
time(&now);
start_time = now;
*pServerIpAddress = 0;
while (continueLooping) {
time(&now);
uRemainingTime = uTimeout - (ULONG)(now - start_time);
FD_ZERO( &readSocketSet );
// FD_SET( Sock, &readSocketSet );
// Had to inline the macro because the compiler was complaining
// about the while(0) that was present in FD_SET
do {
u_int __i;
for (__i = 0; __i < ((fd_set FAR *)(&readSocketSet))->fd_count; __i++) {
if (((fd_set FAR *)(&readSocketSet))->fd_array[__i] == (Sock)) {
continueInternalLoop2 = FALSE;
break;
}
}
if (__i == ((fd_set FAR *)(&readSocketSet))->fd_count) {
if (((fd_set FAR *)(&readSocketSet))->fd_count < FD_SETSIZE) {
((fd_set FAR *)(&readSocketSet))->fd_array[__i] = (Sock);
((fd_set FAR *)(&readSocketSet))->fd_count++;
}
}
} while(continueInternalLoop2);
timeout.tv_sec = uRemainingTime;
timeout.tv_usec = 0;
Error = select(1, &readSocketSet, NULL, NULL, &timeout);
if (Error == 0) {
Error = ERROR_SEM_TIMEOUT;
continueLooping = FALSE;
break;
}
//
// receive available message.
//
Error = recvfrom(
Sock,
(char*)pMessageBuffer,
uMessageBufferSize,
0,
&socketName,
&socketNameSize
);
if ( Error == SOCKET_ERROR ) {
Error = WSAGetLastError();
//
// Don't bail out here.
//
continue;
}
//
// Some sanity check
//
if (Error < sizeof(DHCP_MESSAGE)) {
continue;
}
if (dhcpMessage->HardwareAddressLength != HardwareAddressLength) {
continue;
}
if (memcmp(dhcpMessage->HardwareAddress, HardwareAddress, HardwareAddressLength) != 0) {
continue;
}
if (dhcpMessage->TransactionID != uXid) {
continue;
}
//
// Make sure the option part is well-formed
// +--------------+----------+----------+-------------+
// | magic cookie | Option 1 | Length 1 | Option Data 1 ...
// +--------------+----------+----------+-------------+
//
pucOption = (PUCHAR)(&dhcpMessage->Option);
uBytesRemain = Error - (ULONG)(pucOption - ((PUCHAR)dhcpMessage));
if (uBytesRemain < sizeof(ReqdCookie)) {
continue;
}
if (0 != memcmp(pucOption, ReqdCookie, sizeof(ReqdCookie))) {
continue;
}
pucOption += sizeof(ReqdCookie);
uBytesRemain -= sizeof(ReqdCookie);
bWellFormedPacket = FALSE;
while (continueInternalLoop) {
//
// Make sure pucOption[0] is readable
//
if (uBytesRemain < 1) {
continueInternalLoop = FALSE;
break;
}
if (pucOption[0] == OPTION_PAD) {
pucOption++;
uBytesRemain--;
continue;
}
if (pucOption[0] == OPTION_END) {
//
// See the OPTION_END. This is a well-formed packet
//
bWellFormedPacket = TRUE;
continueInternalLoop = FALSE;
break;
}
//
// Make sure pucOption[1] is readable
//
if (uBytesRemain < 2) {
continueInternalLoop = FALSE;
break;
}
uOptionSize = pucOption[1];
//
// Make sure there is enough bytes for the option data
//
if (uBytesRemain < uOptionSize) {
continueInternalLoop = FALSE;
break;
}
if (pucOption[0] == OPTION_SERVER_IDENTIFIER) {
if (uOptionSize != sizeof(ULONG)) {
continueInternalLoop = FALSE;
break;
}
memcpy(pServerIpAddress, pucOption + 2, sizeof(ULONG));
}
//
// Skip the option head and option data and move
// to the next option
//
uBytesRemain -= uOptionSize + 2;
pucOption += uOptionSize + 2;
}
if (bWellFormedPacket) {
Error = ERROR_SUCCESS;
continueLooping = FALSE;
break;
}
}
return( Error );
}
// This will first attempt a DHCP_INFORM to detect a DHCP server.
// If that fails it will attempt a DHCP_DISCOVER.
DWORD
AnyDHCPServerRunning(
ULONG uClientIp,
ULONG * pServerIp
)
{
CHAR MessageBuffer[DHCP_RECV_MESSAGE_SIZE];
SOCKET Sock = INVALID_SOCKET;
ULONG DestIp = htonl(INADDR_BROADCAST);
DWORD dwError = ERROR_SUCCESS;
ULONG uXid = 0;
ULONG uMessageBufferSize = sizeof(MessageBuffer);
ULONG uTimeout = 4;
int retries = 0;
if (!pServerIp)
{
dwError = ERROR_INVALID_PARAMETER;
goto error;
}
dwError = OpenSocket(
&Sock,
uClientIp,
htons(DHCP_CLIENT_PORT)
);
if( dwError != ERROR_SUCCESS ) {
goto error;
}
for (retries = 0; retries < 3; retries++) {
//
// Try inform
//
dwError =
SendInformOrDiscover(
Sock,
uClientIp,
DHCP_INFORM_MESSAGE,
(PBYTE)MessageBuffer,
uMessageBufferSize,
DestIp,
&uXid);
if (dwError != ERROR_SUCCESS) {
goto error;
}
dwError = GetSpecifiedMessage(
Sock,
(PBYTE)MessageBuffer,
uMessageBufferSize,
uXid,
uTimeout,
pServerIp
);
if (dwError != ERROR_SEM_TIMEOUT && *pServerIp != htonl(INADDR_ANY) && *pServerIp != htonl(INADDR_BROADCAST)) {
break;
}
//
// Try discover
//
dwError =
SendInformOrDiscover(
Sock,
uClientIp,
DHCP_DISCOVER_MESSAGE,
(PBYTE)MessageBuffer,
uMessageBufferSize,
DestIp,
&uXid);
if (dwError != ERROR_SUCCESS) {
goto error;
}
dwError = GetSpecifiedMessage(
Sock,
(PBYTE)MessageBuffer,
uMessageBufferSize,
uXid,
uTimeout,
pServerIp
);
if (dwError != ERROR_SEM_TIMEOUT && *pServerIp != htonl(INADDR_ANY) && *pServerIp != htonl(INADDR_BROADCAST)) {
break;
}
}
error:
if (Sock != INVALID_SOCKET) {
closesocket(Sock);
}
return dwError;
}