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.

2184 lines
57 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. dnsquery.c
  5. Abstract:
  6. This module contains code for the DNS proxy's query-management.
  7. Author:
  8. Abolade Gbadegesin (aboladeg) 11-Mar-1998
  9. Revision History:
  10. Raghu Gatta (rgatta) 1-Dec-2000
  11. Added ICSDomain registry key change notify code.
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "dnsmsg.h"
  16. //
  17. // Structure: DNS_QUERY_TIMEOUT_CONTEXT
  18. //
  19. // This structure is used to pass context information
  20. // to the timeout callback-routine for DNS queries.
  21. //
  22. typedef struct _DNS_QUERY_TIMEOUT_CONTEXT {
  23. ULONG Index;
  24. USHORT QueryId;
  25. } DNS_QUERY_TIMEOUT_CONTEXT, *PDNS_QUERY_TIMEOUT_CONTEXT;
  26. //
  27. // GLOBAL DATA DEFINITIONS
  28. //
  29. const WCHAR DnsDhcpNameServerString[] = L"DhcpNameServer";
  30. const WCHAR DnsNameServerString[] = L"NameServer";
  31. HANDLE DnsNotifyChangeKeyEvent = NULL;
  32. IO_STATUS_BLOCK DnsNotifyChangeKeyIoStatus;
  33. HANDLE DnsNotifyChangeKeyWaitHandle = NULL;
  34. HANDLE DnsNotifyChangeAddressEvent = NULL;
  35. OVERLAPPED DnsNotifyChangeAddressOverlapped;
  36. HANDLE DnsNotifyChangeAddressWaitHandle = NULL;
  37. PULONG DnsServerList[DnsProxyCount] = { NULL, NULL };
  38. HANDLE DnsTcpipInterfacesKey = NULL;
  39. const WCHAR DnsTcpipInterfacesString[] =
  40. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
  41. L"\\Tcpip\\Parameters\\Interfaces";
  42. HANDLE DnsNotifyChangeKeyICSDomainEvent = NULL;
  43. IO_STATUS_BLOCK DnsNotifyChangeKeyICSDomainIoStatus;
  44. HANDLE DnsNotifyChangeKeyICSDomainWaitHandle = NULL;
  45. HANDLE DnsTcpipParametersKey = NULL;
  46. const WCHAR DnsTcpipParametersString[] =
  47. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
  48. L"\\Tcpip\\Parameters";
  49. const WCHAR DnsICSDomainValueName[] =
  50. L"ICSDomain";
  51. PWCHAR DnsICSDomainSuffix = NULL;
  52. //
  53. // FORWARD DECLARATIONS
  54. //
  55. VOID NTAPI
  56. DnsNotifyChangeAddressCallbackRoutine(
  57. PVOID Context,
  58. BOOLEAN TimedOut
  59. );
  60. VOID NTAPI
  61. DnspQueryTimeoutCallbackRoutine(
  62. PVOID Context,
  63. BOOLEAN TimedOut
  64. );
  65. VOID APIENTRY
  66. DnspQueryTimeoutWorkerRoutine(
  67. PVOID Context
  68. );
  69. VOID
  70. DnsReadCompletionRoutine(
  71. ULONG ErrorCode,
  72. ULONG BytesTransferred,
  73. PNH_BUFFER Bufferp
  74. );
  75. VOID
  76. DnsDeleteQuery(
  77. PDNS_INTERFACE Interfacep,
  78. PDNS_QUERY Queryp
  79. )
  80. /*++
  81. Routine Description:
  82. This routine is called to delete a pending query.
  83. Arguments:
  84. Interfacep - the query's interface
  85. Queryp - the query to be deleted
  86. Return Value:
  87. none.
  88. Environment:
  89. Invoked with 'Interfacep' locked by the caller.
  90. --*/
  91. {
  92. PROFILE("DnsDeleteQuery");
  93. if (Queryp->Bufferp) { NhReleaseBuffer(Queryp->Bufferp); }
  94. if (Queryp->TimerHandle) {
  95. //
  96. // This query is associated with a timer;
  97. // Rather than cancel the timeout-routine, we let it run,
  98. // so that it can release any references it has on the component.
  99. // When it does run, though, the routine won't find this query.
  100. //
  101. Queryp->TimerHandle = NULL;
  102. }
  103. RemoveEntryList(&Queryp->Link);
  104. NH_FREE(Queryp);
  105. } // DnsDeleteQuery
  106. BOOLEAN
  107. DnsIsPendingQuery(
  108. PDNS_INTERFACE Interfacep,
  109. PNH_BUFFER QueryBuffer
  110. )
  111. /*++
  112. Routine Description:
  113. This routine is invoked to determine whether a query is already pending
  114. for the client-request in the given buffer.
  115. The list of queries is sorted on 'QueryId', but we will be searching
  116. on 'SourceId' and 'SourceAddress' and 'SourcePort'; hence, we must do
  117. an exhaustive search of the pending-query list.
  118. Arguments:
  119. Interfacep - the interface on which to look
  120. QueryBuffer - the query to be searched for
  121. Return Value:
  122. BOOLEAN - TRUE if the query is already pending, FALSE otherwise.
  123. Environment:
  124. Invoked with 'Interfacep' locked by the caller.
  125. --*/
  126. {
  127. BOOLEAN Exists;
  128. PDNS_HEADER Headerp;
  129. PLIST_ENTRY Link;
  130. PDNS_QUERY Queryp;
  131. PROFILE("DnsIsPendingQuery");
  132. Exists = FALSE;
  133. Headerp = (PDNS_HEADER)QueryBuffer->Buffer;
  134. for (Link = Interfacep->QueryList.Flink;
  135. Link != &Interfacep->QueryList;
  136. Link = Link->Flink
  137. ) {
  138. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  139. if (Queryp->SourceId != Headerp->Xid ||
  140. Queryp->SourceAddress != QueryBuffer->ReadAddress.sin_addr.s_addr ||
  141. Queryp->SourcePort != QueryBuffer->ReadAddress.sin_port
  142. ) {
  143. continue;
  144. }
  145. Exists = TRUE;
  146. break;
  147. }
  148. return Exists;
  149. } // DnsIsPendingQuery
  150. PDNS_QUERY
  151. DnsMapResponseToQuery(
  152. PDNS_INTERFACE Interfacep,
  153. USHORT ResponseId
  154. )
  155. /*++
  156. Routine Description:
  157. This routine is invoked to map an incoming response from a DNS server
  158. to a pending query for a DNS client.
  159. Arguments:
  160. Interfacep - the interface holding the pending query, if any
  161. ResponseId - the ID in the response received from the server
  162. Return Value:
  163. PDNS_QUERY - the pending query, if any
  164. Environment:
  165. Invoked with 'Interfacep' locked by the caller.
  166. --*/
  167. {
  168. PLIST_ENTRY Link;
  169. PDNS_QUERY Queryp;
  170. PROFILE("DnsMapResponseToQuery");
  171. for (Link = Interfacep->QueryList.Flink;
  172. Link != &Interfacep->QueryList;
  173. Link = Link->Flink
  174. ) {
  175. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  176. if (ResponseId > Queryp->QueryId) {
  177. continue;
  178. } else if (ResponseId < Queryp->QueryId) {
  179. break;
  180. }
  181. return Queryp;
  182. }
  183. return NULL;
  184. } // DnsMapResponseToQuery
  185. VOID NTAPI
  186. DnsNotifyChangeAddressCallbackRoutine(
  187. PVOID Context,
  188. BOOLEAN TimedOut
  189. )
  190. /*++
  191. Routine Description:
  192. This routine is invoked to notify us of when changes occur
  193. in the (system) table that maps IP addresses to interfaces.
  194. Arguments:
  195. Context - unused
  196. TimedOut - indicates a time-out occurred
  197. Return Value:
  198. none.
  199. Environment:
  200. The routine runs in the context of an Rtl wait-thread.
  201. (See 'RtlRegisterWait'.)
  202. A reference to the component will have been made on our behalf
  203. when 'RtlRegisterWait' was called. The reference is released
  204. when the wait is cancelled, unless an error occurs here,
  205. in which case it is released immediately.
  206. --*/
  207. {
  208. ULONG Error;
  209. HANDLE UnusedTcpipHandle;
  210. PROFILE("DnsNotifyChangeAddressCallbackRoutine");
  211. EnterCriticalSection(&DnsGlobalInfoLock);
  212. if (!DnsNotifyChangeAddressEvent) {
  213. LeaveCriticalSection(&DnsGlobalInfoLock);
  214. DEREFERENCE_DNS();
  215. return;
  216. }
  217. //
  218. // Rebuild the list of DNS servers
  219. //
  220. DnsQueryServerList();
  221. //
  222. // Repost the address change-notification
  223. //
  224. ZeroMemory(&DnsNotifyChangeAddressOverlapped, sizeof(OVERLAPPED));
  225. DnsNotifyChangeAddressOverlapped.hEvent = DnsNotifyChangeAddressEvent;
  226. Error =
  227. NotifyAddrChange(
  228. &UnusedTcpipHandle,
  229. &DnsNotifyChangeAddressOverlapped
  230. );
  231. if (Error != ERROR_IO_PENDING) {
  232. if (DnsNotifyChangeAddressWaitHandle) {
  233. RtlDeregisterWait(DnsNotifyChangeAddressWaitHandle);
  234. DnsNotifyChangeAddressWaitHandle = NULL;
  235. }
  236. NtClose(DnsNotifyChangeAddressEvent);
  237. DnsNotifyChangeAddressEvent = NULL;
  238. LeaveCriticalSection(&DnsGlobalInfoLock);
  239. DEREFERENCE_DNS();
  240. NhTrace(
  241. TRACE_FLAG_DNS,
  242. "DnsNotifyChangeAddressCallbackRoutine: error %08x "
  243. "for change address",
  244. Error
  245. );
  246. NhWarningLog(
  247. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  248. Error,
  249. ""
  250. );
  251. return;
  252. }
  253. LeaveCriticalSection(&DnsGlobalInfoLock);
  254. } // DnsNotifyChangeAddressCallbackRoutine
  255. VOID NTAPI
  256. DnsNotifyChangeKeyCallbackRoutine(
  257. PVOID Context,
  258. BOOLEAN TimedOut
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is invoked to notify us of a change to the
  263. TCP/IP parameters subkey containing the DNS adapter information.
  264. Arguments:
  265. Context - unused
  266. TimedOut - indicates a time-out occurred
  267. Return Value:
  268. none.
  269. Environment:
  270. The routine runs in the context of an Rtl wait-thread.
  271. (See 'RtlRegisterWait'.)
  272. A reference to the component will have been made on our behalf
  273. when 'RtlRegisterWait' was called. The reference is released
  274. when the wait is cancelled, unless an error occurs here,
  275. in which case it is released immediately.
  276. --*/
  277. {
  278. NTSTATUS status;
  279. PROFILE("DnsNotifyChangeKeyCallbackRoutine");
  280. EnterCriticalSection(&DnsGlobalInfoLock);
  281. if (!DnsNotifyChangeKeyEvent) {
  282. LeaveCriticalSection(&DnsGlobalInfoLock);
  283. DEREFERENCE_DNS();
  284. return;
  285. }
  286. //
  287. // Rebuild the list of DNS servers
  288. //
  289. DnsQueryServerList();
  290. //
  291. // Repost the change-notification
  292. //
  293. status =
  294. NtNotifyChangeKey(
  295. DnsTcpipInterfacesKey,
  296. DnsNotifyChangeKeyEvent,
  297. NULL,
  298. NULL,
  299. &DnsNotifyChangeKeyIoStatus,
  300. REG_NOTIFY_CHANGE_LAST_SET,
  301. TRUE,
  302. NULL,
  303. 0,
  304. TRUE
  305. );
  306. if (!NT_SUCCESS(status)) {
  307. if (DnsNotifyChangeKeyWaitHandle) {
  308. RtlDeregisterWait(DnsNotifyChangeKeyWaitHandle);
  309. DnsNotifyChangeKeyWaitHandle = NULL;
  310. }
  311. NtClose(DnsNotifyChangeKeyEvent);
  312. DnsNotifyChangeKeyEvent = NULL;
  313. LeaveCriticalSection(&DnsGlobalInfoLock);
  314. NhTrace(
  315. TRACE_FLAG_DNS,
  316. "DnsNotifyChangeKeyCallbackRoutine: status %08x "
  317. "enabling change notify",
  318. status
  319. );
  320. NhWarningLog(
  321. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  322. RtlNtStatusToDosError(status),
  323. ""
  324. );
  325. DEREFERENCE_DNS();
  326. return;
  327. }
  328. LeaveCriticalSection(&DnsGlobalInfoLock);
  329. } // DnsNotifyChangeKeyCallbackRoutine
  330. VOID NTAPI
  331. DnsNotifyChangeKeyICSDomainCallbackRoutine(
  332. PVOID Context,
  333. BOOLEAN TimedOut
  334. )
  335. /*++
  336. Routine Description:
  337. This routine is invoked to notify us of a change to the TCP/IP
  338. parameters subkey containing the ICS Domain suffix string information.
  339. Arguments:
  340. Context - unused
  341. TimedOut - indicates a time-out occurred
  342. Return Value:
  343. none.
  344. Environment:
  345. The routine runs in the context of an Rtl wait-thread.
  346. (See 'RtlRegisterWait'.)
  347. A reference to the component will have been made on our behalf
  348. when 'RtlRegisterWait' was called. The reference is released
  349. when the wait is cancelled, unless an error occurs here,
  350. in which case it is released immediately.
  351. --*/
  352. {
  353. NTSTATUS status;
  354. PROFILE("DnsNotifyChangeKeyICSDomainCallbackRoutine");
  355. EnterCriticalSection(&DnsGlobalInfoLock);
  356. if (!DnsNotifyChangeKeyICSDomainEvent) {
  357. LeaveCriticalSection(&DnsGlobalInfoLock);
  358. DEREFERENCE_DNS();
  359. return;
  360. }
  361. //
  362. // Check to see if the domain string changed;
  363. // if it doesnt exist - create one.
  364. //
  365. DnsQueryICSDomainSuffix();
  366. //
  367. // Repost the change-notification
  368. //
  369. status =
  370. NtNotifyChangeKey(
  371. DnsTcpipParametersKey,
  372. DnsNotifyChangeKeyICSDomainEvent,
  373. NULL,
  374. NULL,
  375. &DnsNotifyChangeKeyICSDomainIoStatus,
  376. REG_NOTIFY_CHANGE_LAST_SET,
  377. FALSE, // not interested in the subtree
  378. NULL,
  379. 0,
  380. TRUE
  381. );
  382. if (!NT_SUCCESS(status)) {
  383. if (DnsNotifyChangeKeyICSDomainWaitHandle) {
  384. RtlDeregisterWait(DnsNotifyChangeKeyICSDomainWaitHandle);
  385. DnsNotifyChangeKeyICSDomainWaitHandle = NULL;
  386. }
  387. NtClose(DnsNotifyChangeKeyICSDomainEvent);
  388. DnsNotifyChangeKeyICSDomainEvent = NULL;
  389. LeaveCriticalSection(&DnsGlobalInfoLock);
  390. NhTrace(
  391. TRACE_FLAG_DNS,
  392. "DnsNotifyChangeKeyICSDomainCallbackRoutine: status %08x "
  393. "enabling change notify",
  394. status
  395. );
  396. NhWarningLog(
  397. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  398. RtlNtStatusToDosError(status),
  399. ""
  400. );
  401. DEREFERENCE_DNS();
  402. return;
  403. }
  404. LeaveCriticalSection(&DnsGlobalInfoLock);
  405. } // DnsNotifyChangeKeyICSDomainCallbackRoutine
  406. VOID NTAPI
  407. DnspQueryTimeoutCallbackRoutine(
  408. PVOID Context,
  409. BOOLEAN TimedOut
  410. )
  411. /*++
  412. Routine Description:
  413. This routine is called when the timeout for a query expires.
  414. We may need to resubmit the query and install a new timer,
  415. but we cannot do this in the context of an Rtl timer-routine.
  416. Therefore, queue an RTUTILS.DLL work-item to handle the timeout.
  417. Arguments:
  418. Context - holds the timer context
  419. TimedOut - unused.
  420. Return Value:
  421. none.
  422. Environment:
  423. Invoked in the context of an Rtl timer-thread with a reference made
  424. to the component on our behalf at the time 'RtlCreateTimer' was invoked.
  425. --*/
  426. {
  427. ULONG Error;
  428. PDNS_INTERFACE Interfacep;
  429. PDNS_QUERY Queryp;
  430. NTSTATUS status;
  431. PDNS_QUERY_TIMEOUT_CONTEXT TimeoutContext;
  432. PROFILE("DnspQueryTimeoutCallbackRoutine");
  433. TimeoutContext = (PDNS_QUERY_TIMEOUT_CONTEXT)Context;
  434. //
  435. // Look up the interface for the timeout
  436. //
  437. EnterCriticalSection(&DnsInterfaceLock);
  438. Interfacep = DnsLookupInterface(TimeoutContext->Index, NULL);
  439. if (!Interfacep || !DNS_REFERENCE_INTERFACE(Interfacep)) {
  440. LeaveCriticalSection(&DnsInterfaceLock);
  441. NhTrace(
  442. TRACE_FLAG_DNS,
  443. "DnspQueryTimeoutCallbackRoutine: interface %d not found",
  444. TimeoutContext->Index
  445. );
  446. NH_FREE(TimeoutContext);
  447. DEREFERENCE_DNS();
  448. return;
  449. }
  450. LeaveCriticalSection(&DnsInterfaceLock);
  451. //
  452. // Look up the query which timed out
  453. //
  454. ACQUIRE_LOCK(Interfacep);
  455. Queryp = DnsMapResponseToQuery(Interfacep, TimeoutContext->QueryId);
  456. if (!Queryp) {
  457. RELEASE_LOCK(Interfacep);
  458. DNS_DEREFERENCE_INTERFACE(Interfacep);
  459. NhTrace(
  460. TRACE_FLAG_DNS,
  461. "DnspQueryTimeoutCallbackRoutine: query %d interface %d not found",
  462. TimeoutContext->QueryId,
  463. TimeoutContext->Index
  464. );
  465. NH_FREE(TimeoutContext);
  466. DEREFERENCE_DNS();
  467. return;
  468. }
  469. Queryp->TimerHandle = NULL;
  470. //
  471. // Try to queue a work-item for the timeout;
  472. // if this succeeds, keep the reference on the component.
  473. // Otherwise, we have to drop the reference here.
  474. //
  475. status =
  476. RtlQueueWorkItem(
  477. DnspQueryTimeoutWorkerRoutine,
  478. Context,
  479. WT_EXECUTEINIOTHREAD
  480. );
  481. if (NT_SUCCESS(status)) {
  482. RELEASE_LOCK(Interfacep);
  483. DNS_DEREFERENCE_INTERFACE(Interfacep);
  484. } else {
  485. NH_FREE(TimeoutContext);
  486. NhTrace(
  487. TRACE_FLAG_DNS,
  488. "DnspQueryTimeoutCallbackRoutine: RtlQueueWorkItem=%d, aborting",
  489. status
  490. );
  491. DnsDeleteQuery(Interfacep, Queryp);
  492. RELEASE_LOCK(Interfacep);
  493. DNS_DEREFERENCE_INTERFACE(Interfacep);
  494. DEREFERENCE_DNS();
  495. }
  496. } // DnspQueryTimeoutCallbackRoutine
  497. VOID APIENTRY
  498. DnspQueryTimeoutWorkerRoutine(
  499. PVOID Context
  500. )
  501. /*++
  502. Routine Description:
  503. This routine is called when the timeout for a query expires.
  504. It is queued by the query's timer-handler.
  505. Arguments:
  506. Context - holds the timer context
  507. Return Value:
  508. none.
  509. Environment:
  510. Invoked in the context of an RTUTILS worker-thread with a reference made
  511. to the component on our behalf at the time 'RtlCreateTimer' was invoked.
  512. --*/
  513. {
  514. ULONG Error;
  515. PDNS_INTERFACE Interfacep;
  516. PDNS_QUERY Queryp;
  517. PDNS_QUERY_TIMEOUT_CONTEXT TimeoutContext;
  518. PROFILE("DnspQueryTimeoutWorkerRoutine");
  519. TimeoutContext = (PDNS_QUERY_TIMEOUT_CONTEXT)Context;
  520. //
  521. // Look up the interface for the timeout
  522. //
  523. EnterCriticalSection(&DnsInterfaceLock);
  524. Interfacep = DnsLookupInterface(TimeoutContext->Index, NULL);
  525. if (!Interfacep || !DNS_REFERENCE_INTERFACE(Interfacep)) {
  526. LeaveCriticalSection(&DnsInterfaceLock);
  527. NhTrace(
  528. TRACE_FLAG_DNS,
  529. "DnspQueryTimeoutWorkerRoutine: interface %d not found",
  530. TimeoutContext->Index
  531. );
  532. NH_FREE(TimeoutContext);
  533. DEREFERENCE_DNS();
  534. return;
  535. }
  536. LeaveCriticalSection(&DnsInterfaceLock);
  537. //
  538. // Look up the query which timed out
  539. //
  540. ACQUIRE_LOCK(Interfacep);
  541. Queryp = DnsMapResponseToQuery(Interfacep, TimeoutContext->QueryId);
  542. if (!Queryp) {
  543. RELEASE_LOCK(Interfacep);
  544. DNS_DEREFERENCE_INTERFACE(Interfacep);
  545. NhTrace(
  546. TRACE_FLAG_DNS,
  547. "DnspQueryTimeoutWorkerRoutine: query %d interface %d not found",
  548. TimeoutContext->QueryId,
  549. TimeoutContext->Index
  550. );
  551. NH_FREE(TimeoutContext);
  552. DEREFERENCE_DNS();
  553. return;
  554. }
  555. NH_FREE(TimeoutContext);
  556. //
  557. // Have 'DnsSendQuery' repost the timed-out query.
  558. // Note that we retain our reference to the interface
  559. // on behalf of the send to be initiated in 'DnsSendQuery'.
  560. //
  561. Error =
  562. DnsSendQuery(
  563. Interfacep,
  564. Queryp,
  565. TRUE
  566. );
  567. if (!Error) {
  568. RELEASE_LOCK(Interfacep);
  569. } else {
  570. DnsDeleteQuery(Interfacep, Queryp);
  571. RELEASE_LOCK(Interfacep);
  572. DNS_DEREFERENCE_INTERFACE(Interfacep);
  573. }
  574. DEREFERENCE_DNS();
  575. } // DnspQueryTimeoutWorkerRoutine
  576. ULONG
  577. DnsQueryServerList(
  578. VOID
  579. )
  580. /*++
  581. Routine Description:
  582. This routine is invoked to read the list of DNS servers from the registry.
  583. Arguments:
  584. none.
  585. Return Value:
  586. ULONG - Win32 status code.
  587. Environment:
  588. Invoked in an arbitrary context with 'DnsGlobalInfoLock' acquired
  589. by the caller.
  590. --*/
  591. {
  592. PUCHAR Buffer;
  593. ULONG Error;
  594. PKEY_VALUE_PARTIAL_INFORMATION Information;
  595. PDNS_INTERFACE Interfacep;
  596. OBJECT_ATTRIBUTES ObjectAttributes;
  597. NTSTATUS status;
  598. UNICODE_STRING UnicodeString;
  599. PROFILE("DnsQueryServerList");
  600. if (!DnsTcpipInterfacesKey) {
  601. RtlInitUnicodeString(&UnicodeString, DnsTcpipInterfacesString);
  602. InitializeObjectAttributes(
  603. &ObjectAttributes,
  604. &UnicodeString,
  605. OBJ_CASE_INSENSITIVE,
  606. NULL,
  607. NULL
  608. );
  609. //
  610. // Open the 'Tcpip\Parameters\Interfaces' registry key
  611. //
  612. status =
  613. NtOpenKey(
  614. &DnsTcpipInterfacesKey,
  615. KEY_READ,
  616. &ObjectAttributes
  617. );
  618. if (!NT_SUCCESS(status)) {
  619. Error = RtlNtStatusToDosError(status);
  620. NhTrace(
  621. TRACE_FLAG_DNS,
  622. "DnsQueryServerList: error %x opening registry key",
  623. status
  624. );
  625. NhErrorLog(
  626. IP_DNS_PROXY_LOG_NO_SERVER_LIST,
  627. Error,
  628. ""
  629. );
  630. return Error;
  631. }
  632. }
  633. //
  634. // See if we need to install change-notification,
  635. // and reference ourselves if so.
  636. // The reference is made on behalf of the change-notification routine
  637. // which will be invoked by a wait-thread when a change occurs.
  638. //
  639. if (!DnsNotifyChangeKeyEvent && REFERENCE_DNS()) {
  640. //
  641. // Attempt to set up change notification on the key
  642. //
  643. status =
  644. NtCreateEvent(
  645. &DnsNotifyChangeKeyEvent,
  646. EVENT_ALL_ACCESS,
  647. NULL,
  648. SynchronizationEvent,
  649. FALSE
  650. );
  651. if (!NT_SUCCESS(status)) {
  652. DEREFERENCE_DNS();
  653. NhTrace(
  654. TRACE_FLAG_DNS,
  655. "DnsQueryServerList: status %08x creating notify-change event",
  656. status
  657. );
  658. NhWarningLog(
  659. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  660. RtlNtStatusToDosError(status),
  661. ""
  662. );
  663. } else {
  664. //
  665. // Register a wait on the notify-change event
  666. //
  667. status =
  668. RtlRegisterWait(
  669. &DnsNotifyChangeKeyWaitHandle,
  670. DnsNotifyChangeKeyEvent,
  671. DnsNotifyChangeKeyCallbackRoutine,
  672. NULL,
  673. INFINITE,
  674. 0
  675. );
  676. if (!NT_SUCCESS(status)) {
  677. NtClose(DnsNotifyChangeKeyEvent);
  678. DnsNotifyChangeKeyEvent = NULL;
  679. DEREFERENCE_DNS();
  680. NhTrace(
  681. TRACE_FLAG_DNS,
  682. "DnsQueryServerList: status %08x registering wait",
  683. status
  684. );
  685. NhWarningLog(
  686. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  687. RtlNtStatusToDosError(status),
  688. ""
  689. );
  690. } else {
  691. //
  692. // Register for change-notification on the key
  693. //
  694. status =
  695. NtNotifyChangeKey(
  696. DnsTcpipInterfacesKey,
  697. DnsNotifyChangeKeyEvent,
  698. NULL,
  699. NULL,
  700. &DnsNotifyChangeKeyIoStatus,
  701. REG_NOTIFY_CHANGE_LAST_SET,
  702. TRUE,
  703. NULL,
  704. 0,
  705. TRUE
  706. );
  707. if (!NT_SUCCESS(status)) {
  708. RtlDeregisterWait(DnsNotifyChangeKeyWaitHandle);
  709. DnsNotifyChangeKeyWaitHandle = NULL;
  710. NtClose(DnsNotifyChangeKeyEvent);
  711. DnsNotifyChangeKeyEvent = NULL;
  712. DEREFERENCE_DNS();
  713. NhTrace(
  714. TRACE_FLAG_DNS,
  715. "DnsQueryServerList: status %08x (%08x) "
  716. "enabling change notify",
  717. status
  718. );
  719. NhWarningLog(
  720. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  721. RtlNtStatusToDosError(status),
  722. ""
  723. );
  724. }
  725. }
  726. }
  727. }
  728. //
  729. // See if we need to install address-change-notification,
  730. // and reference ourselves if so.
  731. // The reference is made on behalf of the address-change-notification
  732. // routine which will be invoked by a wait-thread when a change occurs.
  733. //
  734. if (!DnsNotifyChangeAddressEvent && REFERENCE_DNS()) {
  735. //
  736. // Attempt to set up address change notification
  737. //
  738. status =
  739. NtCreateEvent(
  740. &DnsNotifyChangeAddressEvent,
  741. EVENT_ALL_ACCESS,
  742. NULL,
  743. SynchronizationEvent,
  744. FALSE
  745. );
  746. if (!NT_SUCCESS(status)) {
  747. DEREFERENCE_DNS();
  748. NhTrace(
  749. TRACE_FLAG_DNS,
  750. "DnsQueryServerList: status %08x creating "
  751. "notify-change address event",
  752. status
  753. );
  754. NhWarningLog(
  755. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  756. RtlNtStatusToDosError(status),
  757. ""
  758. );
  759. } else {
  760. //
  761. // Register a wait on the notify-change address event
  762. //
  763. status =
  764. RtlRegisterWait(
  765. &DnsNotifyChangeAddressWaitHandle,
  766. DnsNotifyChangeAddressEvent,
  767. DnsNotifyChangeAddressCallbackRoutine,
  768. NULL,
  769. INFINITE,
  770. 0
  771. );
  772. if (!NT_SUCCESS(status)) {
  773. NtClose(DnsNotifyChangeAddressEvent);
  774. DnsNotifyChangeAddressEvent = NULL;
  775. DEREFERENCE_DNS();
  776. NhTrace(
  777. TRACE_FLAG_DNS,
  778. "DnsQueryServerList: status %08x registering wait"
  779. "for change address",
  780. status
  781. );
  782. NhWarningLog(
  783. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  784. RtlNtStatusToDosError(status),
  785. ""
  786. );
  787. } else {
  788. HANDLE UnusedTcpipHandle;
  789. //
  790. // Register for change-notification
  791. //
  792. ZeroMemory(
  793. &DnsNotifyChangeAddressOverlapped,
  794. sizeof(OVERLAPPED)
  795. );
  796. DnsNotifyChangeAddressOverlapped.hEvent =
  797. DnsNotifyChangeAddressEvent;
  798. Error =
  799. NotifyAddrChange(
  800. &UnusedTcpipHandle,
  801. &DnsNotifyChangeAddressOverlapped
  802. );
  803. if (Error != ERROR_IO_PENDING) {
  804. RtlDeregisterWait(DnsNotifyChangeAddressWaitHandle);
  805. DnsNotifyChangeAddressWaitHandle = NULL;
  806. NtClose(DnsNotifyChangeAddressEvent);
  807. DnsNotifyChangeAddressEvent = NULL;
  808. DEREFERENCE_DNS();
  809. NhTrace(
  810. TRACE_FLAG_DNS,
  811. "DnsQueryServerList: error %08x"
  812. "for change address",
  813. Error
  814. );
  815. NhWarningLog(
  816. IP_DNS_PROXY_LOG_CHANGE_NOTIFY_FAILED,
  817. Error,
  818. ""
  819. );
  820. }
  821. }
  822. }
  823. }
  824. {
  825. PIP_ADAPTER_INFO AdapterInfo;
  826. PIP_ADAPTER_INFO AdaptersInfo = NULL;
  827. ULONG Address;
  828. PIP_ADDR_STRING AddrString;
  829. ULONG dnsLength = 0;
  830. PULONG dnsServerList = NULL;
  831. PFIXED_INFO FixedInfo = NULL;
  832. LONG i;
  833. ULONG Length;
  834. PIP_PER_ADAPTER_INFO PerAdapterInfo;
  835. ULONG tempLength;
  836. PULONG tempServerList;
  837. ULONG winsLength;
  838. PULONG winsServerList = NULL;
  839. //
  840. // Read the DNS and WINS server lists.
  841. // 'GetAdaptersInfo' provides the WINS servers for each adapter,
  842. // while 'GetPerAdapterInfo' provides the DNS servers for each adapter.
  843. // While 'GetAdaptersInfo' returns an array of all adapters,
  844. // 'GetPerAdapterInfo' must be invoked for each individual adapter.
  845. // Hence we begin with 'GetAdaptersInfo', and enumerate each adapter
  846. // building the WINS and DNS server lists in parallel.
  847. //
  848. do {
  849. //
  850. // Retrieve the size of the adapter list
  851. //
  852. Length = 0;
  853. Error = GetAdaptersInfo(NULL, &Length);
  854. if (!Error) {
  855. break;
  856. } else if (Error != ERROR_BUFFER_OVERFLOW) {
  857. NhTrace(
  858. TRACE_FLAG_DNS,
  859. "DnsQueryServerList: GetAdaptersInfo=%d",
  860. Error
  861. );
  862. NhErrorLog(
  863. IP_DNS_PROXY_LOG_ERROR_SERVER_LIST,
  864. Error,
  865. ""
  866. );
  867. break;
  868. }
  869. //
  870. // Allocate a buffer to hold the list
  871. //
  872. AdaptersInfo = (PIP_ADAPTER_INFO)NH_ALLOCATE(Length);
  873. if (!AdaptersInfo) {
  874. NhTrace(
  875. TRACE_FLAG_DNS,
  876. "DnsQueryServerList: error allocating %d bytes",
  877. Length
  878. );
  879. NhErrorLog(
  880. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  881. 0,
  882. "%d",
  883. Length
  884. );
  885. break;
  886. }
  887. //
  888. // Retrieve the list
  889. //
  890. Error = GetAdaptersInfo(AdaptersInfo, &Length);
  891. if (Error) {
  892. NhTrace(
  893. TRACE_FLAG_DNS,
  894. "DnsQueryServerList: GetAdaptersInfo=%d",
  895. Error
  896. );
  897. NhErrorLog(
  898. IP_DNS_PROXY_LOG_NO_SERVER_LIST,
  899. Error,
  900. ""
  901. );
  902. break;
  903. }
  904. //
  905. // Count the WINS servers
  906. //
  907. for (AdapterInfo = AdaptersInfo, winsLength = 1;
  908. AdapterInfo;
  909. AdapterInfo = AdapterInfo->Next
  910. ) {
  911. Address =
  912. inet_addr(AdapterInfo->PrimaryWinsServer.IpAddress.String);
  913. if (Address != INADDR_ANY && Address != INADDR_NONE) {
  914. ++winsLength;
  915. }
  916. Address =
  917. inet_addr(AdapterInfo->SecondaryWinsServer.IpAddress.String);
  918. if (Address != INADDR_ANY && Address != INADDR_NONE) {
  919. ++winsLength;
  920. }
  921. }
  922. //
  923. // Allocate space for the WINS servers
  924. //
  925. winsServerList = (PULONG)NH_ALLOCATE(winsLength * sizeof(ULONG));
  926. if (!winsServerList) {
  927. NhTrace(
  928. TRACE_FLAG_DNS,
  929. "DnsQueryServerList: error allocating %d-byte WINS server list",
  930. winsLength * sizeof(ULONG)
  931. );
  932. NhErrorLog(
  933. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  934. 0,
  935. "%d",
  936. winsLength * sizeof(ULONG)
  937. );
  938. break;
  939. }
  940. //
  941. // Now fill in the WINS server names from each adapter.
  942. // In the process, we pick up the DNS server lists for each adapter.
  943. //
  944. for (AdapterInfo = AdaptersInfo, Length = 0;
  945. AdapterInfo;
  946. AdapterInfo = AdapterInfo->Next
  947. ) {
  948. Address =
  949. inet_addr(AdapterInfo->PrimaryWinsServer.IpAddress.String);
  950. if (Address != INADDR_ANY && Address != INADDR_NONE) {
  951. for (i = 0; i < (LONG)Length; i++) {
  952. if (Address == winsServerList[i]) { break; }
  953. }
  954. if (i >= (LONG)Length) { winsServerList[Length++] = Address; }
  955. }
  956. Address =
  957. inet_addr(AdapterInfo->SecondaryWinsServer.IpAddress.String);
  958. if (Address != INADDR_ANY && Address != INADDR_NONE) {
  959. for (i = 0; i < (LONG)Length; i++) {
  960. if (Address == winsServerList[i]) { break; }
  961. }
  962. if (i >= (LONG)Length) { winsServerList[Length++] = Address; }
  963. }
  964. //
  965. // Now obtain the DNS servers for the adapter.
  966. //
  967. Error = GetPerAdapterInfo(AdapterInfo->Index, NULL, &tempLength);
  968. if (Error != ERROR_BUFFER_OVERFLOW) { continue; }
  969. //
  970. // Allocate memory for the per-adapter info
  971. //
  972. PerAdapterInfo =
  973. reinterpret_cast<PIP_PER_ADAPTER_INFO>(
  974. NH_ALLOCATE(tempLength)
  975. );
  976. if (!PerAdapterInfo) {
  977. NhTrace(
  978. TRACE_FLAG_DNS,
  979. "DnsQueryServerList: error allocating %d bytes",
  980. tempLength
  981. );
  982. NhErrorLog(
  983. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  984. 0,
  985. "%d",
  986. tempLength
  987. );
  988. continue;
  989. }
  990. //
  991. // Retrieve the per-adapter info
  992. //
  993. Error =
  994. GetPerAdapterInfo(
  995. AdapterInfo->Index,
  996. PerAdapterInfo,
  997. &tempLength
  998. );
  999. if (Error) {
  1000. NH_FREE(PerAdapterInfo);
  1001. NhTrace(
  1002. TRACE_FLAG_DNS,
  1003. "DnsQueryServerList: GetPerAdapterInfo=%d",
  1004. Error
  1005. );
  1006. NhErrorLog(
  1007. IP_DNS_PROXY_LOG_NO_SERVER_LIST,
  1008. Error,
  1009. ""
  1010. );
  1011. continue;
  1012. }
  1013. //
  1014. // Count the DNS servers for the adapter
  1015. //
  1016. for (AddrString = &PerAdapterInfo->DnsServerList, tempLength = 0;
  1017. AddrString;
  1018. AddrString = AddrString->Next
  1019. ) {
  1020. Address = inet_addr(AddrString->IpAddress.String);
  1021. if (Address != INADDR_ANY && Address != INADDR_NONE) {
  1022. ++tempLength;
  1023. }
  1024. }
  1025. if (!tempLength) { NH_FREE(PerAdapterInfo); continue; }
  1026. //
  1027. // Allocate space for the adapter's DNS servers
  1028. //
  1029. tempServerList =
  1030. reinterpret_cast<PULONG>(
  1031. NH_ALLOCATE((dnsLength + tempLength + 1) * sizeof(ULONG))
  1032. );
  1033. if (!tempServerList) {
  1034. NH_FREE(PerAdapterInfo);
  1035. NhTrace(
  1036. TRACE_FLAG_DNS,
  1037. "DnsQueryServerList: error allocating %d bytes",
  1038. (dnsLength + tempLength + 1) * sizeof(ULONG)
  1039. );
  1040. NhErrorLog(
  1041. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  1042. 0,
  1043. "%d",
  1044. (dnsLength + tempLength + 1) * sizeof(ULONG)
  1045. );
  1046. continue;
  1047. }
  1048. //
  1049. // Copy the existing servers
  1050. //
  1051. if (dnsServerList) {
  1052. CopyMemory(
  1053. tempServerList,
  1054. dnsServerList,
  1055. dnsLength * sizeof(ULONG)
  1056. );
  1057. }
  1058. //
  1059. // Read the new servers into the new server list
  1060. //
  1061. for (AddrString = &PerAdapterInfo->DnsServerList;
  1062. AddrString;
  1063. AddrString = AddrString->Next
  1064. ) {
  1065. Address = inet_addr(AddrString->IpAddress.String);
  1066. if (Address == INADDR_ANY || Address == INADDR_NONE) {
  1067. continue;
  1068. }
  1069. for (i = 0; i < (LONG)dnsLength; i++) {
  1070. if (Address == tempServerList[i]) { break; }
  1071. }
  1072. if (i < (LONG)dnsLength) { continue; }
  1073. //
  1074. // The current DNS server goes in the front of the list,
  1075. // while any other server is appended.
  1076. //
  1077. if (PerAdapterInfo->CurrentDnsServer != AddrString) {
  1078. tempServerList[dnsLength] = Address;
  1079. } else {
  1080. MoveMemory(
  1081. tempServerList + sizeof(ULONG),
  1082. tempServerList,
  1083. dnsLength * sizeof(ULONG)
  1084. );
  1085. tempServerList[0] = Address;
  1086. }
  1087. ++dnsLength;
  1088. }
  1089. tempServerList[dnsLength] = 0;
  1090. NH_FREE(PerAdapterInfo);
  1091. //
  1092. // Replace the existing server list
  1093. //
  1094. if (dnsServerList) { NH_FREE(dnsServerList); }
  1095. dnsServerList = tempServerList;
  1096. }
  1097. winsServerList[Length] = 0;
  1098. } while(FALSE);
  1099. if (AdaptersInfo) { NH_FREE(AdaptersInfo); }
  1100. //
  1101. // Store the new server lists
  1102. //
  1103. NhTrace(
  1104. TRACE_FLAG_DNS,
  1105. "DnsQueryServerList: new server list lengths are : DNS (%d) WINS (%d)",
  1106. dnsLength,
  1107. Length
  1108. );
  1109. if (DnsServerList[DnsProxyDns]) { NH_FREE(DnsServerList[DnsProxyDns]); }
  1110. DnsServerList[DnsProxyDns] = dnsServerList;
  1111. if (DnsServerList[DnsProxyWins]) { NH_FREE(DnsServerList[DnsProxyWins]); }
  1112. DnsServerList[DnsProxyWins] = winsServerList;
  1113. }
  1114. return NO_ERROR;
  1115. } // DnsQueryServerList
  1116. VOID
  1117. DnsQueryRegistryICSDomainSuffix(
  1118. VOID
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This routine is invoked to read the ICS Domain suffix from the registry.
  1123. Arguments:
  1124. none.
  1125. Return Value:
  1126. VOID.
  1127. Environment:
  1128. Invoked in an arbitrary context with 'DnsGlobalInfoLock' acquired
  1129. by the caller.
  1130. --*/
  1131. {
  1132. NTSTATUS status;
  1133. PKEY_VALUE_PARTIAL_INFORMATION Information = NULL;
  1134. DWORD dwSize = 0;
  1135. LPVOID lpMsgBuf;
  1136. BOOL fSuffixChanged = FALSE;
  1137. BOOL fUseDefaultSuffix = FALSE;
  1138. //
  1139. // retrieve current suffix string (if any)
  1140. //
  1141. status =
  1142. NhQueryValueKey(
  1143. DnsTcpipParametersKey,
  1144. DnsICSDomainValueName,
  1145. &Information
  1146. );
  1147. if (!NT_SUCCESS(status) || !Information)
  1148. {
  1149. NhTrace(
  1150. TRACE_FLAG_DNS,
  1151. "DnsQueryRegistryICSDomainSuffix: error (0x%08x) querying "
  1152. "ICS Domain suffix name",
  1153. status
  1154. );
  1155. //
  1156. // if we did not find it in the registry and we had previously
  1157. // got some suffix - we revert to default string (happens below)
  1158. //
  1159. if ((STATUS_OBJECT_NAME_NOT_FOUND == status) && DnsICSDomainSuffix)
  1160. {
  1161. NH_FREE(DnsICSDomainSuffix);
  1162. DnsICSDomainSuffix = NULL;
  1163. }
  1164. //
  1165. // if we have no idea of the string, set our copy to default string
  1166. //
  1167. if (NULL == DnsICSDomainSuffix)
  1168. {
  1169. dwSize = wcslen(DNS_HOMENET_SUFFIX) + 1;
  1170. DnsICSDomainSuffix = reinterpret_cast<PWCHAR>(
  1171. NH_ALLOCATE(sizeof(WCHAR) * dwSize)
  1172. );
  1173. if (!DnsICSDomainSuffix)
  1174. {
  1175. NhTrace(
  1176. TRACE_FLAG_DNS,
  1177. "DnsQueryRegistryICSDomainSuffix: allocation "
  1178. "failed for DnsICSDomainSuffix"
  1179. );
  1180. return;
  1181. }
  1182. wcscpy(DnsICSDomainSuffix, DNS_HOMENET_SUFFIX);
  1183. fSuffixChanged = TRUE;
  1184. }
  1185. }
  1186. else
  1187. {
  1188. //
  1189. // check to see that what we read is a null terminated string
  1190. //
  1191. if (REG_SZ != Information->Type
  1192. || L'\0' != *(PWCHAR) (Information->Data +
  1193. (Information->DataLength - sizeof(WCHAR)))) {
  1194. NH_FREE(Information);
  1195. NhTrace(
  1196. TRACE_FLAG_REG,
  1197. "DnsQueryRegistryICSDomainSuffix: Registry contains invalid data"
  1198. );
  1199. return;
  1200. }
  1201. //
  1202. // overwrite our current version of suffix string
  1203. //
  1204. dwSize = lstrlenW((PWCHAR)Information->Data);
  1205. if (dwSize)
  1206. {
  1207. //
  1208. // we have a nonzero string
  1209. //
  1210. dwSize++; // add 1 for terminating null
  1211. }
  1212. else
  1213. {
  1214. //
  1215. // the data is a null string - use default suffix
  1216. //
  1217. dwSize = wcslen(DNS_HOMENET_SUFFIX) + 1;
  1218. fUseDefaultSuffix = TRUE;
  1219. }
  1220. if (DnsICSDomainSuffix)
  1221. {
  1222. NH_FREE(DnsICSDomainSuffix);
  1223. DnsICSDomainSuffix = NULL;
  1224. }
  1225. DnsICSDomainSuffix = reinterpret_cast<PWCHAR>(
  1226. NH_ALLOCATE(sizeof(WCHAR) * dwSize)
  1227. );
  1228. if (!DnsICSDomainSuffix)
  1229. {
  1230. NH_FREE(Information);
  1231. NhTrace(
  1232. TRACE_FLAG_DNS,
  1233. "DnsQueryRegistryICSDomainSuffix: allocation "
  1234. "failed for DnsICSDomainSuffix"
  1235. );
  1236. return;
  1237. }
  1238. if (!fUseDefaultSuffix)
  1239. {
  1240. wcscpy(DnsICSDomainSuffix, (PWCHAR) Information->Data);
  1241. }
  1242. else
  1243. {
  1244. wcscpy(DnsICSDomainSuffix, DNS_HOMENET_SUFFIX);
  1245. }
  1246. fSuffixChanged = TRUE;
  1247. NH_FREE(Information);
  1248. }
  1249. if (fSuffixChanged)
  1250. {
  1251. //
  1252. // enumerate existing entries and replace old ones
  1253. // + we must do this because otherwise forward and reverse lookups
  1254. // are dependent on the way in which the entries are ordered in
  1255. // the hosts.ics file
  1256. //
  1257. //DnsReplaceOnSuffixChange();
  1258. }
  1259. } // DnsQueryRegistryICSDomainSuffix
  1260. ULONG
  1261. DnsQueryICSDomainSuffix(
  1262. VOID
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. This routine invokes DnsQueryRegistryICSDomainSuffix and installs
  1267. change notification for this reg key if necessary.
  1268. Arguments:
  1269. none.
  1270. Return Value:
  1271. ULONG - Win32 status code.
  1272. Environment:
  1273. Invoked in an arbitrary context with 'DnsGlobalInfoLock' acquired
  1274. by the caller.
  1275. --*/
  1276. {
  1277. PUCHAR Buffer;
  1278. ULONG Error;
  1279. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1280. OBJECT_ATTRIBUTES ObjectAttributes;
  1281. NTSTATUS status;
  1282. UNICODE_STRING UnicodeString;
  1283. PROFILE("DnsQueryICSDomainSuffix");
  1284. if (!DnsTcpipParametersKey)
  1285. {
  1286. RtlInitUnicodeString(&UnicodeString, DnsTcpipParametersString);
  1287. InitializeObjectAttributes(
  1288. &ObjectAttributes,
  1289. &UnicodeString,
  1290. OBJ_CASE_INSENSITIVE,
  1291. NULL,
  1292. NULL
  1293. );
  1294. //
  1295. // Open the 'Tcpip\Parameters' registry key
  1296. //
  1297. status =
  1298. NtOpenKey(
  1299. &DnsTcpipParametersKey,
  1300. KEY_READ,
  1301. &ObjectAttributes
  1302. );
  1303. if (!NT_SUCCESS(status))
  1304. {
  1305. Error = RtlNtStatusToDosError(status);
  1306. NhTrace(
  1307. TRACE_FLAG_DNS,
  1308. "DnsQueryICSDomainSuffix: error %x opening registry key",
  1309. status
  1310. );
  1311. NhErrorLog(
  1312. IP_DNS_PROXY_LOG_NO_ICSD_SUFFIX,
  1313. Error,
  1314. ""
  1315. );
  1316. return Error;
  1317. }
  1318. }
  1319. //
  1320. // See if we need to install change-notification,
  1321. // and reference ourselves if so.
  1322. // The reference is made on behalf of the change-notification routine
  1323. // which will be invoked by a wait-thread when a change occurs.
  1324. //
  1325. if (!DnsNotifyChangeKeyICSDomainEvent && REFERENCE_DNS())
  1326. {
  1327. //
  1328. // Attempt to set up change notification on the key
  1329. //
  1330. status =
  1331. NtCreateEvent(
  1332. &DnsNotifyChangeKeyICSDomainEvent,
  1333. EVENT_ALL_ACCESS,
  1334. NULL,
  1335. SynchronizationEvent,
  1336. FALSE
  1337. );
  1338. if (!NT_SUCCESS(status)) {
  1339. DEREFERENCE_DNS();
  1340. NhTrace(
  1341. TRACE_FLAG_DNS,
  1342. "DnsQueryICSDomainSuffix: status %08x creating notify-change event",
  1343. status
  1344. );
  1345. NhWarningLog(
  1346. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1347. RtlNtStatusToDosError(status),
  1348. ""
  1349. );
  1350. }
  1351. else
  1352. {
  1353. //
  1354. // Register a wait on the notify-change event
  1355. //
  1356. status =
  1357. RtlRegisterWait(
  1358. &DnsNotifyChangeKeyICSDomainWaitHandle,
  1359. DnsNotifyChangeKeyICSDomainEvent,
  1360. DnsNotifyChangeKeyICSDomainCallbackRoutine,
  1361. NULL,
  1362. INFINITE,
  1363. 0
  1364. );
  1365. if (!NT_SUCCESS(status))
  1366. {
  1367. NtClose(DnsNotifyChangeKeyICSDomainEvent);
  1368. DnsNotifyChangeKeyICSDomainEvent = NULL;
  1369. DEREFERENCE_DNS();
  1370. NhTrace(
  1371. TRACE_FLAG_DNS,
  1372. "DnsQueryICSDomainSuffix: status %08x registering wait",
  1373. status
  1374. );
  1375. NhWarningLog(
  1376. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1377. RtlNtStatusToDosError(status),
  1378. ""
  1379. );
  1380. }
  1381. else
  1382. {
  1383. //
  1384. // Register for change-notification on the key
  1385. //
  1386. status =
  1387. NtNotifyChangeKey(
  1388. DnsTcpipParametersKey,
  1389. DnsNotifyChangeKeyICSDomainEvent,
  1390. NULL,
  1391. NULL,
  1392. &DnsNotifyChangeKeyICSDomainIoStatus,
  1393. REG_NOTIFY_CHANGE_LAST_SET,
  1394. FALSE, // not interested in the subtree
  1395. NULL,
  1396. 0,
  1397. TRUE
  1398. );
  1399. if (!NT_SUCCESS(status))
  1400. {
  1401. RtlDeregisterWait(DnsNotifyChangeKeyICSDomainWaitHandle);
  1402. DnsNotifyChangeKeyICSDomainWaitHandle = NULL;
  1403. NtClose(DnsNotifyChangeKeyICSDomainEvent);
  1404. DnsNotifyChangeKeyICSDomainEvent = NULL;
  1405. DEREFERENCE_DNS();
  1406. NhTrace(
  1407. TRACE_FLAG_DNS,
  1408. "DnsQueryICSDomainSuffix: status %08x (%08x) "
  1409. "enabling change notify",
  1410. status
  1411. );
  1412. NhWarningLog(
  1413. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1414. RtlNtStatusToDosError(status),
  1415. ""
  1416. );
  1417. }
  1418. }
  1419. }
  1420. }
  1421. DnsQueryRegistryICSDomainSuffix();
  1422. return NO_ERROR;
  1423. } // DnsQueryICSDomainSuffix
  1424. PDNS_QUERY
  1425. DnsRecordQuery(
  1426. PDNS_INTERFACE Interfacep,
  1427. PNH_BUFFER QueryBuffer
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine is invoked to create a pending-query entry for a client's
  1432. DNS query.
  1433. Arguments:
  1434. Interfacep - the interface on which to create the record
  1435. QueryBuffer - the DNS request for which to create a record
  1436. Return Value:
  1437. PDNS_QUERY - the pending query if created
  1438. Environment:
  1439. Invoked with 'Interfacep' locked by the caller.
  1440. --*/
  1441. {
  1442. BOOLEAN ConflictFound;
  1443. PDNS_HEADER Headerp;
  1444. PLIST_ENTRY Link;
  1445. USHORT QueryId;
  1446. PDNS_QUERY Queryp;
  1447. ULONG RetryCount = MAXCHAR;
  1448. ULONG Seed = GetTickCount();
  1449. PROFILE("DnsRecordQuery");
  1450. //
  1451. // Attempt to generate a random ID for the query.
  1452. // Assuming we succeed, we leave the loop with 'Link'
  1453. // set to the correct insertion-point for the new query.
  1454. //
  1455. do {
  1456. QueryId = (USHORT)((RtlRandom(&Seed) & 0xffff0000) >> 16);
  1457. ConflictFound = FALSE;
  1458. for (Link = Interfacep->QueryList.Flink; Link != &Interfacep->QueryList;
  1459. Link = Link->Flink) {
  1460. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  1461. if (QueryId > Queryp->QueryId) {
  1462. continue;
  1463. } else if (QueryId < Queryp->QueryId) {
  1464. break;
  1465. }
  1466. ConflictFound = TRUE;
  1467. break;
  1468. }
  1469. } while(ConflictFound && --RetryCount);
  1470. if (ConflictFound) { return NULL; }
  1471. //
  1472. // Allocate and initialize the new query
  1473. //
  1474. Queryp = reinterpret_cast<PDNS_QUERY>(NH_ALLOCATE(sizeof(DNS_QUERY)));
  1475. if (!Queryp) {
  1476. NhTrace(
  1477. TRACE_FLAG_DNS,
  1478. "DnsRecordQuery: allocation failed for DNS query"
  1479. );
  1480. NhErrorLog(
  1481. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  1482. 0,
  1483. "%d",
  1484. sizeof(DNS_QUERY)
  1485. );
  1486. return NULL;
  1487. }
  1488. Headerp = (PDNS_HEADER)QueryBuffer->Buffer;
  1489. Queryp->QueryId = QueryId;
  1490. Queryp->SourceId = Headerp->Xid;
  1491. Queryp->SourceAddress = QueryBuffer->ReadAddress.sin_addr.s_addr;
  1492. Queryp->SourcePort = QueryBuffer->ReadAddress.sin_port;
  1493. Queryp->Type =
  1494. DNS_PROXY_PORT_TO_TYPE(NhQueryPortSocket(QueryBuffer->Socket));
  1495. Queryp->QueryLength = QueryBuffer->BytesTransferred;
  1496. Queryp->Bufferp = QueryBuffer;
  1497. Queryp->Interfacep = Interfacep;
  1498. Queryp->TimerHandle = NULL;
  1499. Queryp->RetryCount = 0;
  1500. //
  1501. // Insert the new query in the location determined above.
  1502. //
  1503. InsertTailList(Link, &Queryp->Link);
  1504. return Queryp;
  1505. } // DnsRecordQuery
  1506. ULONG
  1507. DnsSendQuery(
  1508. PDNS_INTERFACE Interfacep,
  1509. PDNS_QUERY Queryp,
  1510. BOOLEAN Resend
  1511. )
  1512. /*++
  1513. Routine Description:
  1514. This routine is invoked to forward a query to our DNS servers.
  1515. Arguments:
  1516. Interfacep - the interface on which to send the query
  1517. Queryp - the DNS request to be sent
  1518. Resend - if TRUE, the buffer is being resent; otherwise, the buffer
  1519. is being sent for the first time.
  1520. Return Value:
  1521. ULONG - Win32 status code.
  1522. On success, 'Queryp' may have been deleted.
  1523. Environment:
  1524. Invoked with 'Interfacep' locked by the caller, and with a reference made
  1525. to it for the send which occurs here.
  1526. If the routine fails, it is the caller's responsibility to release that
  1527. reference.
  1528. --*/
  1529. {
  1530. PNH_BUFFER Bufferp;
  1531. ULONG Error;
  1532. ULONG i, j;
  1533. PULONG ServerList;
  1534. SOCKET Socket;
  1535. NTSTATUS status;
  1536. PDNS_QUERY_TIMEOUT_CONTEXT TimeoutContext;
  1537. ULONG TimeoutSeconds;
  1538. PROFILE("DnsSendQuery");
  1539. //
  1540. // For WINS queries, we use a global socket to work around the fact that
  1541. // even though we're bound to the WINS port, responses will only be
  1542. // delivered to the first socket bound to the socket, which is
  1543. // the kernel-mode NetBT driver.
  1544. //
  1545. EnterCriticalSection(&DnsGlobalInfoLock);
  1546. if (Queryp->Type == DnsProxyDns) {
  1547. Socket = Queryp->Bufferp->Socket;
  1548. ServerList = DnsServerList[DnsProxyDns];
  1549. } else {
  1550. Socket = DnsGlobalSocket;
  1551. ServerList = DnsServerList[DnsProxyWins];
  1552. }
  1553. LeaveCriticalSection(&DnsGlobalInfoLock);
  1554. //
  1555. // See if there are any servers to be tried.
  1556. //
  1557. if (!ServerList ||
  1558. !ServerList[0] ||
  1559. Queryp->RetryCount++ > DNS_QUERY_RETRY) {
  1560. if (!ServerList) {
  1561. NhTrace(
  1562. TRACE_FLAG_DNS,
  1563. "DnsSendQuery: no server list"
  1564. );
  1565. }
  1566. else if (!ServerList[0]) {
  1567. NhTrace(
  1568. TRACE_FLAG_DNS,
  1569. "DnsSendQuery: no server entries in list"
  1570. );
  1571. }
  1572. else {
  1573. NhTrace(
  1574. TRACE_FLAG_DNS,
  1575. "DnsSendQuery: retry count for query %d "
  1576. "greater than DNS_QUERY_RETRY(%d)",
  1577. Queryp->QueryId,
  1578. DNS_QUERY_RETRY
  1579. );
  1580. }
  1581. if (REFERENCE_DNS()) {
  1582. //
  1583. // Initiate an attempt to connect the default interface, if any.
  1584. //
  1585. status =
  1586. RtlQueueWorkItem(
  1587. DnsConnectDefaultInterface,
  1588. NULL,
  1589. WT_EXECUTEINIOTHREAD
  1590. );
  1591. if (!NT_SUCCESS(status)) { DEREFERENCE_DNS(); }
  1592. }
  1593. NhInformationLog(
  1594. IP_DNS_PROXY_LOG_NO_SERVERS_LEFT,
  1595. 0,
  1596. "%I",
  1597. Queryp->SourceAddress
  1598. );
  1599. return ERROR_NO_MORE_ITEMS;
  1600. }
  1601. //
  1602. // Send the query to each server on the list
  1603. //
  1604. for (i = 0; ServerList[i]; i++) {
  1605. for (j = 0; j < Interfacep->BindingCount; j++) {
  1606. if (Interfacep->BindingArray[j].Address == ServerList[i]) {
  1607. break;
  1608. }
  1609. }
  1610. if (j < Interfacep->BindingCount) {
  1611. NhTrace(
  1612. TRACE_FLAG_DNS,
  1613. "DnsSendQuery: server %s is self, ignoring",
  1614. INET_NTOA(ServerList[i])
  1615. );
  1616. continue;
  1617. }
  1618. if (!DNS_REFERENCE_INTERFACE(Interfacep) ||
  1619. !(Bufferp = NhDuplicateBuffer(Queryp->Bufferp))) {
  1620. continue;
  1621. }
  1622. NhTrace(
  1623. TRACE_FLAG_DNS,
  1624. "DnsSendQuery: sending query %d interface %d to %s",
  1625. (PVOID)((PDNS_HEADER)Bufferp->Buffer)->Xid,
  1626. Interfacep->Index,
  1627. INET_NTOA(ServerList[i])
  1628. );
  1629. //
  1630. // Send the message
  1631. //
  1632. Error =
  1633. NhWriteDatagramSocket(
  1634. &DnsComponentReference,
  1635. Socket,
  1636. ServerList[i],
  1637. DNS_PROXY_TYPE_TO_PORT(Queryp->Type),
  1638. Bufferp,
  1639. Queryp->QueryLength,
  1640. DnsWriteCompletionRoutine,
  1641. Interfacep,
  1642. (PVOID)Queryp->QueryId
  1643. );
  1644. if (!Error) {
  1645. InterlockedIncrement(
  1646. reinterpret_cast<LPLONG>(&DnsStatistics.QueriesSent)
  1647. );
  1648. } else {
  1649. NhTrace(
  1650. TRACE_FLAG_DNS,
  1651. "DnsSendQuery: error %d sending query %d interface %d",
  1652. Error,
  1653. Queryp->QueryId,
  1654. Interfacep->Index
  1655. );
  1656. NhErrorLog(
  1657. IP_DNS_PROXY_LOG_QUERY_FAILED,
  1658. Error,
  1659. "%I%I%I",
  1660. Queryp->SourceAddress,
  1661. ServerList[i],
  1662. NhQueryAddressSocket(Bufferp->Socket)
  1663. );
  1664. Error = NO_ERROR;
  1665. NhReleaseBuffer(Bufferp);
  1666. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1667. }
  1668. }
  1669. //
  1670. // Set up the query's timeout.
  1671. // Note that we are now certain that the write-completion routine
  1672. // will be executed. However, if the timeout cannot be set,
  1673. // we want to be assured that the query will still be deleted.
  1674. // Therefore, on failure we delete the query immediately,
  1675. // and the write-completion routine will simply not find it.
  1676. //
  1677. status = STATUS_UNSUCCESSFUL;
  1678. EnterCriticalSection(&DnsGlobalInfoLock);
  1679. TimeoutSeconds = DnsGlobalInfo->TimeoutSeconds;
  1680. LeaveCriticalSection(&DnsGlobalInfoLock);
  1681. if (Queryp->TimerHandle) {
  1682. //
  1683. // Update the timer-queue entry for the query
  1684. //
  1685. status =
  1686. NhUpdateTimer(
  1687. Queryp->TimerHandle,
  1688. TimeoutSeconds * 1000
  1689. );
  1690. } else {
  1691. //
  1692. // Allocate a timer-queue entry context block
  1693. //
  1694. TimeoutContext = reinterpret_cast<PDNS_QUERY_TIMEOUT_CONTEXT>(
  1695. NH_ALLOCATE(sizeof(*TimeoutContext))
  1696. );
  1697. if (!TimeoutContext) {
  1698. NhTrace(
  1699. TRACE_FLAG_DNS,
  1700. "DnsSendQuery: error allocating query %d timeout context",
  1701. Queryp->QueryId
  1702. );
  1703. status = STATUS_UNSUCCESSFUL;
  1704. } else {
  1705. TimeoutContext->Index = Interfacep->Index;
  1706. TimeoutContext->QueryId = Queryp->QueryId;
  1707. //
  1708. // Insert a timer-queue entry to check the status of the query
  1709. //
  1710. status =
  1711. NhSetTimer(
  1712. &DnsComponentReference,
  1713. &Queryp->TimerHandle,
  1714. DnspQueryTimeoutCallbackRoutine,
  1715. TimeoutContext,
  1716. TimeoutSeconds * 1000
  1717. );
  1718. if (!NT_SUCCESS(status)) {
  1719. NH_FREE(TimeoutContext);
  1720. Queryp->TimerHandle = NULL;
  1721. }
  1722. }
  1723. }
  1724. //
  1725. // If the above failed, delete the query now.
  1726. //
  1727. if (!NT_SUCCESS(status)) {
  1728. NhTrace(
  1729. TRACE_FLAG_DNS,
  1730. "DnsSendQuery: status %08x setting timer for query %d",
  1731. status,
  1732. Queryp->QueryId
  1733. );
  1734. DnsDeleteQuery(Interfacep, Queryp);
  1735. }
  1736. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1737. return NO_ERROR;
  1738. } // DnsSendQuery