mirror of https://github.com/tongzx/nt5src
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.
1932 lines
49 KiB
1932 lines
49 KiB
/*++
|
|
|
|
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
|
|
|
|
|