1933 lines
49 KiB
C++
1933 lines
49 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998, Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dhcpmsg.c
|
||
|
||
Abstract:
|
||
|
||
This module contains declarations related to the DHCP allocator's
|
||
message-processing.
|
||
|
||
Author:
|
||
|
||
Abolade Gbadegesin (aboladeg) 6-Mar-1998
|
||
|
||
Revision History:
|
||
|
||
Raghu Gatta (rgatta) 15-Dec-2000
|
||
+ Changed manner in which the option DHCP_TAG_DOMAIN_NAME is
|
||
added in DhcpBuildReplyMessage().
|
||
+ Inform DNS component via DnsUpdate() in DhcpProcessRequestMessage().
|
||
|
||
Raghu Gatta (rgatta) 20-Apr-2001
|
||
+ IP/1394 support changes
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// EXTERNAL DECLARATIONS
|
||
//
|
||
extern PIP_DNS_PROXY_GLOBAL_INFO DnsGlobalInfo;
|
||
extern PWCHAR DnsICSDomainSuffix;
|
||
extern CRITICAL_SECTION DnsGlobalInfoLock;
|
||
|
||
//
|
||
// FORWARD DECLARATIONS
|
||
//
|
||
|
||
VOID
|
||
DhcpAppendOptionToMessage(
|
||
DHCP_OPTION UNALIGNED** Optionp,
|
||
UCHAR Tag,
|
||
UCHAR Length,
|
||
UCHAR Option[]
|
||
);
|
||
|
||
VOID
|
||
DhcpBuildReplyMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED** Option,
|
||
UCHAR MessageType,
|
||
BOOLEAN DynamicDns,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
);
|
||
|
||
ULONG
|
||
DhcpExtractOptionsFromMessage(
|
||
PDHCP_HEADER Headerp,
|
||
ULONG MessageSize,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
);
|
||
|
||
VOID
|
||
DnsUpdate(
|
||
CHAR *pszName,
|
||
ULONG len,
|
||
ULONG ulAddress
|
||
);
|
||
|
||
|
||
VOID
|
||
DhcpAppendOptionToMessage(
|
||
DHCP_OPTION UNALIGNED** Optionp,
|
||
UCHAR Tag,
|
||
UCHAR Length,
|
||
UCHAR Option[]
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to append an option to a DHCP message.
|
||
|
||
Arguments:
|
||
|
||
Optionp - on input, the point at which to append the option;
|
||
on output, the point at which to append the next option.
|
||
|
||
Tag - the option tag
|
||
|
||
Length - the option length
|
||
|
||
Option - the option's data
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
PROFILE("DhcpAppendOptionToMessage");
|
||
|
||
(*Optionp)->Tag = Tag;
|
||
|
||
if (!Length) {
|
||
*Optionp = (DHCP_OPTION UNALIGNED *)((PUCHAR)*Optionp + 1);
|
||
} else {
|
||
(*Optionp)->Length = Length;
|
||
CopyMemory((*Optionp)->Option, Option, Length);
|
||
*Optionp = (DHCP_OPTION UNALIGNED *)((PUCHAR)*Optionp + Length + 2);
|
||
}
|
||
|
||
} // DhcpAppendOptionToMessage
|
||
|
||
|
||
VOID
|
||
DhcpBuildReplyMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED** Option,
|
||
UCHAR MessageType,
|
||
BOOLEAN DynamicDns,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to construct the options portion
|
||
of a reply message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the reply will be sent
|
||
|
||
Bufferp - the buffer containing the reply
|
||
|
||
Option - the start of the options portion on input;
|
||
on output, the end of the message
|
||
|
||
MessageType - the type of message to be sent
|
||
|
||
DynamicDns - indicates whether to include the 'dynamic-dns' option.
|
||
|
||
OptionArray - options extracted from message
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Address;
|
||
ULONG SubnetMask;
|
||
ULONG i;
|
||
|
||
//
|
||
// Obtain the address and mask for the endpoint
|
||
//
|
||
|
||
Address = NhQueryAddressSocket(Bufferp->Socket);
|
||
SubnetMask = PtrToUlong(Bufferp->Context2);
|
||
|
||
if (MessageType == DHCP_MESSAGE_BOOTP) {
|
||
((PDHCP_HEADER)Bufferp->Buffer)->BootstrapServerAddress = Address;
|
||
} else {
|
||
|
||
//
|
||
// Always begin with the 'message-type' option.
|
||
//
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_MESSAGE_TYPE,
|
||
1,
|
||
&MessageType
|
||
);
|
||
|
||
//
|
||
// Provide our address as the server-identifier
|
||
//
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_SERVER_IDENTIFIER,
|
||
4,
|
||
(PUCHAR)&Address
|
||
);
|
||
}
|
||
|
||
if (MessageType != DHCP_MESSAGE_NAK) {
|
||
|
||
PCHAR DomainName;
|
||
ULONG dnSize;
|
||
ULONG LeaseTime;
|
||
UCHAR NbtNodeType = DHCP_NBT_NODE_TYPE_M;
|
||
ULONG RebindingTime;
|
||
ULONG RenewalTime;
|
||
|
||
EnterCriticalSection(&DhcpGlobalInfoLock);
|
||
LeaseTime = DhcpGlobalInfo->LeaseTime * 60;
|
||
LeaveCriticalSection(&DhcpGlobalInfoLock);
|
||
RebindingTime = (LeaseTime * 3) / 4;
|
||
RenewalTime = LeaseTime / 2;
|
||
if (RenewalTime > DHCP_MAXIMUM_RENEWAL_TIME) {
|
||
RenewalTime = DHCP_MAXIMUM_RENEWAL_TIME;
|
||
}
|
||
|
||
LeaseTime = htonl(LeaseTime);
|
||
RebindingTime = htonl(RebindingTime);
|
||
RenewalTime = htonl(RenewalTime);
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_SUBNET_MASK,
|
||
4,
|
||
(PUCHAR)&SubnetMask
|
||
);
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_ROUTER,
|
||
4,
|
||
(PUCHAR)&Address
|
||
);
|
||
|
||
////
|
||
//// RFC 2132 9.14 : server treats client identifier as an opaque object
|
||
//// append the client identifier if present in received message
|
||
////
|
||
//if (OptionArray[DhcpOptionClientIdentifier])
|
||
//{
|
||
// DhcpAppendOptionToMessage(
|
||
// Option,
|
||
// DHCP_TAG_CLIENT_IDENTIFIER,
|
||
// OptionArray[DhcpOptionClientIdentifier]->Length,
|
||
// (PUCHAR)OptionArray[DhcpOptionClientIdentifier]->Option
|
||
// );
|
||
//}
|
||
|
||
if (MessageType != DHCP_MESSAGE_BOOTP) {
|
||
|
||
//specify the DNS server in the message if DNS proxy is enabled
|
||
//or DNS server is running on local host
|
||
if (NhIsDnsProxyEnabled() || !NoLocalDns) {
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_DNS_SERVER,
|
||
4,
|
||
(PUCHAR)&Address
|
||
);
|
||
}
|
||
|
||
if (NhIsWinsProxyEnabled()) {
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_WINS_SERVER,
|
||
4,
|
||
(PUCHAR)&Address
|
||
);
|
||
}
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_RENEWAL_TIME,
|
||
4,
|
||
(PUCHAR)&RenewalTime
|
||
);
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_REBINDING_TIME,
|
||
4,
|
||
(PUCHAR)&RebindingTime
|
||
);
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_LEASE_TIME,
|
||
4,
|
||
(PUCHAR)&LeaseTime
|
||
);
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_NBT_NODE_TYPE,
|
||
1,
|
||
&NbtNodeType
|
||
);
|
||
|
||
if (DynamicDns) {
|
||
UCHAR DynamicDns[3] = { 0x03, 0, 0 };
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_DYNAMIC_DNS,
|
||
sizeof(DynamicDns),
|
||
DynamicDns
|
||
);
|
||
}
|
||
|
||
//if (NhpStopDnsEvent && DnsICSDomainSuffix)
|
||
if (DnsGlobalInfo && DnsICSDomainSuffix)
|
||
{
|
||
EnterCriticalSection(&DnsGlobalInfoLock);
|
||
|
||
dnSize = wcstombs(NULL, DnsICSDomainSuffix, 0);
|
||
DomainName = reinterpret_cast<PCHAR>(NH_ALLOCATE(dnSize + 1));
|
||
if (DomainName)
|
||
{
|
||
wcstombs(DomainName, DnsICSDomainSuffix, (dnSize + 1));
|
||
}
|
||
|
||
LeaveCriticalSection(&DnsGlobalInfoLock);
|
||
}
|
||
else
|
||
//
|
||
// at this point we have no DNS enabled
|
||
// so we default to old behaviour
|
||
//
|
||
{
|
||
DomainName = NhQuerySharedConnectionDomainName();
|
||
}
|
||
|
||
if (DomainName)
|
||
{
|
||
//
|
||
// We include the terminating nul in the domain name
|
||
// even though the RFC says we should not, because
|
||
// the DHCP server does so.
|
||
//
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_DOMAIN_NAME,
|
||
(UCHAR)(lstrlenA(DomainName) + 1),
|
||
(PUCHAR)DomainName
|
||
);
|
||
NH_FREE(DomainName);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
DhcpAppendOptionToMessage(
|
||
Option,
|
||
DHCP_TAG_END,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
} // DhcpBuildReplyMessage
|
||
|
||
|
||
ULONG
|
||
DhcpExtractOptionsFromMessage(
|
||
PDHCP_HEADER Headerp,
|
||
ULONG MessageSize,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to parse the options contained in a DHCP message.
|
||
Pointers to each option are stored in the given option array.
|
||
|
||
Arguments:
|
||
|
||
Headerp - the header of the DHCP message to be parsed
|
||
|
||
MessageSize - the size of the message to be parsed
|
||
|
||
OptionArray - receives the parsed options
|
||
|
||
Return Value:
|
||
|
||
ULONG - Win32 status code.
|
||
|
||
--*/
|
||
|
||
{
|
||
DHCP_OPTION UNALIGNED* Index;
|
||
DHCP_OPTION UNALIGNED* End;
|
||
|
||
PROFILE("DhcpExtractOptionsFromMessage");
|
||
|
||
//
|
||
// Initialize the option array to be empty
|
||
//
|
||
|
||
ZeroMemory(OptionArray, DhcpOptionCount * sizeof(PDHCP_OPTION));
|
||
|
||
//
|
||
// Check that the message is large enough to hold options
|
||
//
|
||
|
||
if (MessageSize < sizeof(DHCP_HEADER)) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpExtractOptionsFromMessage: message size %d too small",
|
||
MessageSize
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_MESSAGE_TOO_SMALL,
|
||
0,
|
||
""
|
||
);
|
||
return ERROR_INVALID_DATA;
|
||
}
|
||
|
||
//
|
||
// Ensure that the magic cookie is present; if not, there are no options.
|
||
//
|
||
|
||
if (MessageSize < (sizeof(DHCP_HEADER) + sizeof(DHCP_FOOTER)) ||
|
||
*(ULONG UNALIGNED*)Headerp->Footer[0].Cookie != DHCP_MAGIC_COOKIE) {
|
||
return NO_ERROR;
|
||
}
|
||
|
||
//
|
||
// Parse the message's options, if any
|
||
//
|
||
|
||
End = (PDHCP_OPTION)((PUCHAR)Headerp + MessageSize);
|
||
|
||
Index = (PDHCP_OPTION)&Headerp->Footer[1];
|
||
|
||
while (Index < End && Index->Tag != DHCP_TAG_END) {
|
||
|
||
if ((DHCP_TAG_PAD != Index->Tag) &&
|
||
(End < (PDHCP_OPTION)(Index->Option + Index->Length))) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpExtractOptionsFromMessage: option truncated at %d bytes",
|
||
MessageSize
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_INVALID_FORMAT,
|
||
0,
|
||
""
|
||
);
|
||
return ERROR_INVALID_DATA;
|
||
}
|
||
|
||
switch (Index->Tag) {
|
||
case DHCP_TAG_PAD:
|
||
NhTrace(TRACE_FLAG_DHCP, "Pad");
|
||
break;
|
||
case DHCP_TAG_CLIENT_IDENTIFIER:
|
||
NhTrace(TRACE_FLAG_DHCP, "ClientIdentifier");
|
||
OptionArray[DhcpOptionClientIdentifier] = Index; break;
|
||
case DHCP_TAG_MESSAGE_TYPE:
|
||
NhTrace(TRACE_FLAG_DHCP, "MessageType");
|
||
if (Index->Length < 1) { break; }
|
||
OptionArray[DhcpOptionMessageType] = Index; break;
|
||
case DHCP_TAG_REQUESTED_ADDRESS:
|
||
NhTrace(TRACE_FLAG_DHCP, "RequestedAddress");
|
||
if (Index->Length < 4) { break; }
|
||
OptionArray[DhcpOptionRequestedAddress] = Index; break;
|
||
case DHCP_TAG_PARAMETER_REQUEST_LIST:
|
||
NhTrace(TRACE_FLAG_DHCP, "ParameterRequestList");
|
||
if (Index->Length < 1) { break; }
|
||
OptionArray[DhcpOptionParameterRequestList] = Index; break;
|
||
case DHCP_TAG_ERROR_MESSAGE:
|
||
NhTrace(TRACE_FLAG_DHCP, "ErrorMessage");
|
||
if (Index->Length < 1) { break; }
|
||
OptionArray[DhcpOptionErrorMessage] = Index; break;
|
||
case DHCP_TAG_DYNAMIC_DNS:
|
||
NhTrace(TRACE_FLAG_DHCP, "DynamicDns");
|
||
if (Index->Length < 1) { break; }
|
||
OptionArray[DhcpOptionDynamicDns] = Index; break;
|
||
case DHCP_TAG_HOST_NAME:
|
||
NhTrace(TRACE_FLAG_DHCP, "HostName");
|
||
if (Index->Length < 1) { break; }
|
||
OptionArray[DhcpOptionHostName] = Index; break;
|
||
}
|
||
|
||
if (DHCP_TAG_PAD != Index->Tag) {
|
||
Index = (PDHCP_OPTION)(Index->Option + Index->Length);
|
||
}
|
||
else {
|
||
Index = (PDHCP_OPTION)((PUCHAR)Index + 1);
|
||
}
|
||
}
|
||
|
||
if (Index->Tag != DHCP_TAG_END) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpExtractOptionsFromMessage: message truncated to %d bytes",
|
||
MessageSize
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_INVALID_FORMAT,
|
||
0,
|
||
""
|
||
);
|
||
return ERROR_INVALID_DATA;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
|
||
} // DhcpExtractOptionsFromMessage
|
||
|
||
|
||
VOID
|
||
DhcpProcessBootpMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to process a received BOOTP message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the message was received
|
||
|
||
Bufferp - the buffer containing the message
|
||
|
||
OptionArray - options extracted from the message
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG AssignedAddress;
|
||
ULONG Error;
|
||
UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
|
||
ULONG ExistingAddressLength;
|
||
PDHCP_HEADER Headerp;
|
||
ULONG MessageLength;
|
||
PDHCP_HEADER Offerp;
|
||
DHCP_OPTION UNALIGNED* Option;
|
||
ULONG ReplyAddress;
|
||
USHORT ReplyPort;
|
||
PNH_BUFFER Replyp;
|
||
ULONG ScopeNetwork;
|
||
ULONG ScopeMask;
|
||
BOOLEAN bIsLocal = FALSE;
|
||
|
||
PROFILE("DhcpProcessBootpMessage");
|
||
|
||
ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
if (!Headerp->ClientAddress) {
|
||
AssignedAddress = 0;
|
||
} else {
|
||
|
||
//
|
||
// Validate the address requested by the client
|
||
//
|
||
|
||
AssignedAddress = Headerp->ClientAddress;
|
||
|
||
EnterCriticalSection(&DhcpGlobalInfoLock);
|
||
ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
|
||
ScopeMask = DhcpGlobalInfo->ScopeMask;
|
||
LeaveCriticalSection(&DhcpGlobalInfoLock);
|
||
|
||
if ((AssignedAddress & ~ScopeMask) == 0 ||
|
||
(AssignedAddress & ~ScopeMask) == ~ScopeMask ||
|
||
(AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
|
||
|
||
//
|
||
// The client is on the wrong subnet, or has an all-zeros
|
||
// or all-ones address on the subnet.
|
||
// Select a different address for the client.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
} else if (!DhcpIsUniqueAddress(
|
||
AssignedAddress,
|
||
&bIsLocal,
|
||
ExistingAddress,
|
||
&ExistingAddressLength
|
||
) &&
|
||
(bIsLocal ||
|
||
((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
|
||
Headerp->HardwareAddressLength) && // if address length is zero we wont compare
|
||
(ExistingAddressLength < Headerp->HardwareAddressLength ||
|
||
memcmp(
|
||
ExistingAddress,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
))))) {
|
||
|
||
//
|
||
// Someone has the requested address, and it's not the requestor.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
|
||
} else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
|
||
|
||
//
|
||
// The address is reserved for someone else.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
}
|
||
}
|
||
|
||
if (!AssignedAddress &&
|
||
!(AssignedAddress =
|
||
DhcpAcquireUniqueAddress(
|
||
NULL,
|
||
0,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
))) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessBootpMessage: address-allocation failed"
|
||
);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Acquire a buffer for the reply we will send back
|
||
//
|
||
|
||
Replyp = NhAcquireBuffer();
|
||
|
||
if (!Replyp) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessBootpMessage: buffer-allocation failed"
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
|
||
0,
|
||
"%d",
|
||
sizeof(NH_BUFFER)
|
||
);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Pick up fields from the original buffer;
|
||
// the routines setting up the reply will attempt to read these,
|
||
// so they are set to the values from the original buffer.
|
||
//
|
||
|
||
Replyp->Socket = Bufferp->Socket;
|
||
Replyp->ReadAddress = Bufferp->ReadAddress;
|
||
Replyp->WriteAddress = Bufferp->WriteAddress;
|
||
Replyp->Context = Bufferp->Context;
|
||
Replyp->Context2 = Bufferp->Context2;
|
||
|
||
Offerp = (PDHCP_HEADER)Replyp->Buffer;
|
||
|
||
//
|
||
// Copy the original header
|
||
//
|
||
|
||
*Offerp = *Headerp;
|
||
|
||
//
|
||
// Set up the offer-header fields
|
||
//
|
||
|
||
Offerp->Operation = BOOTP_OPERATION_REPLY;
|
||
Offerp->AssignedAddress = AssignedAddress;
|
||
Offerp->ServerHostName[0] = 0;
|
||
Offerp->BootFile[0] = 0;
|
||
Offerp->SecondsSinceBoot = 0;
|
||
*(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
|
||
|
||
//
|
||
// Fill in options
|
||
//
|
||
|
||
Option = (PDHCP_OPTION)&Offerp->Footer[1];
|
||
|
||
DhcpBuildReplyMessage(
|
||
Interfacep,
|
||
Replyp,
|
||
&Option,
|
||
DHCP_MESSAGE_BOOTP,
|
||
FALSE,
|
||
OptionArray
|
||
);
|
||
|
||
//
|
||
// Send the offer to the BOOTP client
|
||
//
|
||
|
||
EnterCriticalSection(&DhcpInterfaceLock);
|
||
if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
NhReleaseBuffer(Replyp);
|
||
} else {
|
||
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
|
||
if (Headerp->RelayAgentAddress) {
|
||
ReplyAddress = Headerp->RelayAgentAddress;
|
||
ReplyPort = DHCP_PORT_SERVER;
|
||
} else {
|
||
ReplyAddress = INADDR_BROADCAST;
|
||
ReplyPort = DHCP_PORT_CLIENT;
|
||
}
|
||
|
||
MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
|
||
if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
|
||
MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
|
||
}
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Bufferp->Socket,
|
||
ReplyAddress,
|
||
ReplyPort,
|
||
Replyp,
|
||
MessageLength,
|
||
DhcpWriteCompletionRoutine,
|
||
Interfacep,
|
||
Bufferp->Context2
|
||
);
|
||
|
||
if (!Error) {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.BootpOffersSent)
|
||
);
|
||
} else {
|
||
DHCP_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhReleaseBuffer(Replyp);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessBootpMessage: error %d sending reply",
|
||
Error
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_REPLY_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
} // DhcpProcessBootpMessage
|
||
|
||
|
||
VOID
|
||
DhcpProcessDiscoverMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to process a received DHCPDISCOVER message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the discover was received
|
||
|
||
Bufferp - the buffer containing the message
|
||
|
||
OptionArray - options extracted from the message
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG AssignedAddress;
|
||
ULONG Error;
|
||
UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
|
||
ULONG ExistingAddressLength;
|
||
PDHCP_HEADER Headerp;
|
||
ULONG MessageLength;
|
||
PDHCP_HEADER Offerp;
|
||
DHCP_OPTION UNALIGNED* Option;
|
||
ULONG ReplyAddress;
|
||
USHORT ReplyPort;
|
||
PNH_BUFFER Replyp;
|
||
ULONG ScopeNetwork;
|
||
ULONG ScopeMask;
|
||
BOOLEAN bIsLocal = FALSE;
|
||
|
||
PROFILE("DhcpProcessDiscoverMessage");
|
||
|
||
ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
//
|
||
// See if the client is renewing or requesting
|
||
//
|
||
|
||
if (!OptionArray[DhcpOptionRequestedAddress]) {
|
||
|
||
AssignedAddress = 0;
|
||
} else {
|
||
|
||
//
|
||
// Validate the address requested by the client
|
||
//
|
||
|
||
AssignedAddress =
|
||
*(ULONG UNALIGNED*)OptionArray[DhcpOptionRequestedAddress]->Option;
|
||
|
||
EnterCriticalSection(&DhcpGlobalInfoLock);
|
||
ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
|
||
ScopeMask = DhcpGlobalInfo->ScopeMask;
|
||
LeaveCriticalSection(&DhcpGlobalInfoLock);
|
||
|
||
if ((AssignedAddress & ~ScopeMask) == 0 ||
|
||
(AssignedAddress & ~ScopeMask) == ~ScopeMask ||
|
||
(AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
|
||
|
||
//
|
||
// The client is on the wrong subnet, or has an all-zeroes
|
||
// or all-ones address on the subnet.
|
||
// Select a different address for the client.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
} else if (!DhcpIsUniqueAddress(
|
||
AssignedAddress,
|
||
&bIsLocal,
|
||
ExistingAddress,
|
||
&ExistingAddressLength
|
||
) &&
|
||
(bIsLocal ||
|
||
((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
|
||
Headerp->HardwareAddressLength) && // if address length is zero we wont compare
|
||
(ExistingAddressLength < Headerp->HardwareAddressLength ||
|
||
memcmp(
|
||
ExistingAddress,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
))))) {
|
||
|
||
//
|
||
// Someone has the requested address, and it's not the requestor.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
} else if (OptionArray[DhcpOptionHostName]) {
|
||
if (DhcpIsReservedAddress(
|
||
AssignedAddress,
|
||
reinterpret_cast<PCHAR>(
|
||
OptionArray[DhcpOptionHostName]->Option
|
||
),
|
||
OptionArray[DhcpOptionHostName]->Length
|
||
)) {
|
||
|
||
//
|
||
// The address is reserved for someone else,
|
||
// or the client has a different address reserved.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
}
|
||
} else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
|
||
|
||
//
|
||
// The address is reserved for someone else.
|
||
//
|
||
|
||
AssignedAddress = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Generate an address for the client if necessary
|
||
//
|
||
|
||
if (!AssignedAddress) {
|
||
if (!OptionArray[DhcpOptionHostName]) {
|
||
AssignedAddress =
|
||
DhcpAcquireUniqueAddress(
|
||
NULL,
|
||
0,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
);
|
||
} else {
|
||
AssignedAddress =
|
||
DhcpAcquireUniqueAddress(
|
||
reinterpret_cast<PCHAR>(
|
||
OptionArray[DhcpOptionHostName]->Option
|
||
),
|
||
OptionArray[DhcpOptionHostName]->Length,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
);
|
||
}
|
||
if (!AssignedAddress) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessDiscoverMessage: address-allocation failed"
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Acquire a buffer for the offer we will send back
|
||
//
|
||
|
||
Replyp = NhAcquireBuffer();
|
||
|
||
if (!Replyp) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessDiscoverMessage: buffer-allocation failed"
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
|
||
0,
|
||
"%d",
|
||
sizeof(NH_BUFFER)
|
||
);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Pick up fields from the original message
|
||
// the routines setting up the reply will attempt to read these,
|
||
// so they are set to the values from the original buffer.
|
||
//
|
||
|
||
Replyp->Socket = Bufferp->Socket;
|
||
Replyp->ReadAddress = Bufferp->ReadAddress;
|
||
Replyp->WriteAddress = Bufferp->WriteAddress;
|
||
Replyp->Context = Bufferp->Context;
|
||
Replyp->Context2 = Bufferp->Context2;
|
||
|
||
Offerp = (PDHCP_HEADER)Replyp->Buffer;
|
||
|
||
//
|
||
// Copy the original discover header
|
||
//
|
||
|
||
*Offerp = *Headerp;
|
||
|
||
//
|
||
// IP/1394 support (RFC 2855)
|
||
//
|
||
if ((IP1394_HTYPE == Offerp->HardwareAddressType) &&
|
||
(0 == Offerp->HardwareAddressLength))
|
||
{
|
||
//
|
||
// MUST set client hardware address to zero
|
||
//
|
||
ZeroMemory(Offerp->HardwareAddress, sizeof(Offerp->HardwareAddress));
|
||
}
|
||
|
||
//
|
||
// Set up the offer-header fieldds
|
||
//
|
||
|
||
Offerp->Operation = BOOTP_OPERATION_REPLY;
|
||
Offerp->AssignedAddress = AssignedAddress;
|
||
Offerp->ServerHostName[0] = 0;
|
||
Offerp->BootFile[0] = 0;
|
||
Offerp->SecondsSinceBoot = 0;
|
||
*(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
|
||
|
||
//
|
||
// Fill in options
|
||
//
|
||
|
||
Option = (PDHCP_OPTION)&Offerp->Footer[1];
|
||
|
||
DhcpBuildReplyMessage(
|
||
Interfacep,
|
||
Replyp,
|
||
&Option,
|
||
DHCP_MESSAGE_OFFER,
|
||
(BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
|
||
OptionArray
|
||
);
|
||
|
||
//
|
||
// Send the offer to the client
|
||
//
|
||
|
||
EnterCriticalSection(&DhcpInterfaceLock);
|
||
if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
NhReleaseBuffer(Replyp);
|
||
} else {
|
||
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
|
||
if (Headerp->RelayAgentAddress) {
|
||
ReplyAddress = Headerp->RelayAgentAddress;
|
||
ReplyPort = DHCP_PORT_SERVER;
|
||
} else {
|
||
ReplyAddress = INADDR_BROADCAST;
|
||
ReplyPort = DHCP_PORT_CLIENT;
|
||
}
|
||
|
||
MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
|
||
if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
|
||
MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
|
||
}
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Bufferp->Socket,
|
||
ReplyAddress,
|
||
ReplyPort,
|
||
Replyp,
|
||
MessageLength,
|
||
DhcpWriteCompletionRoutine,
|
||
Interfacep,
|
||
Bufferp->Context2
|
||
);
|
||
|
||
if (!Error) {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.OffersSent)
|
||
);
|
||
} else {
|
||
DHCP_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhReleaseBuffer(Replyp);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessDiscoverMessage: error %d sending reply",
|
||
Error
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_REPLY_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
} // DhcpProcessDiscoverMessage
|
||
|
||
|
||
|
||
VOID
|
||
DhcpProcessInformMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to process a received DHCPINFORM message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the inform was received
|
||
|
||
Bufferp - the buffer containing the message
|
||
|
||
OptionArray - options extracted from the message
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDHCP_HEADER Ackp;
|
||
ULONG Error;
|
||
PDHCP_HEADER Headerp;
|
||
ULONG MessageLength;
|
||
DHCP_OPTION UNALIGNED* Option;
|
||
ULONG ReplyAddress;
|
||
USHORT ReplyPort;
|
||
PNH_BUFFER Replyp;
|
||
|
||
PROFILE("DhcpProcessInformMessage");
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
//
|
||
// Acquire a buffer for the ack we will send back
|
||
//
|
||
|
||
Replyp = NhAcquireBuffer();
|
||
|
||
if (!Replyp) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessInformMessage: buffer-allocation failed"
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
|
||
0,
|
||
"%d",
|
||
sizeof(NH_BUFFER)
|
||
);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Pick up fields from the original message
|
||
// the routines setting up the reply will attempt to read these,
|
||
// so they are set to the values from the original buffer.
|
||
//
|
||
|
||
Replyp->Socket = Bufferp->Socket;
|
||
Replyp->ReadAddress = Bufferp->ReadAddress;
|
||
Replyp->WriteAddress = Bufferp->WriteAddress;
|
||
Replyp->Context = Bufferp->Context;
|
||
Replyp->Context2 = Bufferp->Context2;
|
||
|
||
Ackp = (PDHCP_HEADER)Replyp->Buffer;
|
||
|
||
//
|
||
// Copy the original header
|
||
//
|
||
|
||
*Ackp = *Headerp;
|
||
|
||
//
|
||
// IP/1394 support (RFC 2855)
|
||
//
|
||
if ((IP1394_HTYPE == Ackp->HardwareAddressType) &&
|
||
(0 == Ackp->HardwareAddressLength))
|
||
{
|
||
//
|
||
// MUST set client hardware address to zero
|
||
//
|
||
ZeroMemory(Ackp->HardwareAddress, sizeof(Ackp->HardwareAddress));
|
||
}
|
||
|
||
//
|
||
// Set up the ack-header fieldds
|
||
//
|
||
|
||
Ackp->Operation = BOOTP_OPERATION_REPLY;
|
||
Ackp->AssignedAddress = 0;
|
||
Ackp->ServerHostName[0] = 0;
|
||
Ackp->BootFile[0] = 0;
|
||
Ackp->SecondsSinceBoot = 0;
|
||
*(ULONG UNALIGNED *)Ackp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
|
||
|
||
//
|
||
// Fill in options
|
||
//
|
||
|
||
Option = (PDHCP_OPTION)&Ackp->Footer[1];
|
||
|
||
DhcpBuildReplyMessage(
|
||
Interfacep,
|
||
Replyp,
|
||
&Option,
|
||
DHCP_MESSAGE_ACK,
|
||
(BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
|
||
OptionArray
|
||
);
|
||
|
||
//
|
||
// Send the offer to the client
|
||
//
|
||
|
||
EnterCriticalSection(&DhcpInterfaceLock);
|
||
if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
NhReleaseBuffer(Replyp);
|
||
} else {
|
||
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
|
||
if (Headerp->RelayAgentAddress) {
|
||
ReplyAddress = Headerp->RelayAgentAddress;
|
||
ReplyPort = DHCP_PORT_SERVER;
|
||
} else {
|
||
ReplyAddress = INADDR_BROADCAST;
|
||
ReplyPort = DHCP_PORT_CLIENT;
|
||
}
|
||
|
||
MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
|
||
if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
|
||
MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
|
||
}
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Bufferp->Socket,
|
||
ReplyAddress,
|
||
ReplyPort,
|
||
Replyp,
|
||
MessageLength,
|
||
DhcpWriteCompletionRoutine,
|
||
Interfacep,
|
||
Bufferp->Context2
|
||
);
|
||
|
||
if (!Error) {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.AcksSent)
|
||
);
|
||
} else {
|
||
DHCP_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhReleaseBuffer(Replyp);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessInformMessage: error %d sending reply",
|
||
Error
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_REPLY_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
} // DhcpProcessInformMessage
|
||
|
||
|
||
VOID
|
||
DhcpProcessMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to process a DHCP client message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the request was received
|
||
|
||
Bufferp - the buffer containing the message received
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked internally with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Error;
|
||
PDHCP_HEADER Headerp;
|
||
UCHAR MessageType;
|
||
PDHCP_OPTION OptionArray[DhcpOptionCount];
|
||
|
||
PROFILE("DhcpProcessMessage");
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
#if DBG
|
||
NhDump(
|
||
TRACE_FLAG_DHCP,
|
||
Bufferp->Buffer,
|
||
Bufferp->BytesTransferred,
|
||
1
|
||
);
|
||
#endif
|
||
|
||
//
|
||
// Extract pointers to each option in the message
|
||
//
|
||
|
||
Error =
|
||
DhcpExtractOptionsFromMessage(
|
||
Headerp,
|
||
Bufferp->BytesTransferred,
|
||
OptionArray
|
||
);
|
||
|
||
if (Error) {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.MessagesIgnored)
|
||
);
|
||
}
|
||
else
|
||
//
|
||
// Look for the message-type;
|
||
// This distinguishes BOOTP from DHCP clients.
|
||
//
|
||
if (!OptionArray[DhcpOptionMessageType]) {
|
||
DhcpProcessBootpMessage(
|
||
Interfacep,
|
||
Bufferp,
|
||
OptionArray
|
||
);
|
||
} else if (Headerp->HardwareAddressLength <=
|
||
sizeof(Headerp->HardwareAddress) &&
|
||
DhcpIsLocalHardwareAddress(
|
||
Headerp->HardwareAddress, Headerp->HardwareAddressLength)) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: ignoring message, from self"
|
||
);
|
||
} else switch(MessageType = OptionArray[DhcpOptionMessageType]->Option[0]) {
|
||
case DHCP_MESSAGE_DISCOVER: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.DiscoversReceived)
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: received DISCOVER message"
|
||
);
|
||
DhcpProcessDiscoverMessage(
|
||
Interfacep,
|
||
Bufferp,
|
||
OptionArray
|
||
);
|
||
break;
|
||
}
|
||
case DHCP_MESSAGE_REQUEST: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.RequestsReceived)
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: received REQUEST message"
|
||
);
|
||
DhcpProcessRequestMessage(
|
||
Interfacep,
|
||
Bufferp,
|
||
OptionArray
|
||
);
|
||
break;
|
||
}
|
||
case DHCP_MESSAGE_INFORM: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.InformsReceived)
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: received INFORM message"
|
||
);
|
||
DhcpProcessInformMessage(
|
||
Interfacep,
|
||
Bufferp,
|
||
OptionArray
|
||
);
|
||
break;
|
||
}
|
||
case DHCP_MESSAGE_DECLINE: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.DeclinesReceived)
|
||
);
|
||
// log message
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: received DECLINE message"
|
||
);
|
||
break;
|
||
}
|
||
case DHCP_MESSAGE_RELEASE: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.ReleasesReceived)
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: received RELEASE message"
|
||
);
|
||
break;
|
||
}
|
||
default: {
|
||
InterlockedIncrement(
|
||
reinterpret_cast<LPLONG>(&DhcpStatistics.MessagesIgnored)
|
||
);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: message type %d invalid",
|
||
MessageType
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_INVALID_DHCP_MESSAGE_TYPE,
|
||
0,
|
||
"%d",
|
||
MessageType
|
||
);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Post the buffer for another read
|
||
//
|
||
|
||
EnterCriticalSection(&DhcpInterfaceLock);
|
||
if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
NhReleaseBuffer(Bufferp);
|
||
} else {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
Error =
|
||
NhReadDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Bufferp->Socket,
|
||
Bufferp,
|
||
DhcpReadCompletionRoutine,
|
||
Bufferp->Context,
|
||
Bufferp->Context2
|
||
);
|
||
if (Error) {
|
||
ACQUIRE_LOCK(Interfacep);
|
||
DhcpDeferReadInterface(Interfacep, Bufferp->Socket);
|
||
RELEASE_LOCK(Interfacep);
|
||
DHCP_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessMessage: error %d reposting read",
|
||
Error
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_RECEIVE_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
NhReleaseBuffer(Bufferp);
|
||
}
|
||
}
|
||
|
||
} // DhcpProcessMessage
|
||
|
||
|
||
VOID
|
||
DhcpProcessRequestMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PNH_BUFFER Bufferp,
|
||
DHCP_OPTION UNALIGNED* OptionArray[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to process a request message.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the request was received
|
||
|
||
Bufferp - the buffer containing the message received
|
||
|
||
OptionArray - options extracted from the message
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
Environment:
|
||
|
||
Invoked internally with 'Interfacep' referenced by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG AssignedAddress = 0;
|
||
ULONG Error;
|
||
UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
|
||
ULONG ExistingAddressLength;
|
||
PDHCP_HEADER Headerp;
|
||
ULONG MessageLength;
|
||
PDHCP_HEADER Offerp;
|
||
DHCP_OPTION UNALIGNED* Option;
|
||
ULONG ReplyAddress;
|
||
USHORT ReplyPort;
|
||
PNH_BUFFER Replyp;
|
||
UCHAR ReplyType = DHCP_MESSAGE_ACK;
|
||
ULONG ScopeNetwork;
|
||
ULONG ScopeMask;
|
||
BOOLEAN bIsLocal = FALSE;
|
||
|
||
PROFILE("DhcpProcessRequestMessage");
|
||
|
||
ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
//
|
||
// Validate the address requested by the client
|
||
//
|
||
|
||
if (!Headerp->ClientAddress && !OptionArray[DhcpOptionRequestedAddress]) {
|
||
|
||
//
|
||
// The client left out the address being requested
|
||
//
|
||
|
||
ReplyType = DHCP_MESSAGE_NAK;
|
||
} else {
|
||
|
||
//
|
||
// Try to see if the address is in use.
|
||
//
|
||
|
||
AssignedAddress =
|
||
Headerp->ClientAddress
|
||
? Headerp->ClientAddress
|
||
: *(ULONG UNALIGNED*)
|
||
OptionArray[DhcpOptionRequestedAddress]->Option;
|
||
|
||
EnterCriticalSection(&DhcpGlobalInfoLock);
|
||
ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
|
||
ScopeMask = DhcpGlobalInfo->ScopeMask;
|
||
LeaveCriticalSection(&DhcpGlobalInfoLock);
|
||
|
||
if ((AssignedAddress & ~ScopeMask) == 0 ||
|
||
(AssignedAddress & ~ScopeMask) == ~ScopeMask ||
|
||
(AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
|
||
|
||
//
|
||
// The client is on the wrong subnet, or has an all-ones
|
||
// or all-zeroes address.
|
||
//
|
||
|
||
ReplyType = DHCP_MESSAGE_NAK;
|
||
|
||
} else if (!DhcpIsUniqueAddress(
|
||
AssignedAddress,
|
||
&bIsLocal,
|
||
ExistingAddress,
|
||
&ExistingAddressLength
|
||
) &&
|
||
(bIsLocal ||
|
||
((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
|
||
Headerp->HardwareAddressLength) && // if address length is zero we wont compare
|
||
(ExistingAddressLength < Headerp->HardwareAddressLength ||
|
||
memcmp(
|
||
ExistingAddress,
|
||
Headerp->HardwareAddress,
|
||
Headerp->HardwareAddressLength
|
||
))))) {
|
||
|
||
//
|
||
// Someone has the requested address, and it's not the requestor.
|
||
//
|
||
|
||
ReplyType = DHCP_MESSAGE_NAK;
|
||
|
||
} else if (OptionArray[DhcpOptionHostName]) {
|
||
if (DhcpIsReservedAddress(
|
||
AssignedAddress,
|
||
reinterpret_cast<PCHAR>(
|
||
OptionArray[DhcpOptionHostName]->Option
|
||
),
|
||
OptionArray[DhcpOptionHostName]->Length
|
||
)) {
|
||
|
||
//
|
||
// The address is reserved for someone else,
|
||
// or the client has a different address reserved.
|
||
//
|
||
|
||
ReplyType = DHCP_MESSAGE_NAK;
|
||
}
|
||
} else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
|
||
|
||
//
|
||
// The address is reserved for someone else.
|
||
//
|
||
|
||
ReplyType = DHCP_MESSAGE_NAK;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Acquire a buffer for the reply we will send back
|
||
//
|
||
|
||
Replyp = NhAcquireBuffer();
|
||
|
||
if (!Replyp) {
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessRequestMessage: buffer-allocation failed"
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
|
||
0,
|
||
"%d",
|
||
sizeof(NH_BUFFER)
|
||
);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Pick up fields to be used in the reply-buffer
|
||
// the routines setting up the reply will attempt to read these,
|
||
// so they are set to the values from the original buffer.
|
||
//
|
||
|
||
Replyp->Socket = Bufferp->Socket;
|
||
Replyp->ReadAddress = Bufferp->ReadAddress;
|
||
Replyp->WriteAddress = Bufferp->WriteAddress;
|
||
Replyp->Context = Bufferp->Context;
|
||
Replyp->Context2 = Bufferp->Context2;
|
||
|
||
Offerp = (PDHCP_HEADER)Replyp->Buffer;
|
||
|
||
//
|
||
// Copy the original discover header
|
||
//
|
||
|
||
*Offerp = *Headerp;
|
||
|
||
//
|
||
// IP/1394 support (RFC 2855)
|
||
//
|
||
if ((IP1394_HTYPE == Offerp->HardwareAddressType) &&
|
||
(0 == Offerp->HardwareAddressLength))
|
||
{
|
||
//
|
||
// MUST set client hardware address to zero
|
||
//
|
||
ZeroMemory(Offerp->HardwareAddress, sizeof(Offerp->HardwareAddress));
|
||
}
|
||
|
||
//
|
||
// Set up the offer-header fieldds
|
||
//
|
||
|
||
Offerp->Operation = BOOTP_OPERATION_REPLY;
|
||
Offerp->AssignedAddress = AssignedAddress;
|
||
Offerp->ServerHostName[0] = 0;
|
||
Offerp->BootFile[0] = 0;
|
||
Offerp->SecondsSinceBoot = 0;
|
||
*(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
|
||
|
||
//
|
||
// Fill in options
|
||
//
|
||
|
||
Option = (PDHCP_OPTION)&Offerp->Footer[1];
|
||
|
||
DhcpBuildReplyMessage(
|
||
Interfacep,
|
||
Replyp,
|
||
&Option,
|
||
ReplyType,
|
||
(BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
|
||
OptionArray
|
||
);
|
||
|
||
//
|
||
// NEW LOGIC HERE => tied to DNS
|
||
//
|
||
if (DHCP_MESSAGE_ACK == ReplyType)
|
||
{
|
||
//
|
||
// We perform the equivalent of Dynamic DNS here
|
||
// by informing the DNS component that this client exists
|
||
//
|
||
if (OptionArray[DhcpOptionHostName])
|
||
{
|
||
//
|
||
// check if DNS component is active
|
||
//
|
||
if (REFERENCE_DNS())
|
||
{
|
||
DnsUpdate(
|
||
reinterpret_cast<PCHAR>(OptionArray[DhcpOptionHostName]->Option),
|
||
(ULONG) OptionArray[DhcpOptionHostName]->Length,
|
||
AssignedAddress
|
||
);
|
||
|
||
DEREFERENCE_DNS();
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send the reply to the client
|
||
//
|
||
|
||
EnterCriticalSection(&DhcpInterfaceLock);
|
||
if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
NhReleaseBuffer(Replyp);
|
||
} else {
|
||
|
||
LeaveCriticalSection(&DhcpInterfaceLock);
|
||
|
||
if (Headerp->RelayAgentAddress) {
|
||
ReplyAddress = Headerp->RelayAgentAddress;
|
||
ReplyPort = DHCP_PORT_SERVER;
|
||
} else {
|
||
ReplyAddress = INADDR_BROADCAST;
|
||
ReplyPort = DHCP_PORT_CLIENT;
|
||
}
|
||
|
||
MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
|
||
if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
|
||
MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
|
||
}
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Bufferp->Socket,
|
||
ReplyAddress,
|
||
ReplyPort,
|
||
Replyp,
|
||
MessageLength,
|
||
DhcpWriteCompletionRoutine,
|
||
Interfacep,
|
||
Bufferp->Context2
|
||
);
|
||
|
||
if (!Error) {
|
||
InterlockedIncrement(
|
||
(ReplyType == DHCP_MESSAGE_ACK)
|
||
? reinterpret_cast<LPLONG>(&DhcpStatistics.AcksSent)
|
||
: reinterpret_cast<LPLONG>(&DhcpStatistics.NaksSent)
|
||
);
|
||
} else {
|
||
DHCP_DEREFERENCE_INTERFACE(Interfacep);
|
||
NhReleaseBuffer(Replyp);
|
||
NhTrace(
|
||
TRACE_FLAG_DHCP,
|
||
"DhcpProcessRequestMessage: error %d sending reply",
|
||
Error
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_REPLY_FAILED,
|
||
Error,
|
||
"%I",
|
||
NhQueryAddressSocket(Bufferp->Socket)
|
||
);
|
||
}
|
||
}
|
||
|
||
} // DhcpProcessRequestMessage
|
||
|
||
|
||
ULONG
|
||
DhcpWriteClientRequestMessage(
|
||
PDHCP_INTERFACE Interfacep,
|
||
PDHCP_BINDING Binding
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to check for the existence of a DHCP server
|
||
on the given interface and address. It generates a BOOTP request
|
||
on a socket bound to the DHCP client port.
|
||
|
||
Arguments:
|
||
|
||
Interfacep - the interface on which the client request is to be sent
|
||
|
||
Binding - the binding on which the request is to be sent
|
||
|
||
Return Value:
|
||
|
||
ULONG - status code.
|
||
|
||
Environment:
|
||
|
||
Invoked with 'Interfacep' locked and with a reference made to 'Interfacep'
|
||
for the send which occurs here.
|
||
If the routine fails, it is the caller's responsibility to release
|
||
the reference.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNH_BUFFER Bufferp;
|
||
ULONG Error;
|
||
PDHCP_HEADER Headerp;
|
||
SOCKET Socket;
|
||
|
||
PROFILE("DhcpWriteClientRequestMessage");
|
||
|
||
//
|
||
// Create a socket using the given address
|
||
//
|
||
|
||
Error =
|
||
NhCreateDatagramSocket(
|
||
Binding->Address,
|
||
DHCP_PORT_CLIENT,
|
||
&Binding->ClientSocket
|
||
);
|
||
|
||
if (Error) {
|
||
NhTrace(
|
||
TRACE_FLAG_IF,
|
||
"DhcpWriteClientRequestMessage: error %d creating socket for %s",
|
||
Error,
|
||
INET_NTOA(Binding->Address)
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE,
|
||
Error,
|
||
"%I",
|
||
Binding->Address
|
||
);
|
||
return Error;
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer for the BOOTP request
|
||
//
|
||
|
||
Bufferp = NhAcquireBuffer();
|
||
if (!Bufferp) {
|
||
NhDeleteDatagramSocket(Binding->ClientSocket);
|
||
Binding->ClientSocket = INVALID_SOCKET;
|
||
NhTrace(
|
||
TRACE_FLAG_IF,
|
||
"DhcpWriteClientRequestMessage: error allocating buffer for %s",
|
||
INET_NTOA(Binding->Address)
|
||
);
|
||
NhErrorLog(
|
||
IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
|
||
0,
|
||
"%d",
|
||
sizeof(NH_BUFFER)
|
||
);
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
//
|
||
// Initialize the BOOTP request
|
||
//
|
||
|
||
Headerp = (PDHCP_HEADER)Bufferp->Buffer;
|
||
|
||
ZeroMemory(Headerp, sizeof(*Headerp));
|
||
|
||
Headerp->Operation = BOOTP_OPERATION_REQUEST;
|
||
Headerp->HardwareAddressType = 1;
|
||
Headerp->HardwareAddressLength = 6;
|
||
Headerp->TransactionId = DHCP_DETECTION_TRANSACTION_ID;
|
||
Headerp->SecondsSinceBoot = 10;
|
||
Headerp->Flags |= BOOTP_FLAG_BROADCAST;
|
||
Headerp->ClientAddress = Binding->Address;
|
||
Headerp->HardwareAddress[1] = 0xab;
|
||
*(PULONG)(Headerp->Footer[0].Cookie) = DHCP_MAGIC_COOKIE;
|
||
*(PUCHAR)(Headerp->Footer + 1) = DHCP_TAG_END;
|
||
|
||
//
|
||
// Send the BOOTP request on the socket
|
||
//
|
||
|
||
Error =
|
||
NhWriteDatagramSocket(
|
||
&DhcpComponentReference,
|
||
Binding->ClientSocket,
|
||
INADDR_BROADCAST,
|
||
DHCP_PORT_SERVER,
|
||
Bufferp,
|
||
sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH,
|
||
DhcpWriteClientRequestCompletionRoutine,
|
||
(PVOID)Interfacep,
|
||
UlongToPtr(Binding->Address)
|
||
);
|
||
|
||
if (Error) {
|
||
NhReleaseBuffer(Bufferp);
|
||
NhDeleteDatagramSocket(Binding->ClientSocket);
|
||
Binding->ClientSocket = INVALID_SOCKET;
|
||
NhTrace(
|
||
TRACE_FLAG_IF,
|
||
"DhcpWriteClientRequestMessage: error %d writing request for %s",
|
||
Error,
|
||
INET_NTOA(Binding->Address)
|
||
);
|
||
NhWarningLog(
|
||
IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE,
|
||
Error,
|
||
"%I",
|
||
Binding->Address
|
||
);
|
||
return Error;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
|
||
} // DhcpWriteClientRequestMessage
|
||
|
||
|