Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2157 lines
54 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_ALL_ACCESS,
  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. if (inet_addr(AdapterInfo->PrimaryWinsServer.IpAddress.String)) {
  912. ++winsLength;
  913. }
  914. if (inet_addr(AdapterInfo->SecondaryWinsServer.IpAddress.String)) {
  915. ++winsLength;
  916. }
  917. }
  918. //
  919. // Allocate space for the WINS servers
  920. //
  921. winsServerList = (PULONG)NH_ALLOCATE(winsLength * sizeof(ULONG));
  922. if (!winsServerList) {
  923. NhTrace(
  924. TRACE_FLAG_DNS,
  925. "DnsQueryServerList: error allocating %d-byte WINS server list",
  926. winsLength * sizeof(ULONG)
  927. );
  928. NhErrorLog(
  929. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  930. 0,
  931. "%d",
  932. winsLength * sizeof(ULONG)
  933. );
  934. break;
  935. }
  936. //
  937. // Now fill in the WINS server names from each adapter.
  938. // In the process, we pick up the DNS server lists for each adapter.
  939. //
  940. for (AdapterInfo = AdaptersInfo, Length = 0;
  941. AdapterInfo;
  942. AdapterInfo = AdapterInfo->Next
  943. ) {
  944. Address =
  945. inet_addr(AdapterInfo->PrimaryWinsServer.IpAddress.String);
  946. if (Address) {
  947. for (i = 0; i < (LONG)Length; i++) {
  948. if (Address == winsServerList[i]) { break; }
  949. }
  950. if (i >= (LONG)Length) { winsServerList[Length++] = Address; }
  951. }
  952. Address =
  953. inet_addr(AdapterInfo->SecondaryWinsServer.IpAddress.String);
  954. if (Address) {
  955. for (i = 0; i < (LONG)Length; i++) {
  956. if (Address == winsServerList[i]) { break; }
  957. }
  958. if (i >= (LONG)Length) { winsServerList[Length++] = Address; }
  959. }
  960. //
  961. // Now obtain the DNS servers for the adapter.
  962. //
  963. Error = GetPerAdapterInfo(AdapterInfo->Index, NULL, &tempLength);
  964. if (Error != ERROR_BUFFER_OVERFLOW) { continue; }
  965. //
  966. // Allocate memory for the per-adapter info
  967. //
  968. PerAdapterInfo =
  969. reinterpret_cast<PIP_PER_ADAPTER_INFO>(
  970. NH_ALLOCATE(tempLength)
  971. );
  972. if (!PerAdapterInfo) {
  973. NhTrace(
  974. TRACE_FLAG_DNS,
  975. "DnsQueryServerList: error allocating %d bytes",
  976. tempLength
  977. );
  978. NhErrorLog(
  979. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  980. 0,
  981. "%d",
  982. tempLength
  983. );
  984. continue;
  985. }
  986. //
  987. // Retrieve the per-adapter info
  988. //
  989. Error =
  990. GetPerAdapterInfo(
  991. AdapterInfo->Index,
  992. PerAdapterInfo,
  993. &tempLength
  994. );
  995. if (Error) {
  996. NH_FREE(PerAdapterInfo);
  997. NhTrace(
  998. TRACE_FLAG_DNS,
  999. "DnsQueryServerList: GetPerAdapterInfo=%d",
  1000. Error
  1001. );
  1002. NhErrorLog(
  1003. IP_DNS_PROXY_LOG_NO_SERVER_LIST,
  1004. Error,
  1005. ""
  1006. );
  1007. continue;
  1008. }
  1009. //
  1010. // Count the DNS servers for the adapter
  1011. //
  1012. for (AddrString = &PerAdapterInfo->DnsServerList, tempLength = 0;
  1013. AddrString;
  1014. AddrString = AddrString->Next
  1015. ) {
  1016. if (inet_addr(AddrString->IpAddress.String)) { ++tempLength; }
  1017. }
  1018. if (!tempLength) { NH_FREE(PerAdapterInfo); continue; }
  1019. //
  1020. // Allocate space for the adapter's DNS servers
  1021. //
  1022. tempServerList =
  1023. reinterpret_cast<PULONG>(
  1024. NH_ALLOCATE((dnsLength + tempLength + 1) * sizeof(ULONG))
  1025. );
  1026. if (!tempServerList) {
  1027. NH_FREE(PerAdapterInfo);
  1028. NhTrace(
  1029. TRACE_FLAG_DNS,
  1030. "DnsQueryServerList: error allocating %d bytes",
  1031. (dnsLength + tempLength + 1) * sizeof(ULONG)
  1032. );
  1033. NhErrorLog(
  1034. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  1035. 0,
  1036. "%d",
  1037. (dnsLength + tempLength + 1) * sizeof(ULONG)
  1038. );
  1039. continue;
  1040. }
  1041. //
  1042. // Copy the existing servers
  1043. //
  1044. if (dnsServerList) {
  1045. CopyMemory(
  1046. tempServerList,
  1047. dnsServerList,
  1048. dnsLength * sizeof(ULONG)
  1049. );
  1050. }
  1051. //
  1052. // Read the new servers into the new server list
  1053. //
  1054. for (AddrString = &PerAdapterInfo->DnsServerList;
  1055. AddrString;
  1056. AddrString = AddrString->Next
  1057. ) {
  1058. Address = inet_addr(AddrString->IpAddress.String);
  1059. if (!Address) { continue; }
  1060. for (i = 0; i < (LONG)dnsLength; i++) {
  1061. if (Address == tempServerList[i]) { break; }
  1062. }
  1063. if (i < (LONG)dnsLength) { continue; }
  1064. //
  1065. // The current DNS server goes in the front of the list,
  1066. // while any other server is appended.
  1067. //
  1068. if (PerAdapterInfo->CurrentDnsServer != AddrString) {
  1069. tempServerList[dnsLength] = Address;
  1070. } else {
  1071. MoveMemory(
  1072. tempServerList + sizeof(ULONG),
  1073. tempServerList,
  1074. dnsLength * sizeof(ULONG)
  1075. );
  1076. tempServerList[0] = Address;
  1077. }
  1078. ++dnsLength;
  1079. }
  1080. tempServerList[dnsLength] = 0;
  1081. NH_FREE(PerAdapterInfo);
  1082. //
  1083. // Replace the existing server list
  1084. //
  1085. if (dnsServerList) { NH_FREE(dnsServerList); }
  1086. dnsServerList = tempServerList;
  1087. }
  1088. winsServerList[Length] = 0;
  1089. } while(FALSE);
  1090. if (AdaptersInfo) { NH_FREE(AdaptersInfo); }
  1091. //
  1092. // Store the new server lists
  1093. //
  1094. NhTrace(
  1095. TRACE_FLAG_DNS,
  1096. "DnsQueryServerList: new server list lengths are : DNS (%d) WINS (%d)",
  1097. dnsLength,
  1098. Length
  1099. );
  1100. if (DnsServerList[DnsProxyDns]) { NH_FREE(DnsServerList[DnsProxyDns]); }
  1101. DnsServerList[DnsProxyDns] = dnsServerList;
  1102. if (DnsServerList[DnsProxyWins]) { NH_FREE(DnsServerList[DnsProxyWins]); }
  1103. DnsServerList[DnsProxyWins] = winsServerList;
  1104. }
  1105. return NO_ERROR;
  1106. } // DnsQueryServerList
  1107. VOID
  1108. DnsQueryRegistryICSDomainSuffix(
  1109. VOID
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. This routine is invoked to read the ICS Domain suffix from the registry.
  1114. Arguments:
  1115. none.
  1116. Return Value:
  1117. VOID.
  1118. Environment:
  1119. Invoked in an arbitrary context with 'DnsGlobalInfoLock' acquired
  1120. by the caller.
  1121. --*/
  1122. {
  1123. NTSTATUS status;
  1124. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1125. DWORD dwSize = 0;
  1126. LPVOID lpMsgBuf;
  1127. BOOL fSuffixChanged = FALSE;
  1128. BOOL fUseDefaultSuffix = FALSE;
  1129. //
  1130. // retrieve current suffix string (if any)
  1131. //
  1132. status =
  1133. NhQueryValueKey(
  1134. DnsTcpipParametersKey,
  1135. DnsICSDomainValueName,
  1136. &Information
  1137. );
  1138. if (!NT_SUCCESS(status))
  1139. {
  1140. NhTrace(
  1141. TRACE_FLAG_DNS,
  1142. "DnsQueryRegistryICSDomainSuffix: error (0x%08x) querying "
  1143. "ICS Domain suffix name",
  1144. status
  1145. );
  1146. //
  1147. // if we did not find it in the registry and we had previously
  1148. // got some suffix - we revert to default string (happens below)
  1149. //
  1150. if ((STATUS_OBJECT_NAME_NOT_FOUND == status) && DnsICSDomainSuffix)
  1151. {
  1152. NH_FREE(DnsICSDomainSuffix);
  1153. DnsICSDomainSuffix = NULL;
  1154. }
  1155. //
  1156. // if we have no idea of the string, set our copy to default string
  1157. //
  1158. if (NULL == DnsICSDomainSuffix)
  1159. {
  1160. dwSize = wcslen(DNS_HOMENET_SUFFIX) + 1;
  1161. DnsICSDomainSuffix = reinterpret_cast<PWCHAR>(
  1162. NH_ALLOCATE(sizeof(WCHAR) * dwSize)
  1163. );
  1164. if (!DnsICSDomainSuffix)
  1165. {
  1166. NhTrace(
  1167. TRACE_FLAG_DNS,
  1168. "DnsQueryRegistryICSDomainSuffix: allocation "
  1169. "failed for DnsICSDomainSuffix"
  1170. );
  1171. return;
  1172. }
  1173. wcscpy(DnsICSDomainSuffix, DNS_HOMENET_SUFFIX);
  1174. fSuffixChanged = TRUE;
  1175. }
  1176. }
  1177. else
  1178. {
  1179. //
  1180. // overwrite our current version of suffix string
  1181. //
  1182. dwSize = lstrlenW((PWCHAR)Information->Data);
  1183. if (dwSize)
  1184. {
  1185. //
  1186. // we have a nonzero string
  1187. //
  1188. dwSize++; // add 1 for terminating null
  1189. }
  1190. else
  1191. {
  1192. //
  1193. // the data is a null string - use default suffix
  1194. //
  1195. dwSize = wcslen(DNS_HOMENET_SUFFIX) + 1;
  1196. fUseDefaultSuffix = TRUE;
  1197. }
  1198. if (DnsICSDomainSuffix)
  1199. {
  1200. NH_FREE(DnsICSDomainSuffix);
  1201. DnsICSDomainSuffix = NULL;
  1202. }
  1203. DnsICSDomainSuffix = reinterpret_cast<PWCHAR>(
  1204. NH_ALLOCATE(sizeof(WCHAR) * dwSize)
  1205. );
  1206. if (!DnsICSDomainSuffix)
  1207. {
  1208. NH_FREE(Information);
  1209. NhTrace(
  1210. TRACE_FLAG_DNS,
  1211. "DnsQueryRegistryICSDomainSuffix: allocation "
  1212. "failed for DnsICSDomainSuffix"
  1213. );
  1214. return;
  1215. }
  1216. if (!fUseDefaultSuffix)
  1217. {
  1218. wcscpy(DnsICSDomainSuffix, (PWCHAR) Information->Data);
  1219. }
  1220. else
  1221. {
  1222. wcscpy(DnsICSDomainSuffix, DNS_HOMENET_SUFFIX);
  1223. }
  1224. fSuffixChanged = TRUE;
  1225. NH_FREE(Information);
  1226. }
  1227. if (fSuffixChanged)
  1228. {
  1229. //
  1230. // enumerate existing entries and replace old ones
  1231. // + we must do this because otherwise forward and reverse lookups
  1232. // are dependent on the way in which the entries are ordered in
  1233. // the hosts.ics file
  1234. //
  1235. //DnsReplaceOnSuffixChange();
  1236. }
  1237. } // DnsQueryRegistryICSDomainSuffix
  1238. ULONG
  1239. DnsQueryICSDomainSuffix(
  1240. VOID
  1241. )
  1242. /*++
  1243. Routine Description:
  1244. This routine invokes DnsQueryRegistryICSDomainSuffix and installs
  1245. change notification for this reg key if necessary.
  1246. Arguments:
  1247. none.
  1248. Return Value:
  1249. ULONG - Win32 status code.
  1250. Environment:
  1251. Invoked in an arbitrary context with 'DnsGlobalInfoLock' acquired
  1252. by the caller.
  1253. --*/
  1254. {
  1255. PUCHAR Buffer;
  1256. ULONG Error;
  1257. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1258. OBJECT_ATTRIBUTES ObjectAttributes;
  1259. NTSTATUS status;
  1260. UNICODE_STRING UnicodeString;
  1261. PROFILE("DnsQueryICSDomainSuffix");
  1262. if (!DnsTcpipParametersKey)
  1263. {
  1264. RtlInitUnicodeString(&UnicodeString, DnsTcpipParametersString);
  1265. InitializeObjectAttributes(
  1266. &ObjectAttributes,
  1267. &UnicodeString,
  1268. OBJ_CASE_INSENSITIVE,
  1269. NULL,
  1270. NULL
  1271. );
  1272. //
  1273. // Open the 'Tcpip\Parameters' registry key
  1274. //
  1275. status =
  1276. NtOpenKey(
  1277. &DnsTcpipParametersKey,
  1278. KEY_ALL_ACCESS,
  1279. &ObjectAttributes
  1280. );
  1281. if (!NT_SUCCESS(status))
  1282. {
  1283. Error = RtlNtStatusToDosError(status);
  1284. NhTrace(
  1285. TRACE_FLAG_DNS,
  1286. "DnsQueryICSDomainSuffix: error %x opening registry key",
  1287. status
  1288. );
  1289. NhErrorLog(
  1290. IP_DNS_PROXY_LOG_NO_ICSD_SUFFIX,
  1291. Error,
  1292. ""
  1293. );
  1294. return Error;
  1295. }
  1296. }
  1297. //
  1298. // See if we need to install change-notification,
  1299. // and reference ourselves if so.
  1300. // The reference is made on behalf of the change-notification routine
  1301. // which will be invoked by a wait-thread when a change occurs.
  1302. //
  1303. if (!DnsNotifyChangeKeyICSDomainEvent && REFERENCE_DNS())
  1304. {
  1305. //
  1306. // Attempt to set up change notification on the key
  1307. //
  1308. status =
  1309. NtCreateEvent(
  1310. &DnsNotifyChangeKeyICSDomainEvent,
  1311. EVENT_ALL_ACCESS,
  1312. NULL,
  1313. SynchronizationEvent,
  1314. FALSE
  1315. );
  1316. if (!NT_SUCCESS(status)) {
  1317. DEREFERENCE_DNS();
  1318. NhTrace(
  1319. TRACE_FLAG_DNS,
  1320. "DnsQueryICSDomainSuffix: status %08x creating notify-change event",
  1321. status
  1322. );
  1323. NhWarningLog(
  1324. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1325. RtlNtStatusToDosError(status),
  1326. ""
  1327. );
  1328. }
  1329. else
  1330. {
  1331. //
  1332. // Register a wait on the notify-change event
  1333. //
  1334. status =
  1335. RtlRegisterWait(
  1336. &DnsNotifyChangeKeyICSDomainWaitHandle,
  1337. DnsNotifyChangeKeyICSDomainEvent,
  1338. DnsNotifyChangeKeyICSDomainCallbackRoutine,
  1339. NULL,
  1340. INFINITE,
  1341. 0
  1342. );
  1343. if (!NT_SUCCESS(status))
  1344. {
  1345. NtClose(DnsNotifyChangeKeyICSDomainEvent);
  1346. DnsNotifyChangeKeyICSDomainEvent = NULL;
  1347. DEREFERENCE_DNS();
  1348. NhTrace(
  1349. TRACE_FLAG_DNS,
  1350. "DnsQueryICSDomainSuffix: status %08x registering wait",
  1351. status
  1352. );
  1353. NhWarningLog(
  1354. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1355. RtlNtStatusToDosError(status),
  1356. ""
  1357. );
  1358. }
  1359. else
  1360. {
  1361. //
  1362. // Register for change-notification on the key
  1363. //
  1364. status =
  1365. NtNotifyChangeKey(
  1366. DnsTcpipParametersKey,
  1367. DnsNotifyChangeKeyICSDomainEvent,
  1368. NULL,
  1369. NULL,
  1370. &DnsNotifyChangeKeyICSDomainIoStatus,
  1371. REG_NOTIFY_CHANGE_LAST_SET,
  1372. FALSE, // not interested in the subtree
  1373. NULL,
  1374. 0,
  1375. TRUE
  1376. );
  1377. if (!NT_SUCCESS(status))
  1378. {
  1379. RtlDeregisterWait(DnsNotifyChangeKeyICSDomainWaitHandle);
  1380. DnsNotifyChangeKeyICSDomainWaitHandle = NULL;
  1381. NtClose(DnsNotifyChangeKeyICSDomainEvent);
  1382. DnsNotifyChangeKeyICSDomainEvent = NULL;
  1383. DEREFERENCE_DNS();
  1384. NhTrace(
  1385. TRACE_FLAG_DNS,
  1386. "DnsQueryICSDomainSuffix: status %08x (%08x) "
  1387. "enabling change notify",
  1388. status
  1389. );
  1390. NhWarningLog(
  1391. IP_DNS_PROXY_LOG_CHANGE_ICSD_NOTIFY_FAILED,
  1392. RtlNtStatusToDosError(status),
  1393. ""
  1394. );
  1395. }
  1396. }
  1397. }
  1398. }
  1399. DnsQueryRegistryICSDomainSuffix();
  1400. return NO_ERROR;
  1401. } // DnsQueryICSDomainSuffix
  1402. PDNS_QUERY
  1403. DnsRecordQuery(
  1404. PDNS_INTERFACE Interfacep,
  1405. PNH_BUFFER QueryBuffer
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. This routine is invoked to create a pending-query entry for a client's
  1410. DNS query.
  1411. Arguments:
  1412. Interfacep - the interface on which to create the record
  1413. QueryBuffer - the DNS request for which to create a record
  1414. Return Value:
  1415. PDNS_QUERY - the pending query if created
  1416. Environment:
  1417. Invoked with 'Interfacep' locked by the caller.
  1418. --*/
  1419. {
  1420. BOOLEAN ConflictFound;
  1421. PDNS_HEADER Headerp;
  1422. PLIST_ENTRY Link;
  1423. USHORT QueryId;
  1424. PDNS_QUERY Queryp;
  1425. ULONG RetryCount = MAXCHAR;
  1426. ULONG Seed = GetTickCount();
  1427. PROFILE("DnsRecordQuery");
  1428. //
  1429. // Attempt to generate a random ID for the query.
  1430. // Assuming we succeed, we leave the loop with 'Link'
  1431. // set to the correct insertion-point for the new query.
  1432. //
  1433. do {
  1434. QueryId = (USHORT)((RtlRandom(&Seed) & 0xffff0000) >> 16);
  1435. ConflictFound = FALSE;
  1436. for (Link = Interfacep->QueryList.Flink; Link != &Interfacep->QueryList;
  1437. Link = Link->Flink) {
  1438. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  1439. if (QueryId > Queryp->QueryId) {
  1440. continue;
  1441. } else if (QueryId < Queryp->QueryId) {
  1442. break;
  1443. }
  1444. ConflictFound = TRUE;
  1445. break;
  1446. }
  1447. } while(ConflictFound && --RetryCount);
  1448. if (ConflictFound) { return NULL; }
  1449. //
  1450. // Allocate and initialize the new query
  1451. //
  1452. Queryp = reinterpret_cast<PDNS_QUERY>(NH_ALLOCATE(sizeof(DNS_QUERY)));
  1453. if (!Queryp) {
  1454. NhTrace(
  1455. TRACE_FLAG_DNS,
  1456. "DnsRecordQuery: allocation failed for DNS query"
  1457. );
  1458. NhErrorLog(
  1459. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  1460. 0,
  1461. "%d",
  1462. sizeof(DNS_QUERY)
  1463. );
  1464. return NULL;
  1465. }
  1466. Headerp = (PDNS_HEADER)QueryBuffer->Buffer;
  1467. Queryp->QueryId = QueryId;
  1468. Queryp->SourceId = Headerp->Xid;
  1469. Queryp->SourceAddress = QueryBuffer->ReadAddress.sin_addr.s_addr;
  1470. Queryp->SourcePort = QueryBuffer->ReadAddress.sin_port;
  1471. Queryp->Type =
  1472. DNS_PROXY_PORT_TO_TYPE(NhQueryPortSocket(QueryBuffer->Socket));
  1473. Queryp->QueryLength = QueryBuffer->BytesTransferred;
  1474. Queryp->Bufferp = QueryBuffer;
  1475. Queryp->Interfacep = Interfacep;
  1476. Queryp->TimerHandle = NULL;
  1477. Queryp->RetryCount = 0;
  1478. //
  1479. // Insert the new query in the location determined above.
  1480. //
  1481. InsertTailList(Link, &Queryp->Link);
  1482. return Queryp;
  1483. } // DnsRecordQuery
  1484. ULONG
  1485. DnsSendQuery(
  1486. PDNS_INTERFACE Interfacep,
  1487. PDNS_QUERY Queryp,
  1488. BOOLEAN Resend
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This routine is invoked to forward a query to our DNS servers.
  1493. Arguments:
  1494. Interfacep - the interface on which to send the query
  1495. Queryp - the DNS request to be sent
  1496. Resend - if TRUE, the buffer is being resent; otherwise, the buffer
  1497. is being sent for the first time.
  1498. Return Value:
  1499. ULONG - Win32 status code.
  1500. On success, 'Queryp' may have been deleted.
  1501. Environment:
  1502. Invoked with 'Interfacep' locked by the caller, and with a reference made
  1503. to it for the send which occurs here.
  1504. If the routine fails, it is the caller's responsibility to release that
  1505. reference.
  1506. --*/
  1507. {
  1508. PNH_BUFFER Bufferp;
  1509. ULONG Error;
  1510. ULONG i, j;
  1511. PULONG ServerList;
  1512. SOCKET Socket;
  1513. NTSTATUS status;
  1514. PDNS_QUERY_TIMEOUT_CONTEXT TimeoutContext;
  1515. ULONG TimeoutSeconds;
  1516. PROFILE("DnsSendQuery");
  1517. //
  1518. // For WINS queries, we use a global socket to work around the fact that
  1519. // even though we're bound to the WINS port, responses will only be
  1520. // delivered to the first socket bound to the socket, which is
  1521. // the kernel-mode NetBT driver.
  1522. //
  1523. EnterCriticalSection(&DnsGlobalInfoLock);
  1524. if (Queryp->Type == DnsProxyDns) {
  1525. Socket = Queryp->Bufferp->Socket;
  1526. ServerList = DnsServerList[DnsProxyDns];
  1527. } else {
  1528. Socket = DnsGlobalSocket;
  1529. ServerList = DnsServerList[DnsProxyWins];
  1530. }
  1531. LeaveCriticalSection(&DnsGlobalInfoLock);
  1532. //
  1533. // See if there are any servers to be tried.
  1534. //
  1535. if (!ServerList ||
  1536. !ServerList[0] ||
  1537. Queryp->RetryCount++ > DNS_QUERY_RETRY) {
  1538. if (!ServerList) {
  1539. NhTrace(
  1540. TRACE_FLAG_DNS,
  1541. "DnsSendQuery: no server list"
  1542. );
  1543. }
  1544. else if (!ServerList[0]) {
  1545. NhTrace(
  1546. TRACE_FLAG_DNS,
  1547. "DnsSendQuery: no server entries in list"
  1548. );
  1549. }
  1550. else {
  1551. NhTrace(
  1552. TRACE_FLAG_DNS,
  1553. "DnsSendQuery: retry count for query %d "
  1554. "greater than DNS_QUERY_RETRY(%d)",
  1555. Queryp->QueryId,
  1556. DNS_QUERY_RETRY
  1557. );
  1558. }
  1559. if (REFERENCE_DNS()) {
  1560. //
  1561. // Initiate an attempt to connect the default interface, if any.
  1562. //
  1563. status =
  1564. RtlQueueWorkItem(
  1565. DnsConnectDefaultInterface,
  1566. NULL,
  1567. WT_EXECUTEINIOTHREAD
  1568. );
  1569. if (!NT_SUCCESS(status)) { DEREFERENCE_DNS(); }
  1570. }
  1571. NhInformationLog(
  1572. IP_DNS_PROXY_LOG_NO_SERVERS_LEFT,
  1573. 0,
  1574. "%I",
  1575. Queryp->SourceAddress
  1576. );
  1577. return ERROR_NO_MORE_ITEMS;
  1578. }
  1579. //
  1580. // Send the query to each server on the list
  1581. //
  1582. for (i = 0; ServerList[i]; i++) {
  1583. for (j = 0; j < Interfacep->BindingCount; j++) {
  1584. if (Interfacep->BindingArray[j].Address == ServerList[i]) {
  1585. break;
  1586. }
  1587. }
  1588. if (j < Interfacep->BindingCount) {
  1589. NhTrace(
  1590. TRACE_FLAG_DNS,
  1591. "DnsSendQuery: server %s is self, ignoring",
  1592. INET_NTOA(ServerList[i])
  1593. );
  1594. continue;
  1595. }
  1596. if (!DNS_REFERENCE_INTERFACE(Interfacep) ||
  1597. !(Bufferp = NhDuplicateBuffer(Queryp->Bufferp))) {
  1598. continue;
  1599. }
  1600. NhTrace(
  1601. TRACE_FLAG_DNS,
  1602. "DnsSendQuery: sending query %d interface %d to %s",
  1603. (PVOID)((PDNS_HEADER)Bufferp->Buffer)->Xid,
  1604. Interfacep->Index,
  1605. INET_NTOA(ServerList[i])
  1606. );
  1607. //
  1608. // Send the message
  1609. //
  1610. Error =
  1611. NhWriteDatagramSocket(
  1612. &DnsComponentReference,
  1613. Socket,
  1614. ServerList[i],
  1615. DNS_PROXY_TYPE_TO_PORT(Queryp->Type),
  1616. Bufferp,
  1617. Queryp->QueryLength,
  1618. DnsWriteCompletionRoutine,
  1619. Interfacep,
  1620. (PVOID)Queryp->QueryId
  1621. );
  1622. if (!Error) {
  1623. InterlockedIncrement(
  1624. reinterpret_cast<LPLONG>(&DnsStatistics.QueriesSent)
  1625. );
  1626. } else {
  1627. NhTrace(
  1628. TRACE_FLAG_DNS,
  1629. "DnsSendQuery: error %d sending query %d interface %d",
  1630. Error,
  1631. Queryp->QueryId,
  1632. Interfacep->Index
  1633. );
  1634. NhErrorLog(
  1635. IP_DNS_PROXY_LOG_QUERY_FAILED,
  1636. Error,
  1637. "%I%I%I",
  1638. Queryp->SourceAddress,
  1639. ServerList[i],
  1640. NhQueryAddressSocket(Bufferp->Socket)
  1641. );
  1642. Error = NO_ERROR;
  1643. NhReleaseBuffer(Bufferp);
  1644. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1645. }
  1646. }
  1647. //
  1648. // Set up the query's timeout.
  1649. // Note that we are now certain that the write-completion routine
  1650. // will be executed. However, if the timeout cannot be set,
  1651. // we want to be assured that the query will still be deleted.
  1652. // Therefore, on failure we delete the query immediately,
  1653. // and the write-completion routine will simply not find it.
  1654. //
  1655. status = STATUS_UNSUCCESSFUL;
  1656. EnterCriticalSection(&DnsGlobalInfoLock);
  1657. TimeoutSeconds = DnsGlobalInfo->TimeoutSeconds;
  1658. LeaveCriticalSection(&DnsGlobalInfoLock);
  1659. if (Queryp->TimerHandle) {
  1660. //
  1661. // Update the timer-queue entry for the query
  1662. //
  1663. status =
  1664. NhUpdateTimer(
  1665. Queryp->TimerHandle,
  1666. TimeoutSeconds * 1000
  1667. );
  1668. } else {
  1669. //
  1670. // Allocate a timer-queue entry context block
  1671. //
  1672. TimeoutContext = reinterpret_cast<PDNS_QUERY_TIMEOUT_CONTEXT>(
  1673. NH_ALLOCATE(sizeof(*TimeoutContext))
  1674. );
  1675. if (!TimeoutContext) {
  1676. NhTrace(
  1677. TRACE_FLAG_DNS,
  1678. "DnsSendQuery: error allocating query %d timeout context",
  1679. Queryp->QueryId
  1680. );
  1681. status = STATUS_UNSUCCESSFUL;
  1682. } else {
  1683. TimeoutContext->Index = Interfacep->Index;
  1684. TimeoutContext->QueryId = Queryp->QueryId;
  1685. //
  1686. // Insert a timer-queue entry to check the status of the query
  1687. //
  1688. status =
  1689. NhSetTimer(
  1690. &DnsComponentReference,
  1691. &Queryp->TimerHandle,
  1692. DnspQueryTimeoutCallbackRoutine,
  1693. TimeoutContext,
  1694. TimeoutSeconds * 1000
  1695. );
  1696. if (!NT_SUCCESS(status)) {
  1697. NH_FREE(TimeoutContext);
  1698. Queryp->TimerHandle = NULL;
  1699. }
  1700. }
  1701. }
  1702. //
  1703. // If the above failed, delete the query now.
  1704. //
  1705. if (!NT_SUCCESS(status)) {
  1706. NhTrace(
  1707. TRACE_FLAG_DNS,
  1708. "DnsSendQuery: status %08x setting timer for query %d",
  1709. status,
  1710. Queryp->QueryId
  1711. );
  1712. DnsDeleteQuery(Interfacep, Queryp);
  1713. }
  1714. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1715. return NO_ERROR;
  1716. } // DnsSendQuery