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

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