Source code of Windows XP (NT5)
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

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. dhcpmsg.c
  5. Abstract:
  6. This module contains declarations related to the DHCP allocator's
  7. message-processing.
  8. Author:
  9. Abolade Gbadegesin (aboladeg) 6-Mar-1998
  10. Revision History:
  11. Raghu Gatta (rgatta) 15-Dec-2000
  12. + Changed manner in which the option DHCP_TAG_DOMAIN_NAME is
  13. added in DhcpBuildReplyMessage().
  14. + Inform DNS component via DnsUpdate() in DhcpProcessRequestMessage().
  15. Raghu Gatta (rgatta) 20-Apr-2001
  16. + IP/1394 support changes
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. //
  21. // EXTERNAL DECLARATIONS
  22. //
  23. extern PIP_DNS_PROXY_GLOBAL_INFO DnsGlobalInfo;
  24. extern PWCHAR DnsICSDomainSuffix;
  25. extern CRITICAL_SECTION DnsGlobalInfoLock;
  26. //
  27. // FORWARD DECLARATIONS
  28. //
  29. VOID
  30. DhcpAppendOptionToMessage(
  31. DHCP_OPTION UNALIGNED** Optionp,
  32. UCHAR Tag,
  33. UCHAR Length,
  34. UCHAR Option[]
  35. );
  36. VOID
  37. DhcpBuildReplyMessage(
  38. PDHCP_INTERFACE Interfacep,
  39. PNH_BUFFER Bufferp,
  40. DHCP_OPTION UNALIGNED** Option,
  41. UCHAR MessageType,
  42. BOOLEAN DynamicDns,
  43. DHCP_OPTION UNALIGNED* OptionArray[]
  44. );
  45. ULONG
  46. DhcpExtractOptionsFromMessage(
  47. PDHCP_HEADER Headerp,
  48. ULONG MessageSize,
  49. DHCP_OPTION UNALIGNED* OptionArray[]
  50. );
  51. VOID
  52. DnsUpdate(
  53. CHAR *pszName,
  54. ULONG len,
  55. ULONG ulAddress
  56. );
  57. VOID
  58. DhcpAppendOptionToMessage(
  59. DHCP_OPTION UNALIGNED** Optionp,
  60. UCHAR Tag,
  61. UCHAR Length,
  62. UCHAR Option[]
  63. )
  64. /*++
  65. Routine Description:
  66. This routine is invoked to append an option to a DHCP message.
  67. Arguments:
  68. Optionp - on input, the point at which to append the option;
  69. on output, the point at which to append the next option.
  70. Tag - the option tag
  71. Length - the option length
  72. Option - the option's data
  73. Return Value:
  74. none.
  75. --*/
  76. {
  77. PROFILE("DhcpAppendOptionToMessage");
  78. (*Optionp)->Tag = Tag;
  79. if (!Length) {
  80. *Optionp = (DHCP_OPTION UNALIGNED *)((PUCHAR)*Optionp + 1);
  81. } else {
  82. (*Optionp)->Length = Length;
  83. CopyMemory((*Optionp)->Option, Option, Length);
  84. *Optionp = (DHCP_OPTION UNALIGNED *)((PUCHAR)*Optionp + Length + 2);
  85. }
  86. } // DhcpAppendOptionToMessage
  87. VOID
  88. DhcpBuildReplyMessage(
  89. PDHCP_INTERFACE Interfacep,
  90. PNH_BUFFER Bufferp,
  91. DHCP_OPTION UNALIGNED** Option,
  92. UCHAR MessageType,
  93. BOOLEAN DynamicDns,
  94. DHCP_OPTION UNALIGNED* OptionArray[]
  95. )
  96. /*++
  97. Routine Description:
  98. This routine is called to construct the options portion
  99. of a reply message.
  100. Arguments:
  101. Interfacep - the interface on which the reply will be sent
  102. Bufferp - the buffer containing the reply
  103. Option - the start of the options portion on input;
  104. on output, the end of the message
  105. MessageType - the type of message to be sent
  106. DynamicDns - indicates whether to include the 'dynamic-dns' option.
  107. OptionArray - options extracted from message
  108. Return Value:
  109. none.
  110. Environment:
  111. Invoked with 'Interfacep' referenced by the caller.
  112. --*/
  113. {
  114. ULONG Address;
  115. ULONG SubnetMask;
  116. ULONG i;
  117. //
  118. // Obtain the address and mask for the endpoint
  119. //
  120. Address = NhQueryAddressSocket(Bufferp->Socket);
  121. SubnetMask = PtrToUlong(Bufferp->Context2);
  122. if (MessageType == DHCP_MESSAGE_BOOTP) {
  123. ((PDHCP_HEADER)Bufferp->Buffer)->BootstrapServerAddress = Address;
  124. } else {
  125. //
  126. // Always begin with the 'message-type' option.
  127. //
  128. DhcpAppendOptionToMessage(
  129. Option,
  130. DHCP_TAG_MESSAGE_TYPE,
  131. 1,
  132. &MessageType
  133. );
  134. //
  135. // Provide our address as the server-identifier
  136. //
  137. DhcpAppendOptionToMessage(
  138. Option,
  139. DHCP_TAG_SERVER_IDENTIFIER,
  140. 4,
  141. (PUCHAR)&Address
  142. );
  143. }
  144. if (MessageType != DHCP_MESSAGE_NAK) {
  145. PCHAR DomainName;
  146. ULONG dnSize;
  147. ULONG LeaseTime;
  148. UCHAR NbtNodeType = DHCP_NBT_NODE_TYPE_M;
  149. ULONG RebindingTime;
  150. ULONG RenewalTime;
  151. EnterCriticalSection(&DhcpGlobalInfoLock);
  152. LeaseTime = DhcpGlobalInfo->LeaseTime * 60;
  153. LeaveCriticalSection(&DhcpGlobalInfoLock);
  154. RebindingTime = (LeaseTime * 3) / 4;
  155. RenewalTime = LeaseTime / 2;
  156. if (RenewalTime > DHCP_MAXIMUM_RENEWAL_TIME) {
  157. RenewalTime = DHCP_MAXIMUM_RENEWAL_TIME;
  158. }
  159. LeaseTime = htonl(LeaseTime);
  160. RebindingTime = htonl(RebindingTime);
  161. RenewalTime = htonl(RenewalTime);
  162. DhcpAppendOptionToMessage(
  163. Option,
  164. DHCP_TAG_SUBNET_MASK,
  165. 4,
  166. (PUCHAR)&SubnetMask
  167. );
  168. DhcpAppendOptionToMessage(
  169. Option,
  170. DHCP_TAG_ROUTER,
  171. 4,
  172. (PUCHAR)&Address
  173. );
  174. ////
  175. //// RFC 2132 9.14 : server treats client identifier as an opaque object
  176. //// append the client identifier if present in received message
  177. ////
  178. //if (OptionArray[DhcpOptionClientIdentifier])
  179. //{
  180. // DhcpAppendOptionToMessage(
  181. // Option,
  182. // DHCP_TAG_CLIENT_IDENTIFIER,
  183. // OptionArray[DhcpOptionClientIdentifier]->Length,
  184. // (PUCHAR)OptionArray[DhcpOptionClientIdentifier]->Option
  185. // );
  186. //}
  187. if (MessageType != DHCP_MESSAGE_BOOTP) {
  188. //specify the DNS server in the message if DNS proxy is enabled
  189. //or DNS server is running on local host
  190. if (NhIsDnsProxyEnabled() || !NoLocalDns) {
  191. DhcpAppendOptionToMessage(
  192. Option,
  193. DHCP_TAG_DNS_SERVER,
  194. 4,
  195. (PUCHAR)&Address
  196. );
  197. }
  198. if (NhIsWinsProxyEnabled()) {
  199. DhcpAppendOptionToMessage(
  200. Option,
  201. DHCP_TAG_WINS_SERVER,
  202. 4,
  203. (PUCHAR)&Address
  204. );
  205. }
  206. DhcpAppendOptionToMessage(
  207. Option,
  208. DHCP_TAG_RENEWAL_TIME,
  209. 4,
  210. (PUCHAR)&RenewalTime
  211. );
  212. DhcpAppendOptionToMessage(
  213. Option,
  214. DHCP_TAG_REBINDING_TIME,
  215. 4,
  216. (PUCHAR)&RebindingTime
  217. );
  218. DhcpAppendOptionToMessage(
  219. Option,
  220. DHCP_TAG_LEASE_TIME,
  221. 4,
  222. (PUCHAR)&LeaseTime
  223. );
  224. DhcpAppendOptionToMessage(
  225. Option,
  226. DHCP_TAG_NBT_NODE_TYPE,
  227. 1,
  228. &NbtNodeType
  229. );
  230. if (DynamicDns) {
  231. UCHAR DynamicDns[3] = { 0x03, 0, 0 };
  232. DhcpAppendOptionToMessage(
  233. Option,
  234. DHCP_TAG_DYNAMIC_DNS,
  235. sizeof(DynamicDns),
  236. DynamicDns
  237. );
  238. }
  239. //if (NhpStopDnsEvent && DnsICSDomainSuffix)
  240. if (DnsGlobalInfo && DnsICSDomainSuffix)
  241. {
  242. EnterCriticalSection(&DnsGlobalInfoLock);
  243. dnSize = wcstombs(NULL, DnsICSDomainSuffix, 0);
  244. DomainName = reinterpret_cast<PCHAR>(NH_ALLOCATE(dnSize + 1));
  245. if (DomainName)
  246. {
  247. wcstombs(DomainName, DnsICSDomainSuffix, (dnSize + 1));
  248. }
  249. LeaveCriticalSection(&DnsGlobalInfoLock);
  250. }
  251. else
  252. //
  253. // at this point we have no DNS enabled
  254. // so we default to old behaviour
  255. //
  256. {
  257. DomainName = NhQuerySharedConnectionDomainName();
  258. }
  259. if (DomainName)
  260. {
  261. //
  262. // We include the terminating nul in the domain name
  263. // even though the RFC says we should not, because
  264. // the DHCP server does so.
  265. //
  266. DhcpAppendOptionToMessage(
  267. Option,
  268. DHCP_TAG_DOMAIN_NAME,
  269. (UCHAR)(lstrlenA(DomainName) + 1),
  270. (PUCHAR)DomainName
  271. );
  272. NH_FREE(DomainName);
  273. }
  274. }
  275. }
  276. DhcpAppendOptionToMessage(
  277. Option,
  278. DHCP_TAG_END,
  279. 0,
  280. NULL
  281. );
  282. } // DhcpBuildReplyMessage
  283. ULONG
  284. DhcpExtractOptionsFromMessage(
  285. PDHCP_HEADER Headerp,
  286. ULONG MessageSize,
  287. DHCP_OPTION UNALIGNED* OptionArray[]
  288. )
  289. /*++
  290. Routine Description:
  291. This routine is invoked to parse the options contained in a DHCP message.
  292. Pointers to each option are stored in the given option array.
  293. Arguments:
  294. Headerp - the header of the DHCP message to be parsed
  295. MessageSize - the size of the message to be parsed
  296. OptionArray - receives the parsed options
  297. Return Value:
  298. ULONG - Win32 status code.
  299. --*/
  300. {
  301. DHCP_OPTION UNALIGNED* Index;
  302. DHCP_OPTION UNALIGNED* End;
  303. PROFILE("DhcpExtractOptionsFromMessage");
  304. //
  305. // Initialize the option array to be empty
  306. //
  307. ZeroMemory(OptionArray, DhcpOptionCount * sizeof(PDHCP_OPTION));
  308. //
  309. // Check that the message is large enough to hold options
  310. //
  311. if (MessageSize < sizeof(DHCP_HEADER)) {
  312. NhTrace(
  313. TRACE_FLAG_DHCP,
  314. "DhcpExtractOptionsFromMessage: message size %d too small",
  315. MessageSize
  316. );
  317. NhWarningLog(
  318. IP_AUTO_DHCP_LOG_MESSAGE_TOO_SMALL,
  319. 0,
  320. ""
  321. );
  322. return ERROR_INVALID_DATA;
  323. }
  324. //
  325. // Ensure that the magic cookie is present; if not, there are no options.
  326. //
  327. if (MessageSize < (sizeof(DHCP_HEADER) + sizeof(DHCP_FOOTER)) ||
  328. *(ULONG UNALIGNED*)Headerp->Footer[0].Cookie != DHCP_MAGIC_COOKIE) {
  329. return NO_ERROR;
  330. }
  331. //
  332. // Parse the message's options, if any
  333. //
  334. End = (PDHCP_OPTION)((PUCHAR)Headerp + MessageSize);
  335. Index = (PDHCP_OPTION)&Headerp->Footer[1];
  336. while (Index < End && Index->Tag != DHCP_TAG_END) {
  337. if ((DHCP_TAG_PAD != Index->Tag) &&
  338. (End < (PDHCP_OPTION)(Index->Option + Index->Length))) {
  339. NhTrace(
  340. TRACE_FLAG_DHCP,
  341. "DhcpExtractOptionsFromMessage: option truncated at %d bytes",
  342. MessageSize
  343. );
  344. NhWarningLog(
  345. IP_AUTO_DHCP_LOG_INVALID_FORMAT,
  346. 0,
  347. ""
  348. );
  349. return ERROR_INVALID_DATA;
  350. }
  351. switch (Index->Tag) {
  352. case DHCP_TAG_PAD:
  353. NhTrace(TRACE_FLAG_DHCP, "Pad");
  354. break;
  355. case DHCP_TAG_CLIENT_IDENTIFIER:
  356. NhTrace(TRACE_FLAG_DHCP, "ClientIdentifier");
  357. OptionArray[DhcpOptionClientIdentifier] = Index; break;
  358. case DHCP_TAG_MESSAGE_TYPE:
  359. NhTrace(TRACE_FLAG_DHCP, "MessageType");
  360. if (Index->Length < 1) { break; }
  361. OptionArray[DhcpOptionMessageType] = Index; break;
  362. case DHCP_TAG_REQUESTED_ADDRESS:
  363. NhTrace(TRACE_FLAG_DHCP, "RequestedAddress");
  364. if (Index->Length < 4) { break; }
  365. OptionArray[DhcpOptionRequestedAddress] = Index; break;
  366. case DHCP_TAG_PARAMETER_REQUEST_LIST:
  367. NhTrace(TRACE_FLAG_DHCP, "ParameterRequestList");
  368. if (Index->Length < 1) { break; }
  369. OptionArray[DhcpOptionParameterRequestList] = Index; break;
  370. case DHCP_TAG_ERROR_MESSAGE:
  371. NhTrace(TRACE_FLAG_DHCP, "ErrorMessage");
  372. if (Index->Length < 1) { break; }
  373. OptionArray[DhcpOptionErrorMessage] = Index; break;
  374. case DHCP_TAG_DYNAMIC_DNS:
  375. NhTrace(TRACE_FLAG_DHCP, "DynamicDns");
  376. if (Index->Length < 1) { break; }
  377. OptionArray[DhcpOptionDynamicDns] = Index; break;
  378. case DHCP_TAG_HOST_NAME:
  379. NhTrace(TRACE_FLAG_DHCP, "HostName");
  380. if (Index->Length < 1) { break; }
  381. OptionArray[DhcpOptionHostName] = Index; break;
  382. }
  383. if (DHCP_TAG_PAD != Index->Tag) {
  384. Index = (PDHCP_OPTION)(Index->Option + Index->Length);
  385. }
  386. else {
  387. Index = (PDHCP_OPTION)((PUCHAR)Index + 1);
  388. }
  389. }
  390. if (Index->Tag != DHCP_TAG_END) {
  391. NhTrace(
  392. TRACE_FLAG_DHCP,
  393. "DhcpExtractOptionsFromMessage: message truncated to %d bytes",
  394. MessageSize
  395. );
  396. NhWarningLog(
  397. IP_AUTO_DHCP_LOG_INVALID_FORMAT,
  398. 0,
  399. ""
  400. );
  401. return ERROR_INVALID_DATA;
  402. }
  403. return NO_ERROR;
  404. } // DhcpExtractOptionsFromMessage
  405. VOID
  406. DhcpProcessBootpMessage(
  407. PDHCP_INTERFACE Interfacep,
  408. PNH_BUFFER Bufferp,
  409. DHCP_OPTION UNALIGNED* OptionArray[]
  410. )
  411. /*++
  412. Routine Description:
  413. This routine is called to process a received BOOTP message.
  414. Arguments:
  415. Interfacep - the interface on which the message was received
  416. Bufferp - the buffer containing the message
  417. OptionArray - options extracted from the message
  418. Return Value:
  419. none.
  420. Environment:
  421. Invoked with 'Interfacep' referenced by the caller.
  422. --*/
  423. {
  424. ULONG AssignedAddress;
  425. ULONG Error;
  426. UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
  427. ULONG ExistingAddressLength;
  428. PDHCP_HEADER Headerp;
  429. ULONG MessageLength;
  430. PDHCP_HEADER Offerp;
  431. DHCP_OPTION UNALIGNED* Option;
  432. ULONG ReplyAddress;
  433. USHORT ReplyPort;
  434. PNH_BUFFER Replyp;
  435. ULONG ScopeNetwork;
  436. ULONG ScopeMask;
  437. BOOLEAN bIsLocal = FALSE;
  438. PROFILE("DhcpProcessBootpMessage");
  439. ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
  440. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  441. if (!Headerp->ClientAddress) {
  442. AssignedAddress = 0;
  443. } else {
  444. //
  445. // Validate the address requested by the client
  446. //
  447. AssignedAddress = Headerp->ClientAddress;
  448. EnterCriticalSection(&DhcpGlobalInfoLock);
  449. ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
  450. ScopeMask = DhcpGlobalInfo->ScopeMask;
  451. LeaveCriticalSection(&DhcpGlobalInfoLock);
  452. if ((AssignedAddress & ~ScopeMask) == 0 ||
  453. (AssignedAddress & ~ScopeMask) == ~ScopeMask ||
  454. (AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
  455. //
  456. // The client is on the wrong subnet, or has an all-zeros
  457. // or all-ones address on the subnet.
  458. // Select a different address for the client.
  459. //
  460. AssignedAddress = 0;
  461. } else if (!DhcpIsUniqueAddress(
  462. AssignedAddress,
  463. &bIsLocal,
  464. ExistingAddress,
  465. &ExistingAddressLength
  466. ) &&
  467. (bIsLocal ||
  468. ((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
  469. Headerp->HardwareAddressLength) && // if address length is zero we wont compare
  470. (ExistingAddressLength < Headerp->HardwareAddressLength ||
  471. memcmp(
  472. ExistingAddress,
  473. Headerp->HardwareAddress,
  474. Headerp->HardwareAddressLength
  475. ))))) {
  476. //
  477. // Someone has the requested address, and it's not the requestor.
  478. //
  479. AssignedAddress = 0;
  480. } else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
  481. //
  482. // The address is reserved for someone else.
  483. //
  484. AssignedAddress = 0;
  485. }
  486. }
  487. if (!AssignedAddress &&
  488. !(AssignedAddress =
  489. DhcpAcquireUniqueAddress(
  490. NULL,
  491. 0,
  492. Headerp->HardwareAddress,
  493. Headerp->HardwareAddressLength
  494. ))) {
  495. NhTrace(
  496. TRACE_FLAG_DHCP,
  497. "DhcpProcessBootpMessage: address-allocation failed"
  498. );
  499. return;
  500. }
  501. //
  502. // Acquire a buffer for the reply we will send back
  503. //
  504. Replyp = NhAcquireBuffer();
  505. if (!Replyp) {
  506. NhTrace(
  507. TRACE_FLAG_DHCP,
  508. "DhcpProcessBootpMessage: buffer-allocation failed"
  509. );
  510. NhErrorLog(
  511. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  512. 0,
  513. "%d",
  514. sizeof(NH_BUFFER)
  515. );
  516. return;
  517. }
  518. //
  519. // Pick up fields from the original buffer;
  520. // the routines setting up the reply will attempt to read these,
  521. // so they are set to the values from the original buffer.
  522. //
  523. Replyp->Socket = Bufferp->Socket;
  524. Replyp->ReadAddress = Bufferp->ReadAddress;
  525. Replyp->WriteAddress = Bufferp->WriteAddress;
  526. Replyp->Context = Bufferp->Context;
  527. Replyp->Context2 = Bufferp->Context2;
  528. Offerp = (PDHCP_HEADER)Replyp->Buffer;
  529. //
  530. // Copy the original header
  531. //
  532. *Offerp = *Headerp;
  533. //
  534. // Set up the offer-header fields
  535. //
  536. Offerp->Operation = BOOTP_OPERATION_REPLY;
  537. Offerp->AssignedAddress = AssignedAddress;
  538. Offerp->ServerHostName[0] = 0;
  539. Offerp->BootFile[0] = 0;
  540. Offerp->SecondsSinceBoot = 0;
  541. *(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
  542. //
  543. // Fill in options
  544. //
  545. Option = (PDHCP_OPTION)&Offerp->Footer[1];
  546. DhcpBuildReplyMessage(
  547. Interfacep,
  548. Replyp,
  549. &Option,
  550. DHCP_MESSAGE_BOOTP,
  551. FALSE,
  552. OptionArray
  553. );
  554. //
  555. // Send the offer to the BOOTP client
  556. //
  557. EnterCriticalSection(&DhcpInterfaceLock);
  558. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  559. LeaveCriticalSection(&DhcpInterfaceLock);
  560. NhReleaseBuffer(Replyp);
  561. } else {
  562. LeaveCriticalSection(&DhcpInterfaceLock);
  563. if (Headerp->RelayAgentAddress) {
  564. ReplyAddress = Headerp->RelayAgentAddress;
  565. ReplyPort = DHCP_PORT_SERVER;
  566. } else {
  567. ReplyAddress = INADDR_BROADCAST;
  568. ReplyPort = DHCP_PORT_CLIENT;
  569. }
  570. MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
  571. if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
  572. MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
  573. }
  574. Error =
  575. NhWriteDatagramSocket(
  576. &DhcpComponentReference,
  577. Bufferp->Socket,
  578. ReplyAddress,
  579. ReplyPort,
  580. Replyp,
  581. MessageLength,
  582. DhcpWriteCompletionRoutine,
  583. Interfacep,
  584. Bufferp->Context2
  585. );
  586. if (!Error) {
  587. InterlockedIncrement(
  588. reinterpret_cast<LPLONG>(&DhcpStatistics.BootpOffersSent)
  589. );
  590. } else {
  591. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  592. NhReleaseBuffer(Replyp);
  593. NhTrace(
  594. TRACE_FLAG_DHCP,
  595. "DhcpProcessBootpMessage: error %d sending reply",
  596. Error
  597. );
  598. NhErrorLog(
  599. IP_AUTO_DHCP_LOG_REPLY_FAILED,
  600. Error,
  601. "%I",
  602. NhQueryAddressSocket(Bufferp->Socket)
  603. );
  604. }
  605. }
  606. } // DhcpProcessBootpMessage
  607. VOID
  608. DhcpProcessDiscoverMessage(
  609. PDHCP_INTERFACE Interfacep,
  610. PNH_BUFFER Bufferp,
  611. DHCP_OPTION UNALIGNED* OptionArray[]
  612. )
  613. /*++
  614. Routine Description:
  615. This routine is called to process a received DHCPDISCOVER message.
  616. Arguments:
  617. Interfacep - the interface on which the discover was received
  618. Bufferp - the buffer containing the message
  619. OptionArray - options extracted from the message
  620. Return Value:
  621. none.
  622. Environment:
  623. Invoked with 'Interfacep' referenced by the caller.
  624. --*/
  625. {
  626. ULONG AssignedAddress;
  627. ULONG Error;
  628. UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
  629. ULONG ExistingAddressLength;
  630. PDHCP_HEADER Headerp;
  631. ULONG MessageLength;
  632. PDHCP_HEADER Offerp;
  633. DHCP_OPTION UNALIGNED* Option;
  634. ULONG ReplyAddress;
  635. USHORT ReplyPort;
  636. PNH_BUFFER Replyp;
  637. ULONG ScopeNetwork;
  638. ULONG ScopeMask;
  639. BOOLEAN bIsLocal = FALSE;
  640. PROFILE("DhcpProcessDiscoverMessage");
  641. ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
  642. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  643. //
  644. // See if the client is renewing or requesting
  645. //
  646. if (!OptionArray[DhcpOptionRequestedAddress]) {
  647. AssignedAddress = 0;
  648. } else {
  649. //
  650. // Validate the address requested by the client
  651. //
  652. AssignedAddress =
  653. *(ULONG UNALIGNED*)OptionArray[DhcpOptionRequestedAddress]->Option;
  654. EnterCriticalSection(&DhcpGlobalInfoLock);
  655. ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
  656. ScopeMask = DhcpGlobalInfo->ScopeMask;
  657. LeaveCriticalSection(&DhcpGlobalInfoLock);
  658. if ((AssignedAddress & ~ScopeMask) == 0 ||
  659. (AssignedAddress & ~ScopeMask) == ~ScopeMask ||
  660. (AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
  661. //
  662. // The client is on the wrong subnet, or has an all-zeroes
  663. // or all-ones address on the subnet.
  664. // Select a different address for the client.
  665. //
  666. AssignedAddress = 0;
  667. } else if (!DhcpIsUniqueAddress(
  668. AssignedAddress,
  669. &bIsLocal,
  670. ExistingAddress,
  671. &ExistingAddressLength
  672. ) &&
  673. (bIsLocal ||
  674. ((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
  675. Headerp->HardwareAddressLength) && // if address length is zero we wont compare
  676. (ExistingAddressLength < Headerp->HardwareAddressLength ||
  677. memcmp(
  678. ExistingAddress,
  679. Headerp->HardwareAddress,
  680. Headerp->HardwareAddressLength
  681. ))))) {
  682. //
  683. // Someone has the requested address, and it's not the requestor.
  684. //
  685. AssignedAddress = 0;
  686. } else if (OptionArray[DhcpOptionHostName]) {
  687. if (DhcpIsReservedAddress(
  688. AssignedAddress,
  689. reinterpret_cast<PCHAR>(
  690. OptionArray[DhcpOptionHostName]->Option
  691. ),
  692. OptionArray[DhcpOptionHostName]->Length
  693. )) {
  694. //
  695. // The address is reserved for someone else,
  696. // or the client has a different address reserved.
  697. //
  698. AssignedAddress = 0;
  699. }
  700. } else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
  701. //
  702. // The address is reserved for someone else.
  703. //
  704. AssignedAddress = 0;
  705. }
  706. }
  707. //
  708. // Generate an address for the client if necessary
  709. //
  710. if (!AssignedAddress) {
  711. if (!OptionArray[DhcpOptionHostName]) {
  712. AssignedAddress =
  713. DhcpAcquireUniqueAddress(
  714. NULL,
  715. 0,
  716. Headerp->HardwareAddress,
  717. Headerp->HardwareAddressLength
  718. );
  719. } else {
  720. AssignedAddress =
  721. DhcpAcquireUniqueAddress(
  722. reinterpret_cast<PCHAR>(
  723. OptionArray[DhcpOptionHostName]->Option
  724. ),
  725. OptionArray[DhcpOptionHostName]->Length,
  726. Headerp->HardwareAddress,
  727. Headerp->HardwareAddressLength
  728. );
  729. }
  730. if (!AssignedAddress) {
  731. NhTrace(
  732. TRACE_FLAG_DHCP,
  733. "DhcpProcessDiscoverMessage: address-allocation failed"
  734. );
  735. return;
  736. }
  737. }
  738. //
  739. // Acquire a buffer for the offer we will send back
  740. //
  741. Replyp = NhAcquireBuffer();
  742. if (!Replyp) {
  743. NhTrace(
  744. TRACE_FLAG_DHCP,
  745. "DhcpProcessDiscoverMessage: buffer-allocation failed"
  746. );
  747. NhErrorLog(
  748. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  749. 0,
  750. "%d",
  751. sizeof(NH_BUFFER)
  752. );
  753. return;
  754. }
  755. //
  756. // Pick up fields from the original message
  757. // the routines setting up the reply will attempt to read these,
  758. // so they are set to the values from the original buffer.
  759. //
  760. Replyp->Socket = Bufferp->Socket;
  761. Replyp->ReadAddress = Bufferp->ReadAddress;
  762. Replyp->WriteAddress = Bufferp->WriteAddress;
  763. Replyp->Context = Bufferp->Context;
  764. Replyp->Context2 = Bufferp->Context2;
  765. Offerp = (PDHCP_HEADER)Replyp->Buffer;
  766. //
  767. // Copy the original discover header
  768. //
  769. *Offerp = *Headerp;
  770. //
  771. // IP/1394 support (RFC 2855)
  772. //
  773. if ((IP1394_HTYPE == Offerp->HardwareAddressType) &&
  774. (0 == Offerp->HardwareAddressLength))
  775. {
  776. //
  777. // MUST set client hardware address to zero
  778. //
  779. ZeroMemory(Offerp->HardwareAddress, sizeof(Offerp->HardwareAddress));
  780. }
  781. //
  782. // Set up the offer-header fieldds
  783. //
  784. Offerp->Operation = BOOTP_OPERATION_REPLY;
  785. Offerp->AssignedAddress = AssignedAddress;
  786. Offerp->ServerHostName[0] = 0;
  787. Offerp->BootFile[0] = 0;
  788. Offerp->SecondsSinceBoot = 0;
  789. *(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
  790. //
  791. // Fill in options
  792. //
  793. Option = (PDHCP_OPTION)&Offerp->Footer[1];
  794. DhcpBuildReplyMessage(
  795. Interfacep,
  796. Replyp,
  797. &Option,
  798. DHCP_MESSAGE_OFFER,
  799. (BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
  800. OptionArray
  801. );
  802. //
  803. // Send the offer to the client
  804. //
  805. EnterCriticalSection(&DhcpInterfaceLock);
  806. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  807. LeaveCriticalSection(&DhcpInterfaceLock);
  808. NhReleaseBuffer(Replyp);
  809. } else {
  810. LeaveCriticalSection(&DhcpInterfaceLock);
  811. if (Headerp->RelayAgentAddress) {
  812. ReplyAddress = Headerp->RelayAgentAddress;
  813. ReplyPort = DHCP_PORT_SERVER;
  814. } else {
  815. ReplyAddress = INADDR_BROADCAST;
  816. ReplyPort = DHCP_PORT_CLIENT;
  817. }
  818. MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
  819. if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
  820. MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
  821. }
  822. Error =
  823. NhWriteDatagramSocket(
  824. &DhcpComponentReference,
  825. Bufferp->Socket,
  826. ReplyAddress,
  827. ReplyPort,
  828. Replyp,
  829. MessageLength,
  830. DhcpWriteCompletionRoutine,
  831. Interfacep,
  832. Bufferp->Context2
  833. );
  834. if (!Error) {
  835. InterlockedIncrement(
  836. reinterpret_cast<LPLONG>(&DhcpStatistics.OffersSent)
  837. );
  838. } else {
  839. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  840. NhReleaseBuffer(Replyp);
  841. NhTrace(
  842. TRACE_FLAG_DHCP,
  843. "DhcpProcessDiscoverMessage: error %d sending reply",
  844. Error
  845. );
  846. NhErrorLog(
  847. IP_AUTO_DHCP_LOG_REPLY_FAILED,
  848. Error,
  849. "%I",
  850. NhQueryAddressSocket(Bufferp->Socket)
  851. );
  852. }
  853. }
  854. } // DhcpProcessDiscoverMessage
  855. VOID
  856. DhcpProcessInformMessage(
  857. PDHCP_INTERFACE Interfacep,
  858. PNH_BUFFER Bufferp,
  859. DHCP_OPTION UNALIGNED* OptionArray[]
  860. )
  861. /*++
  862. Routine Description:
  863. This routine is called to process a received DHCPINFORM message.
  864. Arguments:
  865. Interfacep - the interface on which the inform was received
  866. Bufferp - the buffer containing the message
  867. OptionArray - options extracted from the message
  868. Return Value:
  869. none.
  870. Environment:
  871. Invoked with 'Interfacep' referenced by the caller.
  872. --*/
  873. {
  874. PDHCP_HEADER Ackp;
  875. ULONG Error;
  876. PDHCP_HEADER Headerp;
  877. ULONG MessageLength;
  878. DHCP_OPTION UNALIGNED* Option;
  879. ULONG ReplyAddress;
  880. USHORT ReplyPort;
  881. PNH_BUFFER Replyp;
  882. PROFILE("DhcpProcessInformMessage");
  883. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  884. //
  885. // Acquire a buffer for the ack we will send back
  886. //
  887. Replyp = NhAcquireBuffer();
  888. if (!Replyp) {
  889. NhTrace(
  890. TRACE_FLAG_DHCP,
  891. "DhcpProcessInformMessage: buffer-allocation failed"
  892. );
  893. NhErrorLog(
  894. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  895. 0,
  896. "%d",
  897. sizeof(NH_BUFFER)
  898. );
  899. return;
  900. }
  901. //
  902. // Pick up fields from the original message
  903. // the routines setting up the reply will attempt to read these,
  904. // so they are set to the values from the original buffer.
  905. //
  906. Replyp->Socket = Bufferp->Socket;
  907. Replyp->ReadAddress = Bufferp->ReadAddress;
  908. Replyp->WriteAddress = Bufferp->WriteAddress;
  909. Replyp->Context = Bufferp->Context;
  910. Replyp->Context2 = Bufferp->Context2;
  911. Ackp = (PDHCP_HEADER)Replyp->Buffer;
  912. //
  913. // Copy the original header
  914. //
  915. *Ackp = *Headerp;
  916. //
  917. // IP/1394 support (RFC 2855)
  918. //
  919. if ((IP1394_HTYPE == Ackp->HardwareAddressType) &&
  920. (0 == Ackp->HardwareAddressLength))
  921. {
  922. //
  923. // MUST set client hardware address to zero
  924. //
  925. ZeroMemory(Ackp->HardwareAddress, sizeof(Ackp->HardwareAddress));
  926. }
  927. //
  928. // Set up the ack-header fieldds
  929. //
  930. Ackp->Operation = BOOTP_OPERATION_REPLY;
  931. Ackp->AssignedAddress = 0;
  932. Ackp->ServerHostName[0] = 0;
  933. Ackp->BootFile[0] = 0;
  934. Ackp->SecondsSinceBoot = 0;
  935. *(ULONG UNALIGNED *)Ackp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
  936. //
  937. // Fill in options
  938. //
  939. Option = (PDHCP_OPTION)&Ackp->Footer[1];
  940. DhcpBuildReplyMessage(
  941. Interfacep,
  942. Replyp,
  943. &Option,
  944. DHCP_MESSAGE_ACK,
  945. (BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
  946. OptionArray
  947. );
  948. //
  949. // Send the offer to the client
  950. //
  951. EnterCriticalSection(&DhcpInterfaceLock);
  952. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  953. LeaveCriticalSection(&DhcpInterfaceLock);
  954. NhReleaseBuffer(Replyp);
  955. } else {
  956. LeaveCriticalSection(&DhcpInterfaceLock);
  957. if (Headerp->RelayAgentAddress) {
  958. ReplyAddress = Headerp->RelayAgentAddress;
  959. ReplyPort = DHCP_PORT_SERVER;
  960. } else {
  961. ReplyAddress = INADDR_BROADCAST;
  962. ReplyPort = DHCP_PORT_CLIENT;
  963. }
  964. MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
  965. if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
  966. MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
  967. }
  968. Error =
  969. NhWriteDatagramSocket(
  970. &DhcpComponentReference,
  971. Bufferp->Socket,
  972. ReplyAddress,
  973. ReplyPort,
  974. Replyp,
  975. MessageLength,
  976. DhcpWriteCompletionRoutine,
  977. Interfacep,
  978. Bufferp->Context2
  979. );
  980. if (!Error) {
  981. InterlockedIncrement(
  982. reinterpret_cast<LPLONG>(&DhcpStatistics.AcksSent)
  983. );
  984. } else {
  985. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  986. NhReleaseBuffer(Replyp);
  987. NhTrace(
  988. TRACE_FLAG_DHCP,
  989. "DhcpProcessInformMessage: error %d sending reply",
  990. Error
  991. );
  992. NhErrorLog(
  993. IP_AUTO_DHCP_LOG_REPLY_FAILED,
  994. Error,
  995. "%I",
  996. NhQueryAddressSocket(Bufferp->Socket)
  997. );
  998. }
  999. }
  1000. } // DhcpProcessInformMessage
  1001. VOID
  1002. DhcpProcessMessage(
  1003. PDHCP_INTERFACE Interfacep,
  1004. PNH_BUFFER Bufferp
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. This routine is invoked to process a DHCP client message.
  1009. Arguments:
  1010. Interfacep - the interface on which the request was received
  1011. Bufferp - the buffer containing the message received
  1012. Return Value:
  1013. none.
  1014. Environment:
  1015. Invoked internally with 'Interfacep' referenced by the caller.
  1016. --*/
  1017. {
  1018. ULONG Error;
  1019. PDHCP_HEADER Headerp;
  1020. UCHAR MessageType;
  1021. PDHCP_OPTION OptionArray[DhcpOptionCount];
  1022. PROFILE("DhcpProcessMessage");
  1023. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  1024. #if DBG
  1025. NhDump(
  1026. TRACE_FLAG_DHCP,
  1027. Bufferp->Buffer,
  1028. Bufferp->BytesTransferred,
  1029. 1
  1030. );
  1031. #endif
  1032. //
  1033. // Extract pointers to each option in the message
  1034. //
  1035. Error =
  1036. DhcpExtractOptionsFromMessage(
  1037. Headerp,
  1038. Bufferp->BytesTransferred,
  1039. OptionArray
  1040. );
  1041. if (Error) {
  1042. InterlockedIncrement(
  1043. reinterpret_cast<LPLONG>(&DhcpStatistics.MessagesIgnored)
  1044. );
  1045. }
  1046. else
  1047. //
  1048. // Look for the message-type;
  1049. // This distinguishes BOOTP from DHCP clients.
  1050. //
  1051. if (!OptionArray[DhcpOptionMessageType]) {
  1052. DhcpProcessBootpMessage(
  1053. Interfacep,
  1054. Bufferp,
  1055. OptionArray
  1056. );
  1057. } else if (Headerp->HardwareAddressLength <=
  1058. sizeof(Headerp->HardwareAddress) &&
  1059. DhcpIsLocalHardwareAddress(
  1060. Headerp->HardwareAddress, Headerp->HardwareAddressLength)) {
  1061. NhTrace(
  1062. TRACE_FLAG_DHCP,
  1063. "DhcpProcessMessage: ignoring message, from self"
  1064. );
  1065. } else switch(MessageType = OptionArray[DhcpOptionMessageType]->Option[0]) {
  1066. case DHCP_MESSAGE_DISCOVER: {
  1067. InterlockedIncrement(
  1068. reinterpret_cast<LPLONG>(&DhcpStatistics.DiscoversReceived)
  1069. );
  1070. NhTrace(
  1071. TRACE_FLAG_DHCP,
  1072. "DhcpProcessMessage: received DISCOVER message"
  1073. );
  1074. DhcpProcessDiscoverMessage(
  1075. Interfacep,
  1076. Bufferp,
  1077. OptionArray
  1078. );
  1079. break;
  1080. }
  1081. case DHCP_MESSAGE_REQUEST: {
  1082. InterlockedIncrement(
  1083. reinterpret_cast<LPLONG>(&DhcpStatistics.RequestsReceived)
  1084. );
  1085. NhTrace(
  1086. TRACE_FLAG_DHCP,
  1087. "DhcpProcessMessage: received REQUEST message"
  1088. );
  1089. DhcpProcessRequestMessage(
  1090. Interfacep,
  1091. Bufferp,
  1092. OptionArray
  1093. );
  1094. break;
  1095. }
  1096. case DHCP_MESSAGE_INFORM: {
  1097. InterlockedIncrement(
  1098. reinterpret_cast<LPLONG>(&DhcpStatistics.InformsReceived)
  1099. );
  1100. NhTrace(
  1101. TRACE_FLAG_DHCP,
  1102. "DhcpProcessMessage: received INFORM message"
  1103. );
  1104. DhcpProcessInformMessage(
  1105. Interfacep,
  1106. Bufferp,
  1107. OptionArray
  1108. );
  1109. break;
  1110. }
  1111. case DHCP_MESSAGE_DECLINE: {
  1112. InterlockedIncrement(
  1113. reinterpret_cast<LPLONG>(&DhcpStatistics.DeclinesReceived)
  1114. );
  1115. // log message
  1116. NhTrace(
  1117. TRACE_FLAG_DHCP,
  1118. "DhcpProcessMessage: received DECLINE message"
  1119. );
  1120. break;
  1121. }
  1122. case DHCP_MESSAGE_RELEASE: {
  1123. InterlockedIncrement(
  1124. reinterpret_cast<LPLONG>(&DhcpStatistics.ReleasesReceived)
  1125. );
  1126. NhTrace(
  1127. TRACE_FLAG_DHCP,
  1128. "DhcpProcessMessage: received RELEASE message"
  1129. );
  1130. break;
  1131. }
  1132. default: {
  1133. InterlockedIncrement(
  1134. reinterpret_cast<LPLONG>(&DhcpStatistics.MessagesIgnored)
  1135. );
  1136. NhTrace(
  1137. TRACE_FLAG_DHCP,
  1138. "DhcpProcessMessage: message type %d invalid",
  1139. MessageType
  1140. );
  1141. NhWarningLog(
  1142. IP_AUTO_DHCP_LOG_INVALID_DHCP_MESSAGE_TYPE,
  1143. 0,
  1144. "%d",
  1145. MessageType
  1146. );
  1147. break;
  1148. }
  1149. }
  1150. //
  1151. // Post the buffer for another read
  1152. //
  1153. EnterCriticalSection(&DhcpInterfaceLock);
  1154. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1155. LeaveCriticalSection(&DhcpInterfaceLock);
  1156. NhReleaseBuffer(Bufferp);
  1157. } else {
  1158. LeaveCriticalSection(&DhcpInterfaceLock);
  1159. Error =
  1160. NhReadDatagramSocket(
  1161. &DhcpComponentReference,
  1162. Bufferp->Socket,
  1163. Bufferp,
  1164. DhcpReadCompletionRoutine,
  1165. Bufferp->Context,
  1166. Bufferp->Context2
  1167. );
  1168. if (Error) {
  1169. ACQUIRE_LOCK(Interfacep);
  1170. DhcpDeferReadInterface(Interfacep, Bufferp->Socket);
  1171. RELEASE_LOCK(Interfacep);
  1172. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1173. NhTrace(
  1174. TRACE_FLAG_DHCP,
  1175. "DhcpProcessMessage: error %d reposting read",
  1176. Error
  1177. );
  1178. NhWarningLog(
  1179. IP_AUTO_DHCP_LOG_RECEIVE_FAILED,
  1180. Error,
  1181. "%I",
  1182. NhQueryAddressSocket(Bufferp->Socket)
  1183. );
  1184. NhReleaseBuffer(Bufferp);
  1185. }
  1186. }
  1187. } // DhcpProcessMessage
  1188. VOID
  1189. DhcpProcessRequestMessage(
  1190. PDHCP_INTERFACE Interfacep,
  1191. PNH_BUFFER Bufferp,
  1192. DHCP_OPTION UNALIGNED* OptionArray[]
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. This routine is called to process a request message.
  1197. Arguments:
  1198. Interfacep - the interface on which the request was received
  1199. Bufferp - the buffer containing the message received
  1200. OptionArray - options extracted from the message
  1201. Return Value:
  1202. none.
  1203. Environment:
  1204. Invoked internally with 'Interfacep' referenced by the caller.
  1205. --*/
  1206. {
  1207. ULONG AssignedAddress = 0;
  1208. ULONG Error;
  1209. UCHAR ExistingAddress[MAX_HARDWARE_ADDRESS_LENGTH];
  1210. ULONG ExistingAddressLength;
  1211. PDHCP_HEADER Headerp;
  1212. ULONG MessageLength;
  1213. PDHCP_HEADER Offerp;
  1214. DHCP_OPTION UNALIGNED* Option;
  1215. ULONG ReplyAddress;
  1216. USHORT ReplyPort;
  1217. PNH_BUFFER Replyp;
  1218. UCHAR ReplyType = DHCP_MESSAGE_ACK;
  1219. ULONG ScopeNetwork;
  1220. ULONG ScopeMask;
  1221. BOOLEAN bIsLocal = FALSE;
  1222. PROFILE("DhcpProcessRequestMessage");
  1223. ZeroMemory(ExistingAddress, sizeof(ExistingAddress));
  1224. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  1225. //
  1226. // Validate the address requested by the client
  1227. //
  1228. if (!Headerp->ClientAddress && !OptionArray[DhcpOptionRequestedAddress]) {
  1229. //
  1230. // The client left out the address being requested
  1231. //
  1232. ReplyType = DHCP_MESSAGE_NAK;
  1233. } else {
  1234. //
  1235. // Try to see if the address is in use.
  1236. //
  1237. AssignedAddress =
  1238. Headerp->ClientAddress
  1239. ? Headerp->ClientAddress
  1240. : *(ULONG UNALIGNED*)
  1241. OptionArray[DhcpOptionRequestedAddress]->Option;
  1242. EnterCriticalSection(&DhcpGlobalInfoLock);
  1243. ScopeNetwork = DhcpGlobalInfo->ScopeNetwork;
  1244. ScopeMask = DhcpGlobalInfo->ScopeMask;
  1245. LeaveCriticalSection(&DhcpGlobalInfoLock);
  1246. if ((AssignedAddress & ~ScopeMask) == 0 ||
  1247. (AssignedAddress & ~ScopeMask) == ~ScopeMask ||
  1248. (AssignedAddress & ScopeMask) != (ScopeNetwork & ScopeMask)) {
  1249. //
  1250. // The client is on the wrong subnet, or has an all-ones
  1251. // or all-zeroes address.
  1252. //
  1253. ReplyType = DHCP_MESSAGE_NAK;
  1254. } else if (!DhcpIsUniqueAddress(
  1255. AssignedAddress,
  1256. &bIsLocal,
  1257. ExistingAddress,
  1258. &ExistingAddressLength
  1259. ) &&
  1260. (bIsLocal ||
  1261. ((Headerp->HardwareAddressType != 7 && // due to WinXP Bridge bug + WinME Client bug
  1262. Headerp->HardwareAddressLength) && // if address length is zero we wont compare
  1263. (ExistingAddressLength < Headerp->HardwareAddressLength ||
  1264. memcmp(
  1265. ExistingAddress,
  1266. Headerp->HardwareAddress,
  1267. Headerp->HardwareAddressLength
  1268. ))))) {
  1269. //
  1270. // Someone has the requested address, and it's not the requestor.
  1271. //
  1272. ReplyType = DHCP_MESSAGE_NAK;
  1273. } else if (OptionArray[DhcpOptionHostName]) {
  1274. if (DhcpIsReservedAddress(
  1275. AssignedAddress,
  1276. reinterpret_cast<PCHAR>(
  1277. OptionArray[DhcpOptionHostName]->Option
  1278. ),
  1279. OptionArray[DhcpOptionHostName]->Length
  1280. )) {
  1281. //
  1282. // The address is reserved for someone else,
  1283. // or the client has a different address reserved.
  1284. //
  1285. ReplyType = DHCP_MESSAGE_NAK;
  1286. }
  1287. } else if (DhcpIsReservedAddress(AssignedAddress, NULL, 0)) {
  1288. //
  1289. // The address is reserved for someone else.
  1290. //
  1291. ReplyType = DHCP_MESSAGE_NAK;
  1292. }
  1293. }
  1294. //
  1295. // Acquire a buffer for the reply we will send back
  1296. //
  1297. Replyp = NhAcquireBuffer();
  1298. if (!Replyp) {
  1299. NhTrace(
  1300. TRACE_FLAG_DHCP,
  1301. "DhcpProcessRequestMessage: buffer-allocation failed"
  1302. );
  1303. NhErrorLog(
  1304. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  1305. 0,
  1306. "%d",
  1307. sizeof(NH_BUFFER)
  1308. );
  1309. return;
  1310. }
  1311. //
  1312. // Pick up fields to be used in the reply-buffer
  1313. // the routines setting up the reply will attempt to read these,
  1314. // so they are set to the values from the original buffer.
  1315. //
  1316. Replyp->Socket = Bufferp->Socket;
  1317. Replyp->ReadAddress = Bufferp->ReadAddress;
  1318. Replyp->WriteAddress = Bufferp->WriteAddress;
  1319. Replyp->Context = Bufferp->Context;
  1320. Replyp->Context2 = Bufferp->Context2;
  1321. Offerp = (PDHCP_HEADER)Replyp->Buffer;
  1322. //
  1323. // Copy the original discover header
  1324. //
  1325. *Offerp = *Headerp;
  1326. //
  1327. // IP/1394 support (RFC 2855)
  1328. //
  1329. if ((IP1394_HTYPE == Offerp->HardwareAddressType) &&
  1330. (0 == Offerp->HardwareAddressLength))
  1331. {
  1332. //
  1333. // MUST set client hardware address to zero
  1334. //
  1335. ZeroMemory(Offerp->HardwareAddress, sizeof(Offerp->HardwareAddress));
  1336. }
  1337. //
  1338. // Set up the offer-header fieldds
  1339. //
  1340. Offerp->Operation = BOOTP_OPERATION_REPLY;
  1341. Offerp->AssignedAddress = AssignedAddress;
  1342. Offerp->ServerHostName[0] = 0;
  1343. Offerp->BootFile[0] = 0;
  1344. Offerp->SecondsSinceBoot = 0;
  1345. *(ULONG UNALIGNED *)Offerp->Footer[0].Cookie = DHCP_MAGIC_COOKIE;
  1346. //
  1347. // Fill in options
  1348. //
  1349. Option = (PDHCP_OPTION)&Offerp->Footer[1];
  1350. DhcpBuildReplyMessage(
  1351. Interfacep,
  1352. Replyp,
  1353. &Option,
  1354. ReplyType,
  1355. (BOOLEAN)(OptionArray[DhcpOptionDynamicDns] ? TRUE : FALSE),
  1356. OptionArray
  1357. );
  1358. //
  1359. // NEW LOGIC HERE => tied to DNS
  1360. //
  1361. if (DHCP_MESSAGE_ACK == ReplyType)
  1362. {
  1363. //
  1364. // We perform the equivalent of Dynamic DNS here
  1365. // by informing the DNS component that this client exists
  1366. //
  1367. if (OptionArray[DhcpOptionHostName])
  1368. {
  1369. //
  1370. // check if DNS component is active
  1371. //
  1372. if (REFERENCE_DNS())
  1373. {
  1374. DnsUpdate(
  1375. reinterpret_cast<PCHAR>(OptionArray[DhcpOptionHostName]->Option),
  1376. (ULONG) OptionArray[DhcpOptionHostName]->Length,
  1377. AssignedAddress
  1378. );
  1379. DEREFERENCE_DNS();
  1380. }
  1381. }
  1382. }
  1383. //
  1384. // Send the reply to the client
  1385. //
  1386. EnterCriticalSection(&DhcpInterfaceLock);
  1387. if (!DHCP_REFERENCE_INTERFACE(Interfacep)) {
  1388. LeaveCriticalSection(&DhcpInterfaceLock);
  1389. NhReleaseBuffer(Replyp);
  1390. } else {
  1391. LeaveCriticalSection(&DhcpInterfaceLock);
  1392. if (Headerp->RelayAgentAddress) {
  1393. ReplyAddress = Headerp->RelayAgentAddress;
  1394. ReplyPort = DHCP_PORT_SERVER;
  1395. } else {
  1396. ReplyAddress = INADDR_BROADCAST;
  1397. ReplyPort = DHCP_PORT_CLIENT;
  1398. }
  1399. MessageLength = (ULONG)((PUCHAR)Option - Replyp->Buffer);
  1400. if (MessageLength < sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH) {
  1401. MessageLength = sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH;
  1402. }
  1403. Error =
  1404. NhWriteDatagramSocket(
  1405. &DhcpComponentReference,
  1406. Bufferp->Socket,
  1407. ReplyAddress,
  1408. ReplyPort,
  1409. Replyp,
  1410. MessageLength,
  1411. DhcpWriteCompletionRoutine,
  1412. Interfacep,
  1413. Bufferp->Context2
  1414. );
  1415. if (!Error) {
  1416. InterlockedIncrement(
  1417. (ReplyType == DHCP_MESSAGE_ACK)
  1418. ? reinterpret_cast<LPLONG>(&DhcpStatistics.AcksSent)
  1419. : reinterpret_cast<LPLONG>(&DhcpStatistics.NaksSent)
  1420. );
  1421. } else {
  1422. DHCP_DEREFERENCE_INTERFACE(Interfacep);
  1423. NhReleaseBuffer(Replyp);
  1424. NhTrace(
  1425. TRACE_FLAG_DHCP,
  1426. "DhcpProcessRequestMessage: error %d sending reply",
  1427. Error
  1428. );
  1429. NhErrorLog(
  1430. IP_AUTO_DHCP_LOG_REPLY_FAILED,
  1431. Error,
  1432. "%I",
  1433. NhQueryAddressSocket(Bufferp->Socket)
  1434. );
  1435. }
  1436. }
  1437. } // DhcpProcessRequestMessage
  1438. ULONG
  1439. DhcpWriteClientRequestMessage(
  1440. PDHCP_INTERFACE Interfacep,
  1441. PDHCP_BINDING Binding
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This routine is invoked to check for the existence of a DHCP server
  1446. on the given interface and address. It generates a BOOTP request
  1447. on a socket bound to the DHCP client port.
  1448. Arguments:
  1449. Interfacep - the interface on which the client request is to be sent
  1450. Binding - the binding on which the request is to be sent
  1451. Return Value:
  1452. ULONG - status code.
  1453. Environment:
  1454. Invoked with 'Interfacep' locked and with a reference made to 'Interfacep'
  1455. for the send which occurs here.
  1456. If the routine fails, it is the caller's responsibility to release
  1457. the reference.
  1458. --*/
  1459. {
  1460. PNH_BUFFER Bufferp;
  1461. ULONG Error;
  1462. PDHCP_HEADER Headerp;
  1463. SOCKET Socket;
  1464. PROFILE("DhcpWriteClientRequestMessage");
  1465. //
  1466. // Create a socket using the given address
  1467. //
  1468. Error =
  1469. NhCreateDatagramSocket(
  1470. Binding->Address,
  1471. DHCP_PORT_CLIENT,
  1472. &Binding->ClientSocket
  1473. );
  1474. if (Error) {
  1475. NhTrace(
  1476. TRACE_FLAG_IF,
  1477. "DhcpWriteClientRequestMessage: error %d creating socket for %s",
  1478. Error,
  1479. INET_NTOA(Binding->Address)
  1480. );
  1481. NhWarningLog(
  1482. IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE,
  1483. Error,
  1484. "%I",
  1485. Binding->Address
  1486. );
  1487. return Error;
  1488. }
  1489. //
  1490. // Allocate a buffer for the BOOTP request
  1491. //
  1492. Bufferp = NhAcquireBuffer();
  1493. if (!Bufferp) {
  1494. NhDeleteDatagramSocket(Binding->ClientSocket);
  1495. Binding->ClientSocket = INVALID_SOCKET;
  1496. NhTrace(
  1497. TRACE_FLAG_IF,
  1498. "DhcpWriteClientRequestMessage: error allocating buffer for %s",
  1499. INET_NTOA(Binding->Address)
  1500. );
  1501. NhErrorLog(
  1502. IP_AUTO_DHCP_LOG_ALLOCATION_FAILED,
  1503. 0,
  1504. "%d",
  1505. sizeof(NH_BUFFER)
  1506. );
  1507. return ERROR_NOT_ENOUGH_MEMORY;
  1508. }
  1509. //
  1510. // Initialize the BOOTP request
  1511. //
  1512. Headerp = (PDHCP_HEADER)Bufferp->Buffer;
  1513. ZeroMemory(Headerp, sizeof(*Headerp));
  1514. Headerp->Operation = BOOTP_OPERATION_REQUEST;
  1515. Headerp->HardwareAddressType = 1;
  1516. Headerp->HardwareAddressLength = 6;
  1517. Headerp->TransactionId = DHCP_DETECTION_TRANSACTION_ID;
  1518. Headerp->SecondsSinceBoot = 10;
  1519. Headerp->Flags |= BOOTP_FLAG_BROADCAST;
  1520. Headerp->ClientAddress = Binding->Address;
  1521. Headerp->HardwareAddress[1] = 0xab;
  1522. *(PULONG)(Headerp->Footer[0].Cookie) = DHCP_MAGIC_COOKIE;
  1523. *(PUCHAR)(Headerp->Footer + 1) = DHCP_TAG_END;
  1524. //
  1525. // Send the BOOTP request on the socket
  1526. //
  1527. Error =
  1528. NhWriteDatagramSocket(
  1529. &DhcpComponentReference,
  1530. Binding->ClientSocket,
  1531. INADDR_BROADCAST,
  1532. DHCP_PORT_SERVER,
  1533. Bufferp,
  1534. sizeof(DHCP_HEADER) + BOOTP_VENDOR_LENGTH,
  1535. DhcpWriteClientRequestCompletionRoutine,
  1536. (PVOID)Interfacep,
  1537. UlongToPtr(Binding->Address)
  1538. );
  1539. if (Error) {
  1540. NhReleaseBuffer(Bufferp);
  1541. NhDeleteDatagramSocket(Binding->ClientSocket);
  1542. Binding->ClientSocket = INVALID_SOCKET;
  1543. NhTrace(
  1544. TRACE_FLAG_IF,
  1545. "DhcpWriteClientRequestMessage: error %d writing request for %s",
  1546. Error,
  1547. INET_NTOA(Binding->Address)
  1548. );
  1549. NhWarningLog(
  1550. IP_AUTO_DHCP_LOG_DETECTION_UNAVAILABLE,
  1551. Error,
  1552. "%I",
  1553. Binding->Address
  1554. );
  1555. return Error;
  1556. }
  1557. return NO_ERROR;
  1558. } // DhcpWriteClientRequestMessage