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.

2136 lines
48 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. dnslookup.c
  5. Abstract:
  6. This module contains code for the DNS component's name-lookup mechanism.
  7. Author:
  8. Tom Brown (tbrown) 10/21/99
  9. Revision History:
  10. Raghu Gatta (rgatta) 21-Oct-2000
  11. Rewrite + Cleanup + New Functions
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define DNS_HOMENET_DOT L"."
  16. ULONG g_PrivateIPAddr = 0;
  17. CRITICAL_SECTION DnsTableLock; // protects both tables
  18. RTL_GENERIC_TABLE g_DnsTable,
  19. g_ReverseDnsTable;
  20. //
  21. // FORWARD DECLARATIONS
  22. //
  23. ULONG
  24. DhcpGetPrivateInterfaceAddress(
  25. VOID
  26. );
  27. RTL_GENERIC_COMPARE_RESULTS
  28. TableNameCompareRoutine(
  29. PRTL_GENERIC_TABLE Table,
  30. PVOID FirstStruct,
  31. PVOID SecondStruct
  32. )
  33. /*++
  34. Routine Description:
  35. This is a callback routine to compare two DNS_ENTRY structures.
  36. It is used by the RTL table implementation.
  37. Arguments:
  38. Table - pointer to the RTL table. Not used.
  39. FirstStruct - the first DNS_ENTRY structure
  40. SecondStruct - the second DNS_ENTRY structure
  41. Return Value:
  42. One of GenericLessThan, GenericGreaterThan, or GenericEqual,
  43. depending on the relative values of the parameters.
  44. Environment:
  45. Called back by the Rtl table lookup routines.
  46. --*/
  47. {
  48. INT iCompareResults;
  49. BOOL fNamesAreEqual;
  50. WCHAR *pszFirstName, *pszSecondName;
  51. PROFILE("TableNameCompareRoutine");
  52. pszFirstName = ((PDNS_ENTRY)FirstStruct)->pszName;
  53. pszSecondName = ((PDNS_ENTRY)SecondStruct)->pszName;
  54. fNamesAreEqual = DnsNameCompare_W(pszFirstName, pszSecondName);
  55. if (fNamesAreEqual)
  56. {
  57. iCompareResults = 0;
  58. }
  59. else
  60. {
  61. iCompareResults = _wcsicmp(pszFirstName, pszSecondName);
  62. }
  63. if (iCompareResults < 0)
  64. {
  65. return GenericLessThan;
  66. }
  67. else if (iCompareResults > 0)
  68. {
  69. return GenericGreaterThan;
  70. }
  71. else
  72. {
  73. return GenericEqual;
  74. }
  75. }
  76. RTL_GENERIC_COMPARE_RESULTS
  77. TableAddressCompareRoutine(
  78. PRTL_GENERIC_TABLE Table,
  79. PVOID FirstStruct,
  80. PVOID SecondStruct
  81. )
  82. /*++
  83. Routine Description:
  84. This is a callback routine to compare two REVERSE_DNS_ENTRY structures.
  85. It is used by the RTL table implementation.
  86. Arguments:
  87. Table - pointer to the RTL table. Not used.
  88. FirstStruct - the first REVERSE_DNS_ENTRY structure
  89. SecondStruct - the second REVERSE_DNS_ENTRY structure
  90. Return Value:
  91. One of GenericLessThan, GenericGreaterThan, or GenericEqual,
  92. depending on the relative values of the parameters.
  93. Environment:
  94. Called back by the Rtl table lookup routines.
  95. --*/
  96. {
  97. DNS_ADDRESS Address1, Address2;
  98. PROFILE("TableAddressCompareRoutine");
  99. Address1 = ((PREVERSE_DNS_ENTRY)FirstStruct)->ulAddress;
  100. Address2 = ((PREVERSE_DNS_ENTRY)SecondStruct)->ulAddress;
  101. if (Address1 > Address2)
  102. {
  103. return GenericGreaterThan;
  104. }
  105. else if (Address1 < Address2)
  106. {
  107. return GenericLessThan;
  108. }
  109. else
  110. {
  111. return GenericEqual;
  112. }
  113. }
  114. PVOID
  115. TableAllocateRoutine(
  116. PRTL_GENERIC_TABLE Table,
  117. CLONG ByteSize
  118. )
  119. /*++
  120. Routine Description:
  121. This is a callback routine to allocate memory for an Rtl table.
  122. Arguments:
  123. Table - pointer to the RTL table. Not used.
  124. ByteSize - the number of bytes to allocate
  125. SecondStruct - the second DNS_ENTRY structure
  126. Return Value:
  127. A pointer to the allocated memory.
  128. Environment:
  129. Called back by the Rtl table lookup routines.
  130. --*/
  131. {
  132. return NH_ALLOCATE(ByteSize);
  133. }
  134. VOID
  135. TableFreeRoutine(
  136. PRTL_GENERIC_TABLE Table,
  137. PVOID pBuffer
  138. )
  139. /*++
  140. Routine Description:
  141. This is a callback routine to free memory allocated by TableAllocateRoutine.
  142. Arguments:
  143. Table - pointer to the RTL table. Not used.
  144. pBuffer - pointer to the buffer to free
  145. Return Value:
  146. None
  147. Environment:
  148. Called back by the Rtl table lookup routines.
  149. --*/
  150. {
  151. NH_FREE(pBuffer);
  152. }
  153. ULONG
  154. DnsInitializeTableManagement(
  155. VOID
  156. )
  157. /*++
  158. Routine Description:
  159. This is a public function that must be called before any of the other Dns
  160. table functions. It initializes the various tables used by the server.
  161. Arguments:
  162. None
  163. Return Value:
  164. None
  165. Environment:
  166. Arbitrary.
  167. --*/
  168. {
  169. ULONG Error = NO_ERROR;
  170. PROFILE("DnsInitializeTableManagement");
  171. __try {
  172. InitializeCriticalSection(&DnsTableLock);
  173. }
  174. __except(EXCEPTION_EXECUTE_HANDLER) {
  175. NhTrace(
  176. TRACE_FLAG_DNS,
  177. "DnsInitializeTableManagement: exception %d creating lock",
  178. Error = GetExceptionCode()
  179. );
  180. }
  181. RtlInitializeGenericTable(
  182. &g_DnsTable,
  183. TableNameCompareRoutine,
  184. TableAllocateRoutine,
  185. TableFreeRoutine,
  186. NULL
  187. );
  188. RtlInitializeGenericTable(
  189. &g_ReverseDnsTable,
  190. TableAddressCompareRoutine,
  191. TableAllocateRoutine,
  192. TableFreeRoutine,
  193. NULL
  194. );
  195. return Error;
  196. } // DnsInitializeTableManagement
  197. VOID
  198. DnsShutdownTableManagement(
  199. VOID
  200. )
  201. /*++
  202. Routine Description:
  203. This routine is called to shutdown the table management module.
  204. Arguments:
  205. none.
  206. Return Value:
  207. none.
  208. Environment:
  209. Invoked in an arbitrary thread context.
  210. --*/
  211. {
  212. PROFILE("DnsShutdownTableManagement");
  213. DnsEmptyTables();
  214. DeleteCriticalSection(&DnsTableLock);
  215. } // DnsShutdownTableManagement
  216. VOID
  217. DnsEmptyTables(
  218. VOID
  219. )
  220. /*++
  221. Routine Description:
  222. This routine is called to empty the DNS tables.
  223. Arguments:
  224. none.
  225. Return Value:
  226. none.
  227. Environment:
  228. Invoked in an arbitrary thread context.
  229. --*/
  230. {
  231. ULONG i, count;
  232. PDNS_ENTRY pDnsEntry;
  233. REVERSE_DNS_ENTRY reverseEntry;
  234. PREVERSE_DNS_ENTRY pRDnsEntry;
  235. WCHAR *pszNameCopy;
  236. PROFILE("DnsEmptyTables");
  237. //
  238. // for each entry in the forward table, delete all the entries in the
  239. // reverse table
  240. //
  241. //
  242. // emptying table in LIFO order
  243. //
  244. EnterCriticalSection(&DnsTableLock);
  245. count = RtlNumberGenericTableElements(&g_DnsTable);
  246. while (count)
  247. {
  248. pDnsEntry = (PDNS_ENTRY) RtlGetElementGenericTable(
  249. &g_DnsTable,
  250. --count
  251. );
  252. reverseEntry.pszName = NULL;
  253. for (i = 0; i < pDnsEntry->cAddresses; i++)
  254. {
  255. reverseEntry.ulAddress = pDnsEntry->aAddressInfo[i].ulAddress;
  256. RtlDeleteElementGenericTable(
  257. &g_ReverseDnsTable,
  258. &reverseEntry
  259. );
  260. }
  261. pszNameCopy = pDnsEntry->pszName;
  262. NH_FREE(pDnsEntry->aAddressInfo);
  263. pDnsEntry->aAddressInfo = NULL;
  264. RtlDeleteElementGenericTable(
  265. &g_DnsTable,
  266. pDnsEntry
  267. );
  268. NH_FREE(pszNameCopy);
  269. }
  270. //
  271. // the forward table should be empty by now
  272. //
  273. ASSERT(RtlIsGenericTableEmpty(&g_DnsTable));
  274. //
  275. // ensure that the reverse table is also empty
  276. //
  277. count = RtlNumberGenericTableElements(&g_ReverseDnsTable);
  278. while (count)
  279. {
  280. pRDnsEntry = (PREVERSE_DNS_ENTRY) RtlGetElementGenericTable(
  281. &g_ReverseDnsTable,
  282. --count
  283. );
  284. RtlDeleteElementGenericTable(
  285. &g_ReverseDnsTable,
  286. pRDnsEntry
  287. );
  288. }
  289. LeaveCriticalSection(&DnsTableLock);
  290. } // DnsEmptyTables
  291. BOOL
  292. DnsRegisterName(
  293. WCHAR *pszName,
  294. UINT cAddresses,
  295. ADDRESS_INFO aAddressInfo[]
  296. )
  297. /*++
  298. Routine Description:
  299. Public function to register a DNS name in the server's table.
  300. Arguments:
  301. pszName - Name to register, in Unicode, dotted-name format.
  302. cAddresses - Number of addresses associated with this name
  303. aAddressInfo - Array of address information (addresses in network order)
  304. Return Value:
  305. TRUE if the registration was for a new name (the name did not already exist
  306. in the table); FALSE if the name already existed and was replaced.
  307. FALSE also if there was an error condition.
  308. Environment:
  309. Arbitrary
  310. --*/
  311. {
  312. DNS_ENTRY dnsEntry;
  313. DWORD cAddressesAllocated = 0;
  314. REVERSE_DNS_ENTRY reverseDnsEntry;
  315. BOOLEAN fNewElement = TRUE,
  316. fNameIsNew = FALSE;
  317. UINT i;
  318. PROFILE("DnsRegisterName");
  319. NhTrace(
  320. TRACE_FLAG_DNS,
  321. "DnsRegisterName: Registering name %S, with %d addresses",
  322. pszName,
  323. cAddresses
  324. );
  325. for (i = 0; i < cAddresses; i++)
  326. {
  327. NhTrace(
  328. TRACE_FLAG_DNS,
  329. "DnsRegisterName: Address %d = %lx",
  330. i,
  331. aAddressInfo[i].ulAddress
  332. );
  333. }
  334. dnsEntry.pszName = (PWCHAR) NH_ALLOCATE((wcslen(pszName) + 1) * sizeof(WCHAR));
  335. if (!dnsEntry.pszName)
  336. {
  337. return fNameIsNew; // currently set to FALSE
  338. }
  339. wcscpy(dnsEntry.pszName, pszName);
  340. if (cAddresses == 1)
  341. {
  342. // In general, all names will have one address; so if we're just registering
  343. // one name, then only allocate enough space for one name.
  344. cAddressesAllocated = 1;
  345. }
  346. else
  347. {
  348. // If we have more than one address, then allocate in increments of 5.
  349. cAddressesAllocated = ((cAddresses + 4) / 5) * 5;
  350. }
  351. dnsEntry.aAddressInfo = (PADDRESS_INFO) NH_ALLOCATE(cAddressesAllocated * sizeof(ADDRESS_INFO));
  352. if (!dnsEntry.aAddressInfo)
  353. {
  354. NH_FREE(dnsEntry.pszName);
  355. return fNameIsNew; // currently set to FALSE
  356. }
  357. memcpy(dnsEntry.aAddressInfo, aAddressInfo, cAddresses * sizeof(ADDRESS_INFO));
  358. dnsEntry.cAddresses = cAddresses;
  359. dnsEntry.cAddressesAllocated = cAddressesAllocated;
  360. EnterCriticalSection(&DnsTableLock);
  361. RtlInsertElementGenericTable(
  362. &g_DnsTable,
  363. &dnsEntry,
  364. sizeof(dnsEntry),
  365. &fNameIsNew
  366. );
  367. reverseDnsEntry.pszName = dnsEntry.pszName;
  368. for (i = 0; i < cAddresses; i++)
  369. {
  370. PREVERSE_DNS_ENTRY pEntry;
  371. reverseDnsEntry.ulAddress = dnsEntry.aAddressInfo[i].ulAddress;
  372. pEntry = (PREVERSE_DNS_ENTRY) RtlInsertElementGenericTable(
  373. &g_ReverseDnsTable,
  374. &reverseDnsEntry,
  375. sizeof(reverseDnsEntry),
  376. &fNewElement
  377. );
  378. // If this IP address is already in the reverse table, then replace it.
  379. if (!fNewElement)
  380. {
  381. pEntry->pszName = dnsEntry.pszName;
  382. }
  383. }
  384. LeaveCriticalSection(&DnsTableLock);
  385. if (!fNewElement)
  386. {
  387. DnsCleanupTables();
  388. }
  389. return fNameIsNew;
  390. } // DnsRegisterName
  391. VOID
  392. DnsAddAddressForName(
  393. WCHAR *pszName,
  394. DNS_ADDRESS ulAddress,
  395. FILETIME ftExpires
  396. )
  397. /*++
  398. Routine Description:
  399. Public function to add an IP address for a name that potentially
  400. already exists.
  401. Arguments:
  402. pszName - Name to register, in Unicode, dotted-name format.
  403. ulAddress - New IP address to associate with this name,
  404. in network order
  405. Return Value:
  406. None.
  407. Environment:
  408. Arbitrary
  409. --*/
  410. {
  411. PDNS_ENTRY pEntry;
  412. PROFILE("DnsAddAddressForName");
  413. pEntry = DnsLookupAddress(pszName);
  414. if (pEntry == NULL)
  415. {
  416. ADDRESS_INFO info;
  417. info.ulAddress = ulAddress;
  418. info.ftExpires = ftExpires;
  419. //info.ulExpires = ulExpires;
  420. DnsRegisterName(pszName, 1, &info);
  421. }
  422. else
  423. {
  424. UINT i;
  425. REVERSE_DNS_ENTRY reverseDnsEntry;
  426. PREVERSE_DNS_ENTRY pReverseEntry;
  427. BOOLEAN fNewElement;
  428. // first, let's make sure that this IP address isn't already associated with
  429. // this name.
  430. for (i = 0; i < pEntry->cAddresses; i++)
  431. {
  432. if (pEntry->aAddressInfo[i].ulAddress == ulAddress)
  433. {
  434. //
  435. // simply update the expiry time
  436. //
  437. NhTrace(
  438. TRACE_FLAG_DNS,
  439. "DnsAddAddressForName: Refresh expiry time for %S",
  440. pszName
  441. );
  442. pEntry->aAddressInfo[i].ftExpires = ftExpires;
  443. return;
  444. }
  445. }
  446. //
  447. // we limit the number of addresses per machine name to one only
  448. //
  449. //
  450. // guard against zero allocation
  451. //
  452. if (!pEntry->cAddressesAllocated)
  453. {
  454. pEntry->aAddressInfo = (PADDRESS_INFO) NH_ALLOCATE(1 * sizeof(ADDRESS_INFO));
  455. if (pEntry->aAddressInfo)
  456. {
  457. pEntry->cAddressesAllocated = 1;
  458. }
  459. else
  460. {
  461. // no memory - return quitely
  462. return;
  463. }
  464. }
  465. //
  466. // at least 1 block has been allocated
  467. //
  468. pEntry->cAddresses = 1;
  469. pEntry->aAddressInfo[0].ulAddress = ulAddress;
  470. pEntry->aAddressInfo[0].ftExpires = ftExpires;
  471. reverseDnsEntry.ulAddress = ulAddress;
  472. reverseDnsEntry.pszName = pEntry->pszName;
  473. EnterCriticalSection(&DnsTableLock);
  474. pReverseEntry = (PREVERSE_DNS_ENTRY) RtlInsertElementGenericTable(
  475. &g_ReverseDnsTable,
  476. &reverseDnsEntry,
  477. sizeof(reverseDnsEntry),
  478. &fNewElement
  479. );
  480. // If this IP address is already in the reverse table, then replace it.
  481. if (!fNewElement)
  482. {
  483. pReverseEntry->pszName = pEntry->pszName;
  484. }
  485. LeaveCriticalSection(&DnsTableLock);
  486. if (!fNewElement)
  487. {
  488. DnsCleanupTables();
  489. }
  490. }
  491. } // DnsAddAddressForName
  492. VOID
  493. DnsDeleteAddressForName(
  494. WCHAR *pszName,
  495. DNS_ADDRESS ulAddress
  496. )
  497. /*++
  498. Routine Description:
  499. Public function to un-associate an IP address from a given name,
  500. and potentially delete the record from the table if there are no more
  501. IP addresses associated with the name.
  502. Arguments:
  503. pszName - Name, in Unicode, dotted-name format.
  504. ulAddress - IP address to un-associate with the given name,
  505. in network order
  506. Return Value:
  507. None.
  508. Environment:
  509. Arbitrary
  510. --*/
  511. {
  512. PDNS_ENTRY pEntry;
  513. REVERSE_DNS_ENTRY reverseEntry;
  514. PROFILE("DnsDeleteAddressForName");
  515. pEntry = DnsLookupAddress(pszName);
  516. if (pEntry != NULL)
  517. {
  518. INT i, iLocation = -1;
  519. // Find the index of the requested address
  520. for (i = 0; i < (INT)pEntry->cAddresses; i++)
  521. {
  522. if (pEntry->aAddressInfo[i].ulAddress == ulAddress)
  523. {
  524. iLocation = i;
  525. break;
  526. }
  527. }
  528. if (iLocation > -1)
  529. {
  530. if (pEntry->cAddresses > 1)
  531. {
  532. // Move the rest of the array backwards
  533. memcpy(&pEntry->aAddressInfo[iLocation],
  534. &pEntry->aAddressInfo[iLocation + 1],
  535. (pEntry->cAddresses - 1 - iLocation) * sizeof(ADDRESS_INFO));
  536. pEntry->cAddresses--;
  537. }
  538. else
  539. {
  540. // Delete the whole entry - it no longer has any IP addresses associated
  541. // with it.
  542. DnsDeleteName(pszName);
  543. }
  544. }
  545. }
  546. reverseEntry.pszName = NULL;
  547. reverseEntry.ulAddress = ulAddress;
  548. EnterCriticalSection(&DnsTableLock);
  549. RtlDeleteElementGenericTable(
  550. &g_ReverseDnsTable,
  551. &reverseEntry
  552. );
  553. LeaveCriticalSection(&DnsTableLock);
  554. } // DnsDeleteAddressForName
  555. PDNS_ENTRY
  556. DnsPurgeExpiredNames(
  557. PDNS_ENTRY pEntry
  558. )
  559. /*++
  560. Routine Description:
  561. TODO.
  562. Arguments:
  563. TODO
  564. Return Value:
  565. TODO
  566. Environment:
  567. TODO.
  568. --*/
  569. {
  570. UINT i, j;
  571. FILETIME ftTime;
  572. REVERSE_DNS_ENTRY reverseEntry;
  573. PROFILE("DnsPurgeExpiredNames");
  574. GetSystemTimeAsFileTime(&ftTime);
  575. reverseEntry.pszName = NULL;
  576. for (j = 1; j < pEntry->cAddresses + 1; j++)
  577. {
  578. // j is 1-based so that we can safely subtract 1 from it below (it's unsigned).
  579. // we really want the 0-based number, so we translate that to i immediately.
  580. i = j - 1;
  581. if (IsFileTimeExpired(&pEntry->aAddressInfo[i].ftExpires))
  582. {
  583. NhTrace(TRACE_FLAG_DNS, "DnsPurgeExpiredNames: Deleting address %lx for name %ls",
  584. pEntry->aAddressInfo[i].ulAddress,
  585. pEntry->pszName);
  586. reverseEntry.ulAddress = pEntry->aAddressInfo[i].ulAddress;
  587. RtlDeleteElementGenericTable(
  588. &g_ReverseDnsTable,
  589. &reverseEntry
  590. );
  591. memcpy(&pEntry->aAddressInfo[i], &pEntry->aAddressInfo[i+1],
  592. (pEntry->cAddresses - i - 1) * sizeof(ADDRESS_INFO));
  593. pEntry->cAddresses--;
  594. j--;
  595. }
  596. }
  597. if (pEntry->cAddresses == 0)
  598. {
  599. WCHAR *pszName;
  600. pszName = pEntry->pszName;
  601. NH_FREE(pEntry->aAddressInfo);
  602. pEntry->aAddressInfo = NULL;
  603. RtlDeleteElementGenericTable(
  604. &g_DnsTable,
  605. pEntry
  606. );
  607. NH_FREE(pszName);
  608. pEntry = NULL;
  609. }
  610. return pEntry;
  611. } // DnsPurgeExpiredNames
  612. PDNS_ENTRY
  613. DnsLookupAddress(
  614. WCHAR *pszName
  615. )
  616. /*++
  617. Routine Description:
  618. Public function to look up the address of a given name.
  619. Arguments:
  620. pszName - Name to look up, in Unicode, dotted name format.
  621. Return Value:
  622. A pointer to the DNS_ENTRY value that is in the table. Note that
  623. this is not a copy, so a) it should not be freed by the caller, and
  624. b) any modifications made to the data will be reflected in the table.
  625. If the name is not found, the function will return NULL.
  626. Addresses are stored in network order.
  627. Environment:
  628. Arbitrary.
  629. --*/
  630. {
  631. PDNS_ENTRY pEntry;
  632. DNS_ENTRY dnsSearch;
  633. PROFILE("DnsLookupAddress");
  634. dnsSearch.pszName = pszName;
  635. dnsSearch.cAddresses = 0;
  636. EnterCriticalSection(&DnsTableLock);
  637. pEntry = (PDNS_ENTRY) RtlLookupElementGenericTable(
  638. &g_DnsTable,
  639. &dnsSearch
  640. );
  641. if (pEntry)
  642. {
  643. pEntry = DnsPurgeExpiredNames(pEntry);
  644. }
  645. LeaveCriticalSection(&DnsTableLock);
  646. return pEntry;
  647. } // DnsLookupAddress
  648. PREVERSE_DNS_ENTRY
  649. DnsLookupName(
  650. DNS_ADDRESS ulAddress
  651. )
  652. /*++
  653. Routine Description:
  654. Public function to look up the name of a given address.
  655. Arguments:
  656. ulAddress - network order address.
  657. Return Value:
  658. A pointer to the REVERSE_DNS_ENTRY value that is in the table. Note that
  659. this is not a copy, so a) it should not be freed by the caller, and
  660. b) any modifications made to the data will be reflected in the table.
  661. If the address is not found, the function will return NULL.
  662. Environment:
  663. Arbitrary.
  664. --*/
  665. {
  666. PREVERSE_DNS_ENTRY pEntry;
  667. REVERSE_DNS_ENTRY dnsSearch;
  668. PROFILE("DnsLookupName");
  669. dnsSearch.ulAddress = ulAddress;
  670. dnsSearch.pszName = NULL;
  671. EnterCriticalSection(&DnsTableLock);
  672. pEntry = (PREVERSE_DNS_ENTRY) RtlLookupElementGenericTable(
  673. &g_ReverseDnsTable,
  674. &dnsSearch
  675. );
  676. LeaveCriticalSection(&DnsTableLock);
  677. return pEntry;
  678. } // DnsLookupName
  679. VOID
  680. DnsDeleteName(
  681. WCHAR *pszName
  682. )
  683. /*++
  684. Routine Description:
  685. Public function to delete a given name from the DNS table.
  686. Arguments:
  687. pszName - Name to delete.
  688. Return Value:
  689. None.
  690. Environment:
  691. Arbitrary.
  692. --*/
  693. {
  694. PDNS_ENTRY pEntry;
  695. REVERSE_DNS_ENTRY reverseEntry;
  696. UINT i;
  697. WCHAR *pszNameCopy;
  698. PROFILE("DnsDeleteName");
  699. pEntry = DnsLookupAddress(pszName);
  700. reverseEntry.pszName = NULL;
  701. EnterCriticalSection(&DnsTableLock);
  702. for (i = 0; i < pEntry->cAddresses; i++)
  703. {
  704. reverseEntry.ulAddress = pEntry->aAddressInfo[i].ulAddress;
  705. RtlDeleteElementGenericTable(
  706. &g_ReverseDnsTable,
  707. &reverseEntry
  708. );
  709. }
  710. pszNameCopy = pEntry->pszName;
  711. NH_FREE(pEntry->aAddressInfo);
  712. pEntry->aAddressInfo = NULL;
  713. RtlDeleteElementGenericTable(
  714. &g_DnsTable,
  715. pEntry
  716. );
  717. LeaveCriticalSection(&DnsTableLock);
  718. NH_FREE(pszNameCopy);
  719. } // DnsDeleteName
  720. VOID
  721. DnsUpdateName(
  722. WCHAR *pszName,
  723. DNS_ADDRESS ulAddress
  724. )
  725. /*++
  726. Routine Description:
  727. Public function to add an IP address for a name that potentially
  728. already exists. If both name and address exist, we update the time
  729. in the table for a fresh lease
  730. Arguments:
  731. pszName - Name to register, in Unicode, dotted-name format.
  732. ulAddress - (possibly new) IP address to associate with this name,
  733. in network order
  734. Return Value:
  735. None.
  736. Environment:
  737. Arbitrary
  738. --*/
  739. {
  740. PDNS_ENTRY pEntry;
  741. FILETIME ftExpires;
  742. LARGE_INTEGER liExpires, liTime, liNow;
  743. BOOL fWriteToStore = FALSE;
  744. BOOLEAN fNewElement = TRUE; // refers to reverse table entry
  745. GetSystemTimeAsFileTime(&ftExpires); // current UTC time
  746. memcpy(&liNow, &ftExpires, sizeof(LARGE_INTEGER));
  747. //
  748. // current cache table expiry time is fixed - put in registry afterwards
  749. //
  750. liTime = RtlEnlargedIntegerMultiply(CACHE_ENTRY_EXPIRY, SYSTIME_UNITS_IN_1_SEC);
  751. liExpires = RtlLargeIntegerAdd(liTime, liNow);;
  752. memcpy(&ftExpires, &liExpires, sizeof(LARGE_INTEGER));
  753. PROFILE("DnsUpdateName");
  754. pEntry = DnsLookupAddress(pszName);
  755. if (pEntry == NULL)
  756. {
  757. ADDRESS_INFO info;
  758. info.ulAddress = ulAddress;
  759. info.ftExpires = ftExpires;
  760. DnsRegisterName(pszName, 1, &info);
  761. fWriteToStore = TRUE;
  762. }
  763. else
  764. {
  765. UINT i;
  766. REVERSE_DNS_ENTRY reverseDnsEntry;
  767. PREVERSE_DNS_ENTRY pReverseEntry;
  768. // first, let's make sure that this IP address isn't already associated with
  769. // this name.
  770. for (i = 0; i < pEntry->cAddresses; i++)
  771. {
  772. if (pEntry->aAddressInfo[i].ulAddress == ulAddress)
  773. {
  774. //
  775. // simply update the expiry time
  776. //
  777. NhTrace(
  778. TRACE_FLAG_DNS,
  779. "DnsUpdateName: Refresh expiry time for %S",
  780. pszName
  781. );
  782. pEntry->aAddressInfo[i].ftExpires = ftExpires;
  783. return;
  784. }
  785. }
  786. //
  787. // we limit the number of addresses per machine name to one only
  788. //
  789. //
  790. // guard against zero allocation
  791. //
  792. if (!pEntry->cAddressesAllocated)
  793. {
  794. pEntry->aAddressInfo = (PADDRESS_INFO) NH_ALLOCATE(1 * sizeof(ADDRESS_INFO));
  795. if (pEntry->aAddressInfo)
  796. {
  797. pEntry->cAddressesAllocated = 1;
  798. }
  799. else
  800. {
  801. // no memory - return quitely
  802. return;
  803. }
  804. }
  805. //
  806. // at least 1 block has been allocated
  807. //
  808. pEntry->cAddresses = 1;
  809. pEntry->aAddressInfo[0].ulAddress = ulAddress;
  810. pEntry->aAddressInfo[0].ftExpires = ftExpires;
  811. reverseDnsEntry.ulAddress = ulAddress;
  812. reverseDnsEntry.pszName = pEntry->pszName;
  813. EnterCriticalSection(&DnsTableLock);
  814. pReverseEntry = (PREVERSE_DNS_ENTRY) RtlInsertElementGenericTable(
  815. &g_ReverseDnsTable,
  816. &reverseDnsEntry,
  817. sizeof(reverseDnsEntry),
  818. &fNewElement
  819. );
  820. // If this IP address is already in the reverse table, then replace it.
  821. if (!fNewElement)
  822. {
  823. pReverseEntry->pszName = pEntry->pszName;
  824. }
  825. LeaveCriticalSection(&DnsTableLock);
  826. if (!fNewElement)
  827. {
  828. DnsCleanupTables();
  829. }
  830. fWriteToStore = TRUE;
  831. }
  832. if (fWriteToStore)
  833. {
  834. SaveHostsIcsFile(FALSE);
  835. }
  836. } // DnsUpdateName
  837. VOID
  838. DnsUpdate(
  839. CHAR *pName,
  840. ULONG len,
  841. ULONG ulAddress
  842. )
  843. /*++
  844. Routine Description:
  845. Called from the DHCP component to simulate Dynamic DNS.
  846. Arguments:
  847. pName - hostname to register, in wire format.
  848. len - length of hostname
  849. ulAddress - (possibly new) IP address to associate with this name,
  850. in network order
  851. Return Value:
  852. None.
  853. Environment:
  854. Arbitrary
  855. --*/
  856. {
  857. PROFILE("DnsUpdate");
  858. //
  859. // convert string to a Unicode string and update table
  860. //
  861. DWORD dwSize = 0;
  862. DWORD Error = NO_ERROR;
  863. LPVOID lpMsgBuf = NULL;
  864. LPBYTE pszName = NULL;
  865. PWCHAR pszUnicodeFQDN = NULL;
  866. if (NULL == pName || 0 == len || '\0' == *pName)
  867. {
  868. NhTrace(
  869. TRACE_FLAG_DNS,
  870. "DnsUpdate: No Name present - discard DNS Update"
  871. );
  872. return;
  873. }
  874. do
  875. {
  876. EnterCriticalSection(&DnsGlobalInfoLock);
  877. if (!DnsICSDomainSuffix)
  878. {
  879. NhTrace(
  880. TRACE_FLAG_DNS,
  881. "DnsUpdate: DnsICSDomainSuffix string not present - update failed!"
  882. );
  883. break;
  884. }
  885. //
  886. // create a null terminated copy
  887. //
  888. dwSize = len + 4;
  889. pszName = reinterpret_cast<LPBYTE>(NH_ALLOCATE(dwSize));
  890. if (!pszName)
  891. {
  892. NhTrace(
  893. TRACE_FLAG_DNS,
  894. "DnsUpdate: allocation failed for hostname copy buffer"
  895. );
  896. break;
  897. }
  898. ZeroMemory(pszName, dwSize);
  899. memcpy(pszName, pName, len);
  900. pszName[len] = '\0';
  901. //
  902. // NOTE: the RFCs are unclear about how to handle hostname option.
  903. // try out different codepage conversions to unicode in order of:
  904. // OEM, ANSI, MAC and finally give UTF8 a try
  905. // our default conversion is to use mbstowcs()
  906. //
  907. //
  908. // try OEM to Unicode conversion
  909. //
  910. Error = DnsConvertHostNametoUnicode(
  911. CP_OEMCP,
  912. (PCHAR)pszName,
  913. DnsICSDomainSuffix,
  914. &pszUnicodeFQDN
  915. );
  916. if (Error)
  917. {
  918. NhTrace(
  919. TRACE_FLAG_DNS,
  920. "DnsUpdate: DnsConvertHostName(OEM)toUnicode failed with "
  921. "Error %ld (0x%08x)",
  922. Error,
  923. Error
  924. );
  925. if (pszUnicodeFQDN)
  926. {
  927. NH_FREE(pszUnicodeFQDN);
  928. pszUnicodeFQDN = NULL;
  929. }
  930. }
  931. //
  932. // try ANSI to Unicode conversion
  933. //
  934. if (!pszUnicodeFQDN)
  935. {
  936. Error = DnsConvertHostNametoUnicode(
  937. CP_ACP,
  938. (PCHAR)pszName,
  939. DnsICSDomainSuffix,
  940. &pszUnicodeFQDN
  941. );
  942. if (Error)
  943. {
  944. NhTrace(
  945. TRACE_FLAG_DNS,
  946. "DnsUpdate: DnsConvertHostName(ANSI)toUnicode failed with "
  947. "Error %ld (0x%08x)",
  948. Error,
  949. Error
  950. );
  951. if (pszUnicodeFQDN)
  952. {
  953. NH_FREE(pszUnicodeFQDN);
  954. pszUnicodeFQDN = NULL;
  955. }
  956. }
  957. }
  958. //
  959. // try MAC to Unicode conversion
  960. //
  961. if (!pszUnicodeFQDN)
  962. {
  963. Error = DnsConvertHostNametoUnicode(
  964. CP_MACCP,
  965. (PCHAR)pszName,
  966. DnsICSDomainSuffix,
  967. &pszUnicodeFQDN
  968. );
  969. if (Error)
  970. {
  971. NhTrace(
  972. TRACE_FLAG_DNS,
  973. "DnsUpdate: DnsConvertHostName(MAC)toUnicode() failed with "
  974. "Error %ld (0x%08x)",
  975. Error,
  976. Error
  977. );
  978. if (pszUnicodeFQDN)
  979. {
  980. NH_FREE(pszUnicodeFQDN);
  981. pszUnicodeFQDN = NULL;
  982. }
  983. }
  984. }
  985. //
  986. // try UTF8 to Unicode conversion
  987. //
  988. if (!pszUnicodeFQDN)
  989. {
  990. Error = DnsConvertHostNametoUnicode(
  991. CP_UTF8,
  992. (PCHAR)pszName,
  993. DnsICSDomainSuffix,
  994. &pszUnicodeFQDN
  995. );
  996. if (Error)
  997. {
  998. NhTrace(
  999. TRACE_FLAG_DNS,
  1000. "DnsUpdate: DnsConvertHostName(UTF8)toUnicode() failed with "
  1001. "Error %ld (0x%08x)",
  1002. Error,
  1003. Error
  1004. );
  1005. if (pszUnicodeFQDN)
  1006. {
  1007. NH_FREE(pszUnicodeFQDN);
  1008. pszUnicodeFQDN = NULL;
  1009. }
  1010. }
  1011. }
  1012. //
  1013. // default conversion
  1014. //
  1015. if (!pszUnicodeFQDN)
  1016. {
  1017. dwSize = len +
  1018. wcslen(DNS_HOMENET_DOT) +
  1019. wcslen(DnsICSDomainSuffix) +
  1020. 1;
  1021. pszUnicodeFQDN = reinterpret_cast<PWCHAR>(NH_ALLOCATE(sizeof(WCHAR) * dwSize));
  1022. if (!pszUnicodeFQDN)
  1023. {
  1024. NhTrace(
  1025. TRACE_FLAG_DNS,
  1026. "DnsUpdate: allocation failed for client name"
  1027. );
  1028. break;
  1029. }
  1030. ZeroMemory(pszUnicodeFQDN, (sizeof(WCHAR) * dwSize));
  1031. mbstowcs(pszUnicodeFQDN, (char *)pszName, len);
  1032. wcscat(pszUnicodeFQDN, DNS_HOMENET_DOT); // add the dot
  1033. wcscat(pszUnicodeFQDN, DnsICSDomainSuffix); // add the suffix
  1034. }
  1035. LeaveCriticalSection(&DnsGlobalInfoLock);
  1036. DnsUpdateName(
  1037. pszUnicodeFQDN,
  1038. ulAddress
  1039. );
  1040. NH_FREE(pszName);
  1041. NH_FREE(pszUnicodeFQDN);
  1042. return;
  1043. } while (FALSE);
  1044. LeaveCriticalSection(&DnsGlobalInfoLock);
  1045. if (pszName)
  1046. {
  1047. NH_FREE(pszName);
  1048. }
  1049. if (pszUnicodeFQDN)
  1050. {
  1051. NH_FREE(pszUnicodeFQDN);
  1052. }
  1053. return;
  1054. } // DnsUpdate
  1055. VOID
  1056. DnsAddSelf(
  1057. VOID
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. Called each time we do a load of the hosts.ics file
  1062. Arguments:
  1063. none.
  1064. Return Value:
  1065. None.
  1066. Environment:
  1067. Arbitrary
  1068. --*/
  1069. {
  1070. PROFILE("DnsAddSelf");
  1071. DWORD len = 512, dwSize = 0;
  1072. WCHAR pszCompNameBuf[512];
  1073. PWCHAR pszBuf = NULL;
  1074. LPVOID lpMsgBuf;
  1075. ULONG ulAddress = 0;
  1076. FILETIME ftExpires;
  1077. LARGE_INTEGER liExpires, liTime, liNow;
  1078. ZeroMemory(pszCompNameBuf, (sizeof(WCHAR) * len));
  1079. if (!GetComputerNameExW(
  1080. ComputerNameDnsHostname,//ComputerNameNetBIOS,
  1081. pszCompNameBuf,
  1082. &len
  1083. )
  1084. )
  1085. {
  1086. lpMsgBuf = NULL;
  1087. FormatMessage(
  1088. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1089. FORMAT_MESSAGE_FROM_SYSTEM |
  1090. FORMAT_MESSAGE_IGNORE_INSERTS,
  1091. NULL,
  1092. GetLastError(),
  1093. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1094. (LPTSTR) &lpMsgBuf,
  1095. 0,
  1096. NULL
  1097. );
  1098. NhTrace(
  1099. TRACE_FLAG_DNS,
  1100. "DnsAddSelf: GetComputerNameExW failed with message: %S",
  1101. lpMsgBuf
  1102. );
  1103. if (lpMsgBuf) LocalFree(lpMsgBuf);
  1104. }
  1105. else
  1106. {
  1107. //
  1108. // we query the DHCP component if it is active for an IP address
  1109. // because it has scope information also. if this fails, we revert
  1110. // to the DNS component's list of interface addresses
  1111. //
  1112. //
  1113. // check if DHCP component is active
  1114. //
  1115. if (REFERENCE_DHCP())
  1116. {
  1117. ulAddress = DhcpGetPrivateInterfaceAddress();
  1118. DEREFERENCE_DHCP();
  1119. }
  1120. if (!ulAddress)
  1121. {
  1122. ulAddress = DnsGetPrivateInterfaceAddress();
  1123. }
  1124. if (!ulAddress)
  1125. {
  1126. //
  1127. // could not retreive correct IP address - use cached address
  1128. //
  1129. ulAddress = g_PrivateIPAddr;
  1130. }
  1131. else
  1132. {
  1133. //
  1134. // got some valid address
  1135. //
  1136. g_PrivateIPAddr = ulAddress;
  1137. }
  1138. if (ulAddress)
  1139. {
  1140. if (DnsICSDomainSuffix)
  1141. {
  1142. EnterCriticalSection(&DnsGlobalInfoLock);
  1143. dwSize = len +
  1144. wcslen(DNS_HOMENET_DOT) +
  1145. wcslen(DnsICSDomainSuffix) +
  1146. 1;
  1147. pszBuf = reinterpret_cast<PWCHAR>(
  1148. NH_ALLOCATE(sizeof(WCHAR) * dwSize)
  1149. );
  1150. if (!pszBuf)
  1151. {
  1152. LeaveCriticalSection(&DnsGlobalInfoLock);
  1153. NhTrace(
  1154. TRACE_FLAG_DNS,
  1155. "DnsAddSelf: allocation failed for client name"
  1156. );
  1157. return;
  1158. }
  1159. ZeroMemory(pszBuf, (sizeof(WCHAR) * dwSize));
  1160. wcscpy(pszBuf, pszCompNameBuf); // copy the name
  1161. wcscat(pszBuf, DNS_HOMENET_DOT); // add the dot
  1162. wcscat(pszBuf, DnsICSDomainSuffix); // add the suffix
  1163. LeaveCriticalSection(&DnsGlobalInfoLock);
  1164. GetSystemTimeAsFileTime(&ftExpires); // current UTC time
  1165. memcpy(&liNow, &ftExpires, sizeof(LARGE_INTEGER));
  1166. liTime = RtlEnlargedIntegerMultiply((5 * 365 * 24 * 60 * 60), SYSTIME_UNITS_IN_1_SEC);
  1167. liExpires = RtlLargeIntegerAdd(liTime, liNow);;
  1168. memcpy(&ftExpires, &liExpires, sizeof(LARGE_INTEGER));
  1169. DnsAddAddressForName(
  1170. pszBuf,
  1171. ulAddress,
  1172. ftExpires
  1173. );
  1174. NH_FREE(pszBuf);
  1175. }
  1176. else
  1177. {
  1178. NhTrace(
  1179. TRACE_FLAG_DNS,
  1180. "DnsAddSelf: DnsICSDomainSuffix string not present - update failed!"
  1181. );
  1182. }
  1183. }
  1184. }
  1185. return;
  1186. } // DnsAddSelf
  1187. VOID
  1188. DnsCleanupTables(
  1189. VOID
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. Called each time we detect that there could be atleast one entry with
  1194. an IP address not belonging to it anymore.
  1195. Arguments:
  1196. none.
  1197. Return Value:
  1198. None.
  1199. Environment:
  1200. Arbitrary.
  1201. --*/
  1202. {
  1203. PDNS_ENTRY pFwdEntry;
  1204. PREVERSE_DNS_ENTRY pRevEntry;
  1205. DNS_ENTRY dnsFwdSearch;
  1206. REVERSE_DNS_ENTRY dnsRevSearch;
  1207. BOOL fDelEntry;
  1208. UINT i;
  1209. PWCHAR *GCArray = NULL;
  1210. DWORD GCCount = 0,
  1211. GCSize = 0;
  1212. //
  1213. // Enumerate through the forward DNS table - if the IP address(es)
  1214. // for each forward entry have an entry in the reverse DNS table
  1215. // and this reverse entry's name pointer does not point to us, then
  1216. // delete this IP address from this forward entry
  1217. //
  1218. EnterCriticalSection(&DnsTableLock);
  1219. pFwdEntry = (PDNS_ENTRY) RtlEnumerateGenericTable(&g_DnsTable, TRUE);
  1220. while (pFwdEntry != NULL)
  1221. {
  1222. for (i = 0; i < pFwdEntry->cAddresses; i++)
  1223. {
  1224. pRevEntry = NULL;
  1225. dnsRevSearch.ulAddress = pFwdEntry->aAddressInfo[i].ulAddress;
  1226. dnsRevSearch.pszName = NULL;
  1227. pRevEntry = (PREVERSE_DNS_ENTRY) RtlLookupElementGenericTable(
  1228. &g_ReverseDnsTable,
  1229. &dnsRevSearch
  1230. );
  1231. if ((!pRevEntry) ||
  1232. ((pRevEntry) &&
  1233. (pRevEntry->pszName != pFwdEntry->pszName)))
  1234. {
  1235. //
  1236. // Remove this IP address from the forward entry address list
  1237. //
  1238. if (pFwdEntry->cAddresses > 1)
  1239. {
  1240. memcpy(&pFwdEntry->aAddressInfo[i],
  1241. &pFwdEntry->aAddressInfo[i + 1],
  1242. (pFwdEntry->cAddresses - 1 - i) * sizeof(ADDRESS_INFO));
  1243. pFwdEntry->cAddresses--;
  1244. }
  1245. else
  1246. {
  1247. //
  1248. // Single "invalid" IP address - zero the count
  1249. //
  1250. pFwdEntry->cAddresses = 0;
  1251. NH_FREE(pFwdEntry->aAddressInfo);
  1252. pFwdEntry->aAddressInfo = NULL;
  1253. break;
  1254. }
  1255. }
  1256. }
  1257. if (0 == pFwdEntry->cAddresses)
  1258. {
  1259. //
  1260. // Remember this entry name
  1261. //
  1262. if (GCSize <= GCCount)
  1263. {
  1264. PWCHAR *tmpGCArray = NULL;
  1265. DWORD tmpGCSize = 0;
  1266. // Allocate in increments of five
  1267. tmpGCSize = ((GCCount + 5) / 5) * 5;
  1268. tmpGCArray = (PWCHAR *) NH_ALLOCATE(tmpGCSize * sizeof(PWCHAR));
  1269. if (tmpGCArray)
  1270. {
  1271. if (GCArray)
  1272. {
  1273. memcpy(tmpGCArray, GCArray, (GCCount * sizeof(PWCHAR)));
  1274. NH_FREE(GCArray);
  1275. }
  1276. GCSize = tmpGCSize;
  1277. GCArray = tmpGCArray;
  1278. //
  1279. // add it to our array
  1280. //
  1281. GCArray[GCCount++] = pFwdEntry->pszName;
  1282. }
  1283. }
  1284. else
  1285. {
  1286. //
  1287. // add it to our array
  1288. //
  1289. GCArray[GCCount++] = pFwdEntry->pszName;
  1290. }
  1291. }
  1292. pFwdEntry = (PDNS_ENTRY) RtlEnumerateGenericTable(&g_DnsTable, FALSE);
  1293. }
  1294. //
  1295. // Garbage collect after complete enumeration
  1296. //
  1297. for (i = 0; i < GCCount; i++)
  1298. {
  1299. dnsFwdSearch.pszName = GCArray[i];
  1300. dnsFwdSearch.cAddresses = 0;
  1301. pFwdEntry = (PDNS_ENTRY) RtlLookupElementGenericTable(
  1302. &g_DnsTable,
  1303. &dnsFwdSearch
  1304. );
  1305. if (pFwdEntry)
  1306. {
  1307. //
  1308. // (1) we have a copy of pointer to name as in GCArray[i]
  1309. // (2) aAddressInfo has already been taken care of above
  1310. // (3) only need to get rid of FwdEntry struct from table
  1311. //
  1312. RtlDeleteElementGenericTable(
  1313. &g_DnsTable,
  1314. pFwdEntry
  1315. );
  1316. //
  1317. // done after the fwd entry was deleted from fwd DNS table
  1318. //
  1319. NH_FREE(GCArray[i]);
  1320. }
  1321. GCArray[i] = NULL;
  1322. }
  1323. LeaveCriticalSection(&DnsTableLock);
  1324. if (GCArray)
  1325. {
  1326. NH_FREE(GCArray);
  1327. }
  1328. return;
  1329. } // DnsCleanupTables
  1330. //
  1331. // Utility conversion routines
  1332. //
  1333. DWORD
  1334. DnsConvertHostNametoUnicode(
  1335. UINT CodePage,
  1336. CHAR *pszHostName,
  1337. PWCHAR DnsICSDomainSuffix,
  1338. PWCHAR *ppszUnicodeFQDN
  1339. )
  1340. {
  1341. PROFILE("DnsConvertHostNametoUnicode");
  1342. //
  1343. // make sure to free the returned UnicodeFQDN
  1344. // caller holds DnsGlobalInfoLock
  1345. //
  1346. DWORD dwSize = 0;
  1347. DWORD Error = NO_ERROR;
  1348. LPBYTE pszUtf8HostName = NULL; // copy of pszHostName in Utf8 format
  1349. PWCHAR pszUnicodeHostName = NULL;
  1350. PWCHAR pszUnicodeFQDN = NULL;
  1351. //
  1352. // convert the given hostname to a Unicode string
  1353. //
  1354. if (CP_UTF8 == CodePage)
  1355. {
  1356. pszUtf8HostName = (LPBYTE)pszHostName;
  1357. }
  1358. else
  1359. {
  1360. //
  1361. // now convert this into UTF8 format
  1362. //
  1363. if (!ConvertToUtf8(
  1364. CodePage,
  1365. (LPSTR)pszHostName,
  1366. (PCHAR *)&pszUtf8HostName,
  1367. &dwSize))
  1368. {
  1369. Error = GetLastError();
  1370. NhTrace(
  1371. TRACE_FLAG_DNS,
  1372. "DnsConvertHostNametoUnicode: conversion from "
  1373. "CodePage %d to UTF8 for hostname failed "
  1374. "with error %ld (0x%08x)",
  1375. CodePage,
  1376. Error,
  1377. Error
  1378. );
  1379. if (pszUtf8HostName)
  1380. {
  1381. NH_FREE(pszUtf8HostName);
  1382. }
  1383. return Error;
  1384. }
  1385. }
  1386. //
  1387. // now convert this into Unicode format
  1388. //
  1389. if (!ConvertUTF8ToUnicode(
  1390. pszUtf8HostName,
  1391. (LPWSTR *)&pszUnicodeHostName,
  1392. &dwSize))
  1393. {
  1394. Error = GetLastError();
  1395. NhTrace(
  1396. TRACE_FLAG_DNS,
  1397. "DnsConvertHostNametoUnicode: conversion from "
  1398. "UTF8 to Unicode for hostname failed "
  1399. "with error %ld (0x%08x)",
  1400. Error,
  1401. Error
  1402. );
  1403. if (CP_UTF8 != CodePage)
  1404. {
  1405. NH_FREE(pszUtf8HostName);
  1406. }
  1407. if (pszUnicodeHostName)
  1408. {
  1409. NH_FREE(pszUnicodeHostName);
  1410. }
  1411. return Error;
  1412. }
  1413. dwSize += sizeof(WCHAR)*(wcslen(DNS_HOMENET_DOT)+wcslen(DnsICSDomainSuffix)+1);
  1414. pszUnicodeFQDN = reinterpret_cast<PWCHAR>(NH_ALLOCATE(dwSize));
  1415. if (!pszUnicodeFQDN)
  1416. {
  1417. NhTrace(
  1418. TRACE_FLAG_DNS,
  1419. "DnsConvertHostNametoUnicode: allocation failed "
  1420. "for Unicode FQDN"
  1421. );
  1422. if (CP_UTF8 != CodePage)
  1423. {
  1424. NH_FREE(pszUtf8HostName);
  1425. }
  1426. NH_FREE(pszUnicodeHostName);
  1427. return ERROR_NOT_ENOUGH_MEMORY;
  1428. }
  1429. ZeroMemory(pszUnicodeFQDN, dwSize);
  1430. wcscpy(pszUnicodeFQDN, pszUnicodeHostName); // copy the name
  1431. wcscat(pszUnicodeFQDN, DNS_HOMENET_DOT); // add the dot
  1432. wcscat(pszUnicodeFQDN, DnsICSDomainSuffix); // add the suffix
  1433. *ppszUnicodeFQDN = pszUnicodeFQDN;
  1434. if (CP_UTF8 != CodePage)
  1435. {
  1436. NH_FREE(pszUtf8HostName);
  1437. }
  1438. NH_FREE(pszUnicodeHostName);
  1439. NhTrace(
  1440. TRACE_FLAG_DNS,
  1441. "DnsConvertHostNametoUnicode: succeeded! %S",
  1442. pszUnicodeFQDN
  1443. );
  1444. return Error;
  1445. } // DnsConvertHostNametoUnicode
  1446. BOOL
  1447. ConvertToUtf8(
  1448. IN UINT CodePage,
  1449. IN LPSTR pszName,
  1450. OUT PCHAR *ppszUtf8Name,
  1451. OUT ULONG *pUtf8NameSize
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. This functions converts an specified CodePage string to Utf8 format.
  1456. Arguments:
  1457. pszName - Buffer to the hostname string which is null terminated.
  1458. ppszUtf8Name - receives Pointer to the buffer receiving Utf8 string.
  1459. BufSize - receives Length of the above buffer in bytes.
  1460. Return Value:
  1461. TRUE on successful conversion.
  1462. --*/
  1463. {
  1464. DWORD Error = NO_ERROR;
  1465. DWORD dwSize = 0;
  1466. PCHAR pszUtf8Name = NULL;
  1467. LPWSTR pBuf = NULL;
  1468. DWORD Count;
  1469. Count = MultiByteToWideChar(
  1470. CodePage,
  1471. MB_ERR_INVALID_CHARS,
  1472. pszName,
  1473. -1,
  1474. pBuf,
  1475. 0
  1476. );
  1477. if(0 == Count)
  1478. {
  1479. Error = GetLastError();
  1480. NhTrace(
  1481. TRACE_FLAG_DNS,
  1482. "ConvertToUtf8: MultiByteToWideChar returned %ld (0x%08x)",
  1483. Error,
  1484. Error
  1485. );
  1486. return FALSE;
  1487. }
  1488. dwSize = Count * sizeof(WCHAR);
  1489. pBuf = reinterpret_cast<LPWSTR>(NH_ALLOCATE(dwSize));
  1490. if (!pBuf)
  1491. {
  1492. NhTrace(
  1493. TRACE_FLAG_DNS,
  1494. "ConvertToUtf8: allocation failed for temporary wide char buffer"
  1495. );
  1496. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1497. return FALSE;
  1498. }
  1499. ZeroMemory(pBuf, dwSize);
  1500. Count = MultiByteToWideChar(
  1501. CodePage,
  1502. MB_ERR_INVALID_CHARS,
  1503. pszName,
  1504. -1,
  1505. pBuf,
  1506. Count
  1507. );
  1508. if(0 == Count)
  1509. {
  1510. Error = GetLastError();
  1511. NhTrace(
  1512. TRACE_FLAG_DNS,
  1513. "ConvertToUtf8: MultiByteToWideChar returned %ld (0x%08x)",
  1514. Error,
  1515. Error
  1516. );
  1517. NH_FREE(pBuf);
  1518. return FALSE;
  1519. }
  1520. Count = WideCharToMultiByte(
  1521. CP_UTF8,
  1522. 0,
  1523. pBuf,
  1524. -1,
  1525. pszUtf8Name,
  1526. 0,
  1527. NULL,
  1528. NULL
  1529. );
  1530. dwSize = Count;
  1531. pszUtf8Name = reinterpret_cast<PCHAR>(NH_ALLOCATE(dwSize));
  1532. if (!pszUtf8Name)
  1533. {
  1534. NhTrace(
  1535. TRACE_FLAG_DNS,
  1536. "ConvertToUtf8: allocation failed for Utf8 char buffer"
  1537. );
  1538. NH_FREE(pBuf);
  1539. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1540. return FALSE;
  1541. }
  1542. ZeroMemory(pszUtf8Name, dwSize);
  1543. Count = WideCharToMultiByte(
  1544. CP_UTF8,
  1545. 0,
  1546. pBuf,
  1547. -1,
  1548. pszUtf8Name,
  1549. Count,
  1550. NULL,
  1551. NULL
  1552. );
  1553. //
  1554. // N.B. Looks like there is no such thing as a default
  1555. // character for UTF8 - so we have to assume this
  1556. // succeeded..
  1557. // if any default characters were used, then it can't be
  1558. // converted actually.. so don't allow this
  1559. //
  1560. NH_FREE(pBuf);
  1561. *ppszUtf8Name = pszUtf8Name;
  1562. *pUtf8NameSize = dwSize;
  1563. return (Count != 0);
  1564. } // ConvertToUtf8
  1565. BOOL
  1566. ConvertUTF8ToUnicode(
  1567. IN LPBYTE UTF8String,
  1568. OUT LPWSTR *ppszUnicodeName,
  1569. OUT DWORD *pUnicodeNameSize
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. This functions converts Utf8 format to Unicodestring.
  1574. Arguments:
  1575. UTF8String - Buffer to UTFString which is null terminated.
  1576. ppszUnicodeName - receives Pointer to the buffer receiving Unicode string.
  1577. pUnicodeLength - receives Length of the above buffer in bytes.
  1578. Return Value:
  1579. TRUE on successful conversion.
  1580. --*/
  1581. {
  1582. DWORD Count, dwSize = 0, Error = NO_ERROR;
  1583. LPWSTR pBuf = NULL;
  1584. Count = MultiByteToWideChar(
  1585. CP_UTF8,
  1586. 0,
  1587. (LPCSTR)UTF8String,
  1588. -1,
  1589. pBuf,
  1590. 0
  1591. );
  1592. if(0 == Count)
  1593. {
  1594. Error = GetLastError();
  1595. NhTrace(
  1596. TRACE_FLAG_DNS,
  1597. "ConvertUTF8ToUnicode: MultiByteToWideChar returned %ld (0x%08x)",
  1598. Error,
  1599. Error
  1600. );
  1601. return FALSE;
  1602. }
  1603. dwSize = Count * sizeof(WCHAR);
  1604. pBuf = reinterpret_cast<LPWSTR>(NH_ALLOCATE(dwSize));
  1605. if (!pBuf)
  1606. {
  1607. NhTrace(
  1608. TRACE_FLAG_DNS,
  1609. "ConvertUTF8ToUnicode: allocation failed for unicode string buffer"
  1610. );
  1611. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1612. return FALSE;
  1613. }
  1614. ZeroMemory(pBuf, dwSize);
  1615. Count = MultiByteToWideChar(
  1616. CP_UTF8,
  1617. 0,
  1618. (LPCSTR)UTF8String,
  1619. -1,
  1620. pBuf,
  1621. Count
  1622. );
  1623. if(0 == Count)
  1624. {
  1625. Error = GetLastError();
  1626. NhTrace(
  1627. TRACE_FLAG_DNS,
  1628. "ConvertUTF8ToUnicode: MultiByteToWideChar returned %ld (0x%08x)",
  1629. Error,
  1630. Error
  1631. );
  1632. NH_FREE(pBuf);
  1633. return FALSE;
  1634. }
  1635. *ppszUnicodeName = pBuf;
  1636. *pUnicodeNameSize = dwSize;
  1637. return (Count != 0);
  1638. } // ConvertUTF8ToUnicode