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.

2341 lines
53 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. dnsif.c
  5. Abstract:
  6. This module contains code for the DNS proxy's interface management.
  7. Author:
  8. Abolade Gbadegesin (aboladeg) 9-Mar-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // LOCAL TYPE DECLARATIONS
  15. //
  16. typedef struct _DNS_DEFER_READ_CONTEXT {
  17. ULONG Index;
  18. SOCKET Socket;
  19. ULONG DeferralCount;
  20. } DNS_DEFER_READ_CONTEXT, *PDNS_DEFER_READ_CONTEXT;
  21. #define DNS_DEFER_READ_INITIAL_TIMEOUT (1 * 1000)
  22. #define DNS_DEFER_READ_TIMEOUT (5 * 1000)
  23. #define DNS_CONNECT_TIMEOUT (60 * 1000)
  24. //
  25. // GLOBAL DATA DEFINITIONS
  26. //
  27. LIST_ENTRY DnsInterfaceList;
  28. CRITICAL_SECTION DnsInterfaceLock;
  29. ULONG DnspLastConnectAttemptTickCount;
  30. //
  31. // Forward declarations
  32. //
  33. VOID NTAPI
  34. DnspDeferReadCallbackRoutine(
  35. PVOID Context,
  36. BOOLEAN TimedOut
  37. );
  38. VOID APIENTRY
  39. DnspDeferReadWorkerRoutine(
  40. PVOID Context
  41. );
  42. ULONG NTAPI
  43. DnspSaveFileWorkerRoutine(
  44. PVOID Context
  45. );
  46. ULONG
  47. DnsActivateInterface(
  48. PDNS_INTERFACE Interfacep
  49. )
  50. /*++
  51. Routine Description:
  52. This routine is called to activate an interface, when the interface
  53. becomes both enabled and bound.
  54. Activation involves
  55. (a) creating sockets for each binding of the interface
  56. (b) initiating datagram-reads on each created socket
  57. Arguments:
  58. Interfacep - the interface to be activated
  59. Return Value:
  60. ULONG - Win32 status code indicating success or failure.
  61. Environment:
  62. Always invoked locally, with 'Interfacep' referenced by caller and/or
  63. 'DnsInterfaceLock' held by caller.
  64. --*/
  65. {
  66. BOOLEAN EnableDns;
  67. BOOLEAN EnableWins = FALSE;
  68. ULONG Error;
  69. ULONG i;
  70. ULONG InterfaceCharacteristics;
  71. DNS_INTERFACE_TYPE dnsIfType;
  72. PROFILE("DnsActivateInterface");
  73. EnterCriticalSection(&DnsGlobalInfoLock);
  74. EnableDns =
  75. (DnsGlobalInfo->Flags & IP_DNS_PROXY_FLAG_ENABLE_DNS) ? TRUE : FALSE;
  76. LeaveCriticalSection(&DnsGlobalInfoLock);
  77. //
  78. // (re)take the interface lock for the duration of the routine
  79. //
  80. EnterCriticalSection(&DnsInterfaceLock);
  81. if (!(EnableDns || EnableWins) ||
  82. DNS_INTERFACE_ADMIN_DISABLED(Interfacep)) {
  83. LeaveCriticalSection(&DnsInterfaceLock);
  84. return NO_ERROR;
  85. }
  86. InterfaceCharacteristics =
  87. NatGetInterfaceCharacteristics(
  88. Interfacep->Index
  89. );
  90. if (!InterfaceCharacteristics) {
  91. ACQUIRE_LOCK(Interfacep);
  92. Interfacep->DnsInterfaceType = DnsInterfaceInvalid;
  93. RELEASE_LOCK(Interfacep);
  94. LeaveCriticalSection(&DnsInterfaceLock);
  95. NhTrace(
  96. TRACE_FLAG_DNS,
  97. "DnsActivateInterface: ignoring non-NAT interface %d",
  98. Interfacep->Index
  99. );
  100. return NO_ERROR;
  101. }
  102. if (NAT_IFC_BOUNDARY(InterfaceCharacteristics))
  103. {
  104. if (NAT_IFC_FW(InterfaceCharacteristics))
  105. {
  106. dnsIfType = DnsInterfaceBoundaryFirewalled;
  107. }
  108. else
  109. {
  110. dnsIfType = DnsInterfaceBoundary;
  111. }
  112. }
  113. else
  114. if (NAT_IFC_FW(InterfaceCharacteristics))
  115. {
  116. dnsIfType = DnsInterfaceFirewalled;
  117. }
  118. else
  119. {
  120. dnsIfType = DnsInterfacePrivate;
  121. }
  122. //
  123. // Create datagram sockets for receiving data on each logical network
  124. //
  125. Error = NO_ERROR;
  126. ACQUIRE_LOCK(Interfacep);
  127. Interfacep->DnsInterfaceType = dnsIfType;
  128. if (DnsInterfacePrivate != dnsIfType)
  129. {
  130. //
  131. // DNS should be active only on Private interfaces
  132. //
  133. NhTrace(
  134. TRACE_FLAG_DNS,
  135. "DnsActivateInterface: ignoring NAT interface %d",
  136. Interfacep->Index
  137. );
  138. NhWarningLog(
  139. IP_DNS_PROXY_LOG_NAT_INTERFACE_IGNORED,
  140. 0,
  141. "%d",
  142. Interfacep->Index
  143. );
  144. RELEASE_LOCK(Interfacep);
  145. LeaveCriticalSection(&DnsInterfaceLock);
  146. return NO_ERROR;
  147. }
  148. for (i = 0; i < Interfacep->BindingCount; i++) {
  149. if (EnableDns) {
  150. Error =
  151. NhCreateDatagramSocket(
  152. Interfacep->BindingArray[i].Address,
  153. DNS_PORT_SERVER,
  154. &Interfacep->BindingArray[i].Socket[DnsProxyDns]
  155. );
  156. if (Error) { break; }
  157. }
  158. if (EnableWins) {
  159. Error =
  160. NhCreateDatagramSocket(
  161. Interfacep->BindingArray[i].Address,
  162. WINS_PORT_SERVER,
  163. &Interfacep->BindingArray[i].Socket[DnsProxyWins]
  164. );
  165. if (Error) { break; }
  166. }
  167. }
  168. //
  169. // If an error occurred, roll back all work done so far and fail.
  170. //
  171. if (Error) {
  172. ULONG FailedAddress = i;
  173. for (; (LONG)i >= 0; i--) {
  174. NhDeleteDatagramSocket(
  175. Interfacep->BindingArray[i].Socket[DnsProxyDns]
  176. );
  177. Interfacep->BindingArray[i].Socket[DnsProxyDns] = INVALID_SOCKET;
  178. NhDeleteDatagramSocket(
  179. Interfacep->BindingArray[i].Socket[DnsProxyWins]
  180. );
  181. Interfacep->BindingArray[i].Socket[DnsProxyWins] = INVALID_SOCKET;
  182. }
  183. NhErrorLog(
  184. IP_DNS_PROXY_LOG_ACTIVATE_FAILED,
  185. Error,
  186. "%I",
  187. Interfacep->BindingArray[FailedAddress].Address
  188. );
  189. RELEASE_LOCK(Interfacep);
  190. LeaveCriticalSection(&DnsInterfaceLock);
  191. return Error;
  192. }
  193. if (EnableWins && DNS_REFERENCE_INTERFACE(Interfacep)) {
  194. Error =
  195. NhReadDatagramSocket(
  196. &DnsComponentReference,
  197. DnsGlobalSocket,
  198. NULL,
  199. DnsReadCompletionRoutine,
  200. Interfacep,
  201. NULL
  202. );
  203. if (Error) { DNS_DEREFERENCE_INTERFACE(Interfacep); }
  204. }
  205. //
  206. // Initiate read-operations on each socket
  207. //
  208. for (i = 0; i < Interfacep->BindingCount; i++) {
  209. if (EnableDns) {
  210. //
  211. // Make a reference to the interface;
  212. // this reference is released in the completion routine
  213. //
  214. if (!DNS_REFERENCE_INTERFACE(Interfacep)) { continue; }
  215. //
  216. // Initiate the read-operation
  217. //
  218. Error =
  219. NhReadDatagramSocket(
  220. &DnsComponentReference,
  221. Interfacep->BindingArray[i].Socket[DnsProxyDns],
  222. NULL,
  223. DnsReadCompletionRoutine,
  224. Interfacep,
  225. UlongToPtr(Interfacep->BindingArray[i].Address)
  226. );
  227. //
  228. // Drop the reference if a failure occurred
  229. //
  230. if (Error) {
  231. NhErrorLog(
  232. IP_DNS_PROXY_LOG_RECEIVE_FAILED,
  233. Error,
  234. "%I",
  235. Interfacep->BindingArray[i].Address
  236. );
  237. DNS_DEREFERENCE_INTERFACE(Interfacep);
  238. //
  239. // Reissue the read-operation later
  240. //
  241. DnsDeferReadInterface(
  242. Interfacep,
  243. Interfacep->BindingArray[i].Socket[DnsProxyDns]
  244. );
  245. Error = NO_ERROR;
  246. }
  247. }
  248. if (EnableWins) {
  249. //
  250. // Reference the interface for the WINS socket receive
  251. //
  252. if (!DNS_REFERENCE_INTERFACE(Interfacep)) { continue; }
  253. //
  254. // Initiate the read-operation
  255. //
  256. Error =
  257. NhReadDatagramSocket(
  258. &DnsComponentReference,
  259. Interfacep->BindingArray[i].Socket[DnsProxyWins],
  260. NULL,
  261. DnsReadCompletionRoutine,
  262. Interfacep,
  263. UlongToPtr(Interfacep->BindingArray[i].Address)
  264. );
  265. //
  266. // Drop the reference if a failure occurred
  267. //
  268. if (Error) {
  269. NhErrorLog(
  270. IP_DNS_PROXY_LOG_RECEIVE_FAILED,
  271. Error,
  272. "%I",
  273. Interfacep->BindingArray[i].Address
  274. );
  275. DNS_DEREFERENCE_INTERFACE(Interfacep);
  276. //
  277. // Reissue the read-operation later
  278. //
  279. DnsDeferReadInterface(
  280. Interfacep,
  281. Interfacep->BindingArray[i].Socket[DnsProxyWins]
  282. );
  283. Error = NO_ERROR;
  284. }
  285. }
  286. }
  287. RELEASE_LOCK(Interfacep);
  288. LeaveCriticalSection(&DnsInterfaceLock);
  289. //
  290. // queue a write to disk (ip address may have changed)
  291. // (necessary to do this to prevent possible deadlock)
  292. //
  293. if (REFERENCE_DNS())
  294. {
  295. if (!QueueUserWorkItem(DnspSaveFileWorkerRoutine, NULL, WT_EXECUTEDEFAULT))
  296. {
  297. Error = GetLastError();
  298. NhTrace(
  299. TRACE_FLAG_DNS,
  300. "DnsActivateInterface: QueueUserWorkItem failed with error %d (0x%08x)",
  301. Error,
  302. Error
  303. );
  304. DEREFERENCE_DNS();
  305. }
  306. else
  307. {
  308. NhTrace(
  309. TRACE_FLAG_DNS,
  310. "DnsActivateInterface: queued a write of %s file",
  311. HOSTSICSFILE
  312. );
  313. }
  314. }
  315. return NO_ERROR;
  316. } // DnsActivateInterface
  317. ULONG
  318. DnsBindInterface(
  319. ULONG Index,
  320. PIP_ADAPTER_BINDING_INFO BindingInfo
  321. )
  322. /*++
  323. Routine Description:
  324. This routine is invoked to supply the binding for an interface.
  325. It records the binding information received, and if necessary,
  326. it activates the interface.
  327. Arguments:
  328. Index - the index of the interface to be bound
  329. BindingInfo - the binding-information for the interface
  330. Return Value:
  331. ULONG - Win32 status code.
  332. Environment:
  333. Invoked internally in the context of an IP router-manager thread.
  334. (See 'RMDNS.C').
  335. --*/
  336. {
  337. ULONG Error = NO_ERROR;
  338. ULONG i;
  339. PDNS_INTERFACE Interfacep;
  340. PROFILE("DnsBindInterface");
  341. EnterCriticalSection(&DnsInterfaceLock);
  342. //
  343. // Retrieve the interface to be bound
  344. //
  345. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  346. LeaveCriticalSection(&DnsInterfaceLock);
  347. NhTrace(
  348. TRACE_FLAG_IF,
  349. "DnsBindInterface: interface %d not found",
  350. Index
  351. );
  352. return ERROR_NO_SUCH_INTERFACE;
  353. }
  354. //
  355. // Make sure the interface isn't already bound
  356. //
  357. if (DNS_INTERFACE_BOUND(Interfacep)) {
  358. LeaveCriticalSection(&DnsInterfaceLock);
  359. NhTrace(
  360. TRACE_FLAG_IF,
  361. "DnsBindInterface: interface %d is already bound",
  362. Index
  363. );
  364. return ERROR_ADDRESS_ALREADY_ASSOCIATED;
  365. }
  366. //
  367. // Reference the interface
  368. //
  369. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  370. LeaveCriticalSection(&DnsInterfaceLock);
  371. NhTrace(
  372. TRACE_FLAG_IF,
  373. "DnsBindInterface: interface %d cannot be referenced",
  374. Index
  375. );
  376. return ERROR_INTERFACE_DISABLED;
  377. }
  378. //
  379. // Update the interface's flags
  380. //
  381. Interfacep->Flags |= DNS_INTERFACE_FLAG_BOUND;
  382. LeaveCriticalSection(&DnsInterfaceLock);
  383. ACQUIRE_LOCK(Interfacep);
  384. //
  385. // Allocate space for the binding
  386. //
  387. if (!BindingInfo->AddressCount) {
  388. Interfacep->BindingCount = 0;
  389. Interfacep->BindingArray = NULL;
  390. }
  391. else {
  392. Interfacep->BindingArray =
  393. reinterpret_cast<PDNS_BINDING>(
  394. NH_ALLOCATE(BindingInfo->AddressCount * sizeof(DNS_BINDING))
  395. );
  396. if (!Interfacep->BindingArray) {
  397. RELEASE_LOCK(Interfacep);
  398. DNS_DEREFERENCE_INTERFACE(Interfacep);
  399. NhTrace(
  400. TRACE_FLAG_IF,
  401. "DnsBindInterface: allocation failed for interface %d binding",
  402. Index
  403. );
  404. NhErrorLog(
  405. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  406. 0,
  407. "%d",
  408. BindingInfo->AddressCount * sizeof(DNS_BINDING)
  409. );
  410. return ERROR_NOT_ENOUGH_MEMORY;
  411. }
  412. Interfacep->BindingCount = BindingInfo->AddressCount;
  413. }
  414. //
  415. // Copy the binding
  416. //
  417. for (i = 0; i < BindingInfo->AddressCount; i++) {
  418. Interfacep->BindingArray[i].Address = BindingInfo->Address[i].Address;
  419. Interfacep->BindingArray[i].Mask = BindingInfo->Address[i].Mask;
  420. Interfacep->BindingArray[i].Socket[DnsProxyDns] = INVALID_SOCKET;
  421. Interfacep->BindingArray[i].TimerPending[DnsProxyDns] = FALSE;
  422. Interfacep->BindingArray[i].Socket[DnsProxyWins] = INVALID_SOCKET;
  423. Interfacep->BindingArray[i].TimerPending[DnsProxyWins] = FALSE;
  424. }
  425. RELEASE_LOCK(Interfacep);
  426. //
  427. // Activate the interface if necessary
  428. //
  429. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  430. Error = DnsActivateInterface(Interfacep);
  431. }
  432. DNS_DEREFERENCE_INTERFACE(Interfacep);
  433. return Error;
  434. } // DnsBindInterface
  435. VOID
  436. DnsCleanupInterface(
  437. PDNS_INTERFACE Interfacep
  438. )
  439. /*++
  440. Routine Description:
  441. This routine is invoked when the very last reference to an interface
  442. is released, and the interface must be destroyed.
  443. Arguments:
  444. Interfacep - the interface to be destroyed
  445. Return Value:
  446. none.
  447. Environment:
  448. Invoked internally from an arbitrary context.
  449. --*/
  450. {
  451. PLIST_ENTRY Link;
  452. PDNS_QUERY Queryp;
  453. PROFILE("DnsCleanupInterface");
  454. if (Interfacep->BindingArray) {
  455. NH_FREE(Interfacep->BindingArray);
  456. Interfacep->BindingArray = NULL;
  457. }
  458. while (!IsListEmpty(&Interfacep->QueryList)) {
  459. Link = Interfacep->QueryList.Flink;
  460. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  461. DnsDeleteQuery(Interfacep, Queryp);
  462. }
  463. DeleteCriticalSection(&Interfacep->Lock);
  464. NH_FREE(Interfacep);
  465. } // DnsCleanupInterface
  466. VOID
  467. DnsConnectDefaultInterface(
  468. PVOID Unused
  469. )
  470. /*++
  471. Routine Description:
  472. This routine is invoked to attempt to initiate a demand-dial connection
  473. on the interface marked as 'default' for DNS requests.
  474. If no such interface is found, no operation is performed.
  475. Arguments:
  476. none used.
  477. Return Value:
  478. ULONG - Win32 status code.
  479. Environment:
  480. The routine is invoked from the context of an RTUTILS work item.
  481. --*/
  482. {
  483. ULONG Error;
  484. ULONG Index;
  485. PDNS_INTERFACE Interfacep;
  486. PLIST_ENTRY Link;
  487. ULONG TickCount;
  488. ROUTER_INTERFACE_TYPE Type;
  489. PROFILE("DnsConnectDefaultInterface");
  490. //
  491. // To avoid repeated autodial dialogs, we record the last time
  492. // we attempted to connect the default interface.
  493. // If we did so recently, return silently.
  494. // N.B. If the tick-count wrapped, we reset the last-attempt counter.
  495. //
  496. EnterCriticalSection(&DnsGlobalInfoLock);
  497. TickCount = NtGetTickCount();
  498. if (TickCount > DnspLastConnectAttemptTickCount &&
  499. TickCount <= (DnspLastConnectAttemptTickCount + DNS_CONNECT_TIMEOUT)
  500. ) {
  501. LeaveCriticalSection(&DnsGlobalInfoLock);
  502. DEREFERENCE_DNS();
  503. return;
  504. }
  505. DnspLastConnectAttemptTickCount = TickCount;
  506. LeaveCriticalSection(&DnsGlobalInfoLock);
  507. //
  508. // Look through the interface list for one which is marked as default
  509. //
  510. EnterCriticalSection(&DnsInterfaceLock);
  511. for (Link = DnsInterfaceList.Flink;
  512. Link != &DnsInterfaceList;
  513. Link = Link->Flink
  514. ) {
  515. Interfacep = CONTAINING_RECORD(Link, DNS_INTERFACE, Link);
  516. if (!DNS_INTERFACE_ADMIN_DEFAULT(Interfacep)) { continue; }
  517. //
  518. // We've found the default interface.
  519. //
  520. Index = Interfacep->Index;
  521. LeaveCriticalSection(&DnsInterfaceLock);
  522. //
  523. // Attempt to connect it.
  524. //
  525. EnterCriticalSection(&DnsGlobalInfoLock);
  526. Error =
  527. DnsSupportFunctions.DemandDialRequest ?
  528. DnsSupportFunctions.DemandDialRequest(MS_IP_DNS_PROXY, Index) :
  529. NO_ERROR;
  530. LeaveCriticalSection(&DnsGlobalInfoLock);
  531. DEREFERENCE_DNS();
  532. return;
  533. }
  534. //
  535. // No interface is marked as the default.
  536. //
  537. LeaveCriticalSection(&DnsInterfaceLock);
  538. NhDialSharedConnection();
  539. NhWarningLog(
  540. IP_DNS_PROXY_LOG_NO_DEFAULT_INTERFACE,
  541. 0,
  542. ""
  543. );
  544. DEREFERENCE_DNS();
  545. } // DnsConnectDefaultInterface
  546. ULONG
  547. DnsConfigureInterface(
  548. ULONG Index,
  549. PIP_DNS_PROXY_INTERFACE_INFO InterfaceInfo
  550. )
  551. /*++
  552. Routine Description:
  553. This routine is called to set the configuration for an interface.
  554. Arguments:
  555. Index - the interface to be configured
  556. InterfaceInfo - the new configuration
  557. Return Value:
  558. ULONG - Win32 status code
  559. Environment:
  560. Invoked internally in the context of a IP router-manager thread.
  561. (See 'RMDNS.C').
  562. --*/
  563. {
  564. ULONG Error;
  565. PDNS_INTERFACE Interfacep;
  566. ULONG NewFlags;
  567. ULONG OldFlags;
  568. PROFILE("DnsConfigureInterface");
  569. //
  570. // Retrieve the interface to be configured
  571. //
  572. EnterCriticalSection(&DnsInterfaceLock);
  573. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  574. LeaveCriticalSection(&DnsInterfaceLock);
  575. NhTrace(
  576. TRACE_FLAG_IF,
  577. "DnsConfigureInterface: interface %d not found",
  578. Index
  579. );
  580. return ERROR_NO_SUCH_INTERFACE;
  581. }
  582. //
  583. // Reference the interface
  584. //
  585. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  586. LeaveCriticalSection(&DnsInterfaceLock);
  587. NhTrace(
  588. TRACE_FLAG_IF,
  589. "DnsConfigureInterface: interface %d cannot be referenced",
  590. Index
  591. );
  592. return ERROR_INTERFACE_DISABLED;
  593. }
  594. LeaveCriticalSection(&DnsInterfaceLock);
  595. Error = NO_ERROR;
  596. ACQUIRE_LOCK(Interfacep);
  597. //
  598. // Compare the interface's current and new configuration
  599. //
  600. OldFlags = Interfacep->Info.Flags;
  601. NewFlags =
  602. (InterfaceInfo
  603. ? (InterfaceInfo->Flags|DNS_INTERFACE_FLAG_CONFIGURED) : 0);
  604. Interfacep->Flags &= ~OldFlags;
  605. Interfacep->Flags |= NewFlags;
  606. if (!InterfaceInfo) {
  607. ZeroMemory(&Interfacep->Info, sizeof(*InterfaceInfo));
  608. //
  609. // The interface no longer has any information;
  610. // default to being enabled.
  611. //
  612. if (OldFlags & IP_DNS_PROXY_INTERFACE_FLAG_DISABLED) {
  613. //
  614. // Activate the interface if necessary
  615. //
  616. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  617. RELEASE_LOCK(Interfacep);
  618. Error = DnsActivateInterface(Interfacep);
  619. ACQUIRE_LOCK(Interfacep);
  620. }
  621. }
  622. }
  623. else {
  624. CopyMemory(&Interfacep->Info, InterfaceInfo, sizeof(*InterfaceInfo));
  625. //
  626. // Activate or deactivate the interface if its status changed
  627. //
  628. if ((OldFlags & IP_DNS_PROXY_INTERFACE_FLAG_DISABLED) &&
  629. !(NewFlags & IP_DNS_PROXY_INTERFACE_FLAG_DISABLED)) {
  630. //
  631. // Activate the interface
  632. //
  633. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  634. RELEASE_LOCK(Interfacep);
  635. Error = DnsActivateInterface(Interfacep);
  636. ACQUIRE_LOCK(Interfacep);
  637. }
  638. }
  639. else
  640. if (!(OldFlags & IP_DNS_PROXY_INTERFACE_FLAG_DISABLED) &&
  641. (NewFlags & IP_DNS_PROXY_INTERFACE_FLAG_DISABLED)) {
  642. //
  643. // Deactivate the interface if necessary
  644. //
  645. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  646. RELEASE_LOCK(Interfacep);
  647. DnsDeactivateInterface(Interfacep);
  648. ACQUIRE_LOCK(Interfacep);
  649. }
  650. }
  651. }
  652. RELEASE_LOCK(Interfacep);
  653. DNS_DEREFERENCE_INTERFACE(Interfacep);
  654. return Error;
  655. } // DnsConfigureInterface
  656. ULONG
  657. DnsCreateInterface(
  658. ULONG Index,
  659. NET_INTERFACE_TYPE Type,
  660. PIP_DNS_PROXY_INTERFACE_INFO InterfaceInfo,
  661. OUT PDNS_INTERFACE* InterfaceCreated
  662. )
  663. /*++
  664. Routine Description:
  665. This routine is invoked by the router-manager to add a new interface
  666. to the DNS proxy.
  667. Arguments:
  668. Index - the index of the new interface
  669. Type - the media type of the new interface
  670. InterfaceInfo - the interface's configuration
  671. Interfacep - receives the interface created
  672. Return Value:
  673. ULONG - Win32 error code
  674. Environment:
  675. Invoked internally in the context of an IP router-manager thread.
  676. (See 'RMDNS.C').
  677. --*/
  678. {
  679. PLIST_ENTRY InsertionPoint;
  680. PDNS_INTERFACE Interfacep;
  681. PROFILE("DnsCreateInterface");
  682. EnterCriticalSection(&DnsInterfaceLock);
  683. //
  684. // See if the interface already exists;
  685. // If not, this obtains the insertion point
  686. //
  687. if (DnsLookupInterface(Index, &InsertionPoint)) {
  688. LeaveCriticalSection(&DnsInterfaceLock);
  689. NhTrace(
  690. TRACE_FLAG_IF,
  691. "DnsCreateInterface: duplicate index found for %d",
  692. Index
  693. );
  694. return ERROR_INTERFACE_ALREADY_EXISTS;
  695. }
  696. //
  697. // Allocate a new interface
  698. //
  699. Interfacep = reinterpret_cast<PDNS_INTERFACE>(
  700. NH_ALLOCATE(sizeof(DNS_INTERFACE))
  701. );
  702. if (!Interfacep) {
  703. LeaveCriticalSection(&DnsInterfaceLock);
  704. NhTrace(
  705. TRACE_FLAG_IF, "DnsCreateInterface: error allocating interface"
  706. );
  707. NhErrorLog(
  708. IP_DNS_PROXY_LOG_ALLOCATION_FAILED,
  709. 0,
  710. "%d",
  711. sizeof(DNS_INTERFACE)
  712. );
  713. return ERROR_NOT_ENOUGH_MEMORY;
  714. }
  715. //
  716. // Initialize the new interface
  717. //
  718. ZeroMemory(Interfacep, sizeof(*Interfacep));
  719. __try {
  720. InitializeCriticalSection(&Interfacep->Lock);
  721. }
  722. __except(EXCEPTION_EXECUTE_HANDLER) {
  723. LeaveCriticalSection(&DnsInterfaceLock);
  724. NH_FREE(Interfacep);
  725. return GetExceptionCode();
  726. }
  727. Interfacep->Index = Index;
  728. Interfacep->Type = Type;
  729. if (InterfaceInfo) {
  730. Interfacep->Flags = InterfaceInfo->Flags|DNS_INTERFACE_FLAG_CONFIGURED;
  731. CopyMemory(&Interfacep->Info, InterfaceInfo, sizeof(*InterfaceInfo));
  732. }
  733. Interfacep->ReferenceCount = 1;
  734. InitializeListHead(&Interfacep->QueryList);
  735. InsertTailList(InsertionPoint, &Interfacep->Link);
  736. LeaveCriticalSection(&DnsInterfaceLock);
  737. if (InterfaceCreated) { *InterfaceCreated = Interfacep; }
  738. return NO_ERROR;
  739. } // DnsCreateInterface
  740. VOID
  741. DnsDeactivateInterface(
  742. PDNS_INTERFACE Interfacep
  743. )
  744. /*++
  745. Routine Description:
  746. This routine is called to deactivate an interface.
  747. It closes all sockets on the interface's bindings (if any).
  748. Arguments:
  749. Interfacep - the interface to be deactivated
  750. Return Value:
  751. none.
  752. Environment:
  753. Always invoked locally, with 'Interfacep' referenced by caller and/or
  754. 'DnsInterfaceLock' held by caller.
  755. --*/
  756. {
  757. ULONG i;
  758. PLIST_ENTRY Link;
  759. PDNS_QUERY Queryp;
  760. PROFILE("DnsDeactivateInterface");
  761. ACQUIRE_LOCK(Interfacep);
  762. //
  763. // Stop all network I/O on the interface's logical networks
  764. //
  765. for (i = 0; i < Interfacep->BindingCount; i++) {
  766. NhDeleteDatagramSocket(
  767. Interfacep->BindingArray[i].Socket[DnsProxyDns]
  768. );
  769. Interfacep->BindingArray[i].Socket[DnsProxyDns] = INVALID_SOCKET;
  770. NhDeleteDatagramSocket(
  771. Interfacep->BindingArray[i].Socket[DnsProxyWins]
  772. );
  773. Interfacep->BindingArray[i].Socket[DnsProxyWins] = INVALID_SOCKET;
  774. }
  775. //
  776. // Eliminate all pending queries
  777. //
  778. while (!IsListEmpty(&Interfacep->QueryList)) {
  779. Link = RemoveHeadList(&Interfacep->QueryList);
  780. Queryp = CONTAINING_RECORD(Link, DNS_QUERY, Link);
  781. NH_FREE(Queryp);
  782. }
  783. RELEASE_LOCK(Interfacep);
  784. } // DnsDeactivateInterface
  785. VOID NTAPI
  786. DnspDeferReadCallbackRoutine(
  787. PVOID Context,
  788. BOOLEAN TimedOut
  789. )
  790. /*++
  791. Routine Description:
  792. This routine is invoked to re-issue a deferred read when the countdown
  793. for the deferral completes.
  794. Arguments:
  795. Context - holds information identifying the interface and socket
  796. TimedOut - indicates whether the countdown completed
  797. Return Value:
  798. none.
  799. Environment:
  800. Invoked with an outstanding reference to the component on our behalf.
  801. --*/
  802. {
  803. PDNS_DEFER_READ_CONTEXT Contextp;
  804. ULONG Error;
  805. ULONG i;
  806. PDNS_INTERFACE Interfacep;
  807. NTSTATUS status;
  808. DNS_PROXY_TYPE Type;
  809. PROFILE("DnspDeferReadCallbackRoutine");
  810. Contextp = (PDNS_DEFER_READ_CONTEXT)Context;
  811. //
  812. // Find the interface on which the read was deferred
  813. //
  814. EnterCriticalSection(&DnsInterfaceLock);
  815. Interfacep = DnsLookupInterface(Contextp->Index, NULL);
  816. if (!Interfacep ||
  817. !DNS_INTERFACE_ACTIVE(Interfacep) ||
  818. !DNS_REFERENCE_INTERFACE(Interfacep)) {
  819. LeaveCriticalSection(&DnsInterfaceLock);
  820. NH_FREE(Contextp);
  821. DEREFERENCE_DNS();
  822. return;
  823. }
  824. LeaveCriticalSection(&DnsInterfaceLock);
  825. ACQUIRE_LOCK(Interfacep);
  826. //
  827. // Search for the socket on which to reissue the read
  828. //
  829. for (i = 0; i < Interfacep->BindingCount; i++) {
  830. if (Interfacep->BindingArray[i].Socket[Type = DnsProxyDns]
  831. != Contextp->Socket &&
  832. Interfacep->BindingArray[i].Socket[Type = DnsProxyWins]
  833. != Contextp->Socket) {
  834. continue;
  835. }
  836. //
  837. // This is the binding on which to reissue the read.
  838. // If no pending timer is recorded, assume a rebind occurred, and quit.
  839. //
  840. if (!Interfacep->BindingArray[i].TimerPending[Type]) { break; }
  841. Interfacep->BindingArray[i].TimerPending[Type] = FALSE;
  842. Error =
  843. NhReadDatagramSocket(
  844. &DnsComponentReference,
  845. Contextp->Socket,
  846. NULL,
  847. DnsReadCompletionRoutine,
  848. Interfacep,
  849. UlongToPtr(Interfacep->BindingArray[i].Address)
  850. );
  851. RELEASE_LOCK(Interfacep);
  852. if (!Error) {
  853. NH_FREE(Contextp);
  854. DEREFERENCE_DNS();
  855. return;
  856. }
  857. //
  858. // An error occurred; we'll have to retry later.
  859. // we queue a work item which sets the timer.
  860. //
  861. NhTrace(
  862. TRACE_FLAG_DNS,
  863. "DnspDeferReadCallbackRoutine: error %d reading interface %d",
  864. Error,
  865. Interfacep->Index
  866. );
  867. //
  868. // Reference the component on behalf of the work-item
  869. //
  870. if (REFERENCE_DNS()) {
  871. //
  872. // Queue a work-item, reusing the deferral context
  873. //
  874. status =
  875. RtlQueueWorkItem(
  876. DnspDeferReadWorkerRoutine,
  877. Contextp,
  878. WT_EXECUTEINIOTHREAD
  879. );
  880. if (NT_SUCCESS(status)) {
  881. Contextp = NULL;
  882. }
  883. else {
  884. NH_FREE(Contextp);
  885. NhTrace(
  886. TRACE_FLAG_DNS,
  887. "DnspDeferReadCallbackRoutine: error %d deferring %d",
  888. Error,
  889. Interfacep->Index
  890. );
  891. DEREFERENCE_DNS();
  892. }
  893. }
  894. DNS_DEREFERENCE_INTERFACE(Interfacep);
  895. DEREFERENCE_DNS();
  896. return;
  897. }
  898. //
  899. // The interface was not found; never mind.
  900. //
  901. RELEASE_LOCK(Interfacep);
  902. DNS_DEREFERENCE_INTERFACE(Interfacep);
  903. NH_FREE(Contextp);
  904. DEREFERENCE_DNS();
  905. } // DnspDeferReadCallbackRoutine
  906. VOID
  907. DnsDeferReadInterface(
  908. PDNS_INTERFACE Interfacep,
  909. SOCKET Socket
  910. )
  911. /*++
  912. Routine Description:
  913. This routine is invoked to defer a read-request on an interface,
  914. typically if an attempt to post a read failed.
  915. Arguments:
  916. Interfacep - the interface on which to defer the request
  917. Socket - the socket on which to defer the request
  918. Return Value:
  919. none.
  920. Environment:
  921. Invoked with 'Interfacep' locked by the caller.
  922. --*/
  923. {
  924. PDNS_DEFER_READ_CONTEXT Contextp;
  925. ULONG i;
  926. NTSTATUS status;
  927. DNS_PROXY_TYPE Type;
  928. PROFILE("DnsDeferReadInterface");
  929. //
  930. // Find the binding for the given socket.
  931. //
  932. status = STATUS_SUCCESS;
  933. for (i = 0; i < Interfacep->BindingCount; i++) {
  934. if (Interfacep->BindingArray[i].Socket[Type = DnsProxyDns] != Socket &&
  935. Interfacep->BindingArray[i].Socket[Type = DnsProxyWins] != Socket) {
  936. continue;
  937. }
  938. //
  939. // This is the binding. If there is already a timer for it,
  940. // then just return silently.
  941. //
  942. if (Interfacep->BindingArray[i].TimerPending[Type]) {
  943. status = STATUS_UNSUCCESSFUL;
  944. break;
  945. }
  946. //
  947. // Allocate a context block for the deferral.
  948. //
  949. Contextp =
  950. (PDNS_DEFER_READ_CONTEXT)
  951. NH_ALLOCATE(sizeof(DNS_DEFER_READ_CONTEXT));
  952. if (!Contextp) {
  953. NhTrace(
  954. TRACE_FLAG_DNS,
  955. "DnsDeferReadInterface: cannot allocate deferral context"
  956. );
  957. status = STATUS_NO_MEMORY;
  958. break;
  959. }
  960. Contextp->Index = Interfacep->Index;
  961. Contextp->Socket = Socket;
  962. Contextp->DeferralCount = 1;
  963. //
  964. // Install a timer to re-issue the read request
  965. //
  966. status =
  967. NhSetTimer(
  968. &DnsComponentReference,
  969. NULL,
  970. DnspDeferReadCallbackRoutine,
  971. Contextp,
  972. DNS_DEFER_READ_INITIAL_TIMEOUT
  973. );
  974. if (NT_SUCCESS(status)) {
  975. Interfacep->BindingArray[i].TimerPending[Type] = TRUE;
  976. }
  977. else {
  978. NH_FREE(Contextp);
  979. NhTrace(
  980. TRACE_FLAG_DNS,
  981. "DnsDeferReadInterface: status %08x setting deferral timer",
  982. status
  983. );
  984. }
  985. break;
  986. }
  987. if (i >= Interfacep->BindingCount) { status = STATUS_UNSUCCESSFUL; }
  988. } // DnsDeferReadInterface
  989. VOID APIENTRY
  990. DnspDeferReadWorkerRoutine(
  991. PVOID Context
  992. )
  993. /*++
  994. Routine Description:
  995. This routine is invoked to set a timer for reissuing a deferred read.
  996. Arguments:
  997. Context - contains the context for the timer.
  998. Return Value:
  999. none.
  1000. Environment:
  1001. Invoked with an outstanding reference to the module made on our behalf.
  1002. --*/
  1003. {
  1004. PDNS_DEFER_READ_CONTEXT Contextp;
  1005. ULONG i;
  1006. PDNS_INTERFACE Interfacep;
  1007. NTSTATUS status;
  1008. DNS_PROXY_TYPE Type;
  1009. PROFILE("DnspDeferReadWorkerRoutine");
  1010. Contextp = (PDNS_DEFER_READ_CONTEXT)Context;
  1011. ++Contextp->DeferralCount;
  1012. //
  1013. // Find the interface on which the read was deferred
  1014. //
  1015. EnterCriticalSection(&DnsInterfaceLock);
  1016. Interfacep = DnsLookupInterface(Contextp->Index, NULL);
  1017. if (!Interfacep ||
  1018. !DNS_INTERFACE_ACTIVE(Interfacep) ||
  1019. !DNS_REFERENCE_INTERFACE(Interfacep)) {
  1020. LeaveCriticalSection(&DnsInterfaceLock);
  1021. NH_FREE(Contextp);
  1022. DEREFERENCE_DNS();
  1023. return;
  1024. }
  1025. LeaveCriticalSection(&DnsInterfaceLock);
  1026. ACQUIRE_LOCK(Interfacep);
  1027. //
  1028. // Search for the binding on which to set the timer
  1029. //
  1030. for (i = 0; i < Interfacep->BindingCount; i++) {
  1031. if (Interfacep->BindingArray[i].Socket[Type = DnsProxyDns]
  1032. != Contextp->Socket &&
  1033. Interfacep->BindingArray[i].Socket[Type = DnsProxyWins]
  1034. != Contextp->Socket) {
  1035. continue;
  1036. }
  1037. //
  1038. // This is the binding on which to reissue the read.
  1039. // If a timer is already pending, assume a rebind occurred, and quit.
  1040. //
  1041. if (Interfacep->BindingArray[i].TimerPending[Type]) { break; }
  1042. //
  1043. // Install a timer to re-issue the read request,
  1044. // reusing the deferral context.
  1045. //
  1046. status =
  1047. NhSetTimer(
  1048. &DnsComponentReference,
  1049. NULL,
  1050. DnspDeferReadCallbackRoutine,
  1051. Contextp,
  1052. DNS_DEFER_READ_TIMEOUT
  1053. );
  1054. if (NT_SUCCESS(status)) {
  1055. Contextp = NULL;
  1056. Interfacep->BindingArray[i].TimerPending[Type] = TRUE;
  1057. }
  1058. else {
  1059. NhTrace(
  1060. TRACE_FLAG_DNS,
  1061. "DnspDeferReadWorkerRoutine: status %08x setting timer",
  1062. status
  1063. );
  1064. }
  1065. }
  1066. RELEASE_LOCK(Interfacep);
  1067. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1068. if (Contextp) { NH_FREE(Contextp); }
  1069. DEREFERENCE_DNS();
  1070. } // DnspDeferReadWorkerRoutine
  1071. ULONG
  1072. DnsDeleteInterface(
  1073. ULONG Index
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This routine is called to delete an interface.
  1078. It drops the reference count on the interface so that the last
  1079. dereferencer will delete the interface, and sets the 'deleted' flag
  1080. so that further references to the interface will fail.
  1081. Arguments:
  1082. Index - the index of the interface to be deleted
  1083. Return Value:
  1084. ULONG - Win32 status code.
  1085. Environment:
  1086. Invoked internally in the context of an IP router-manager thread.
  1087. (See 'RMDNS.C').
  1088. --*/
  1089. {
  1090. PDNS_INTERFACE Interfacep;
  1091. PROFILE("DnsDeleteInterface");
  1092. //
  1093. // Retrieve the interface to be deleted
  1094. //
  1095. EnterCriticalSection(&DnsInterfaceLock);
  1096. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1097. LeaveCriticalSection(&DnsInterfaceLock);
  1098. NhTrace(
  1099. TRACE_FLAG_IF,
  1100. "DnsDeleteInterface: interface %d not found",
  1101. Index
  1102. );
  1103. return ERROR_NO_SUCH_INTERFACE;
  1104. }
  1105. //
  1106. // Deactivate the interface
  1107. //
  1108. DnsDeactivateInterface(Interfacep);
  1109. //
  1110. // Mark the interface as deleted and take it off the interface list
  1111. //
  1112. Interfacep->Flags |= DNS_INTERFACE_FLAG_DELETED;
  1113. Interfacep->Flags &= ~DNS_INTERFACE_FLAG_ENABLED;
  1114. RemoveEntryList(&Interfacep->Link);
  1115. //
  1116. // Drop the reference count; if it is non-zero,
  1117. // the deletion will complete later.
  1118. //
  1119. if (--Interfacep->ReferenceCount) {
  1120. LeaveCriticalSection(&DnsInterfaceLock);
  1121. NhTrace(
  1122. TRACE_FLAG_IF,
  1123. "DnsDeleteInterface: interface %d deletion pending",
  1124. Index
  1125. );
  1126. return NO_ERROR;
  1127. }
  1128. //
  1129. // The reference count is zero, so perform final cleanup
  1130. //
  1131. DnsCleanupInterface(Interfacep);
  1132. LeaveCriticalSection(&DnsInterfaceLock);
  1133. return NO_ERROR;
  1134. } // DnsDeleteInterface
  1135. ULONG
  1136. DnsDisableInterface(
  1137. ULONG Index
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This routine is called to disable I/O on an interface.
  1142. If the interface is active, it is deactivated.
  1143. Arguments:
  1144. Index - the index of the interface to be disabled.
  1145. Return Value:
  1146. none.
  1147. Environment:
  1148. Invoked internally in the context of an IP router-manager thread.
  1149. (See 'RMDNS.C').
  1150. --*/
  1151. {
  1152. PDNS_INTERFACE Interfacep;
  1153. PROFILE("DnsDisableInterface");
  1154. //
  1155. // Retrieve the interface to be disabled
  1156. //
  1157. EnterCriticalSection(&DnsInterfaceLock);
  1158. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1159. LeaveCriticalSection(&DnsInterfaceLock);
  1160. NhTrace(
  1161. TRACE_FLAG_IF,
  1162. "DnsDisableInterface: interface %d not found",
  1163. Index
  1164. );
  1165. return ERROR_NO_SUCH_INTERFACE;
  1166. }
  1167. //
  1168. // Make sure the interface is not already disabled
  1169. //
  1170. if (!DNS_INTERFACE_ENABLED(Interfacep)) {
  1171. LeaveCriticalSection(&DnsInterfaceLock);
  1172. NhTrace(
  1173. TRACE_FLAG_IF,
  1174. "DnsDisableInterface: interface %d already disabled",
  1175. Index
  1176. );
  1177. return ERROR_INTERFACE_DISABLED;
  1178. }
  1179. //
  1180. // Reference the interface
  1181. //
  1182. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  1183. LeaveCriticalSection(&DnsInterfaceLock);
  1184. NhTrace(
  1185. TRACE_FLAG_IF,
  1186. "DnsDisableInterface: interface %d cannot be referenced",
  1187. Index
  1188. );
  1189. return ERROR_INTERFACE_DISABLED;
  1190. }
  1191. //
  1192. // Clear the 'enabled' flag
  1193. //
  1194. Interfacep->Flags &= ~DNS_INTERFACE_FLAG_ENABLED;
  1195. //
  1196. // Deactivate the interface, if necessary
  1197. //
  1198. if (DNS_INTERFACE_BOUND(Interfacep)) {
  1199. DnsDeactivateInterface(Interfacep);
  1200. }
  1201. LeaveCriticalSection(&DnsInterfaceLock);
  1202. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1203. return NO_ERROR;
  1204. } // DnsDisableInterface
  1205. ULONG
  1206. DnsEnableInterface(
  1207. ULONG Index
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. This routine is called to enable I/O on an interface.
  1212. If the interface is already bound, this enabling activates it.
  1213. Arguments:
  1214. Index - the index of the interfaec to be enabled
  1215. Return Value:
  1216. ULONG - Win32 status code.
  1217. Environment:
  1218. Invoked internally in the context of an IP router-manager thread.
  1219. (See 'RMDNS.C').
  1220. --*/
  1221. {
  1222. ULONG Error = NO_ERROR;
  1223. PDNS_INTERFACE Interfacep;
  1224. PROFILE("DnsEnableInterface");
  1225. //
  1226. // Retrieve the interface to be enabled
  1227. //
  1228. EnterCriticalSection(&DnsInterfaceLock);
  1229. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1230. LeaveCriticalSection(&DnsInterfaceLock);
  1231. NhTrace(
  1232. TRACE_FLAG_IF,
  1233. "DnsEnableInterface: interface %d not found",
  1234. Index
  1235. );
  1236. return ERROR_NO_SUCH_INTERFACE;
  1237. }
  1238. //
  1239. // Make sure the interface is not already enabled
  1240. //
  1241. if (DNS_INTERFACE_ENABLED(Interfacep)) {
  1242. LeaveCriticalSection(&DnsInterfaceLock);
  1243. NhTrace(
  1244. TRACE_FLAG_IF,
  1245. "DnsEnableInterface: interface %d already enabled",
  1246. Index
  1247. );
  1248. return ERROR_INTERFACE_ALREADY_EXISTS;
  1249. }
  1250. //
  1251. // Reference the interface
  1252. //
  1253. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  1254. LeaveCriticalSection(&DnsInterfaceLock);
  1255. NhTrace(
  1256. TRACE_FLAG_IF,
  1257. "DnsEnableInterface: interface %d cannot be referenced",
  1258. Index
  1259. );
  1260. return ERROR_INTERFACE_DISABLED;
  1261. }
  1262. //
  1263. // Set the 'enabled' flag
  1264. //
  1265. Interfacep->Flags |= DNS_INTERFACE_FLAG_ENABLED;
  1266. //
  1267. // Activate the interface, if necessary
  1268. //
  1269. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  1270. Error = DnsActivateInterface(Interfacep);
  1271. }
  1272. LeaveCriticalSection(&DnsInterfaceLock);
  1273. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1274. return Error;
  1275. } // DnsEnableInterface
  1276. ULONG
  1277. DnsInitializeInterfaceManagement(
  1278. VOID
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. This routine is called to initialize the interface-management module.
  1283. Arguments:
  1284. none.
  1285. Return Value:
  1286. ULONG - Win32 status code.
  1287. Environment:
  1288. Invoked internally in the context of an IP router-manager thread.
  1289. (See 'RMDNS.C').
  1290. --*/
  1291. {
  1292. ULONG Error = NO_ERROR;
  1293. PROFILE("DnsInitializeInterfaceManagement");
  1294. InitializeListHead(&DnsInterfaceList);
  1295. __try {
  1296. InitializeCriticalSection(&DnsInterfaceLock);
  1297. }
  1298. __except(EXCEPTION_EXECUTE_HANDLER) {
  1299. NhTrace(
  1300. TRACE_FLAG_IF,
  1301. "DnsInitializeInterfaceManagement: exception %d creating lock",
  1302. Error = GetExceptionCode()
  1303. );
  1304. }
  1305. DnspLastConnectAttemptTickCount = NtGetTickCount();
  1306. return Error;
  1307. } // DnsInitializeInterfaceManagement
  1308. PDNS_INTERFACE
  1309. DnsLookupInterface(
  1310. ULONG Index,
  1311. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  1312. )
  1313. /*++
  1314. Routine Description:
  1315. This routine is called to retrieve an interface given its index.
  1316. Arguments:
  1317. Index - the index of the interface to be retrieved
  1318. InsertionPoint - if the interface is not found, optionally receives
  1319. the point where the interface would be inserted in the interface list
  1320. Return Value:
  1321. PDNS_INTERFACE - the interface, if found; otherwise, NULL.
  1322. Environment:
  1323. Invoked internally from an arbitrary context, with 'DnsInterfaceLock'
  1324. held by caller.
  1325. --*/
  1326. {
  1327. PDNS_INTERFACE Interfacep;
  1328. PLIST_ENTRY Link;
  1329. PROFILE("DnsLookupInterface");
  1330. if (InsertionPoint)
  1331. {
  1332. *InsertionPoint = NULL;
  1333. }
  1334. for (Link = DnsInterfaceList.Flink;
  1335. Link != &DnsInterfaceList;
  1336. Link = Link->Flink
  1337. ) {
  1338. Interfacep = CONTAINING_RECORD(Link, DNS_INTERFACE, Link);
  1339. if (Index > Interfacep->Index) { continue; }
  1340. else
  1341. if (Index < Interfacep->Index) { break; }
  1342. return Interfacep;
  1343. }
  1344. if (InsertionPoint) { *InsertionPoint = Link; }
  1345. return NULL;
  1346. } // DnsLookupInterface
  1347. ULONG
  1348. DnsQueryInterface(
  1349. ULONG Index,
  1350. PVOID InterfaceInfo,
  1351. PULONG InterfaceInfoSize
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This routine is invoked to retrieve the configuration for an interface.
  1356. Arguments:
  1357. Index - the interface to be queried
  1358. InterfaceInfo - receives the retrieved information
  1359. InterfaceInfoSize - receives the (required) size of the information
  1360. Return Value:
  1361. ULONG - Win32 status code.
  1362. --*/
  1363. {
  1364. PDNS_INTERFACE Interfacep;
  1365. PROFILE("DnsQueryInterface");
  1366. //
  1367. // Check the caller's buffer size
  1368. //
  1369. if (!InterfaceInfoSize) { return ERROR_INVALID_PARAMETER; }
  1370. //
  1371. // Retrieve the interface to be configured
  1372. //
  1373. EnterCriticalSection(&DnsInterfaceLock);
  1374. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1375. LeaveCriticalSection(&DnsInterfaceLock);
  1376. NhTrace(
  1377. TRACE_FLAG_IF,
  1378. "DnsQueryInterface: interface %d not found",
  1379. Index
  1380. );
  1381. return ERROR_NO_SUCH_INTERFACE;
  1382. }
  1383. //
  1384. // Reference the interface
  1385. //
  1386. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  1387. LeaveCriticalSection(&DnsInterfaceLock);
  1388. NhTrace(
  1389. TRACE_FLAG_IF,
  1390. "DnsQueryInterface: interface %d cannot be referenced",
  1391. Index
  1392. );
  1393. return ERROR_INTERFACE_DISABLED;
  1394. }
  1395. //
  1396. // See if there is any explicit config on this interface
  1397. //
  1398. if (!DNS_INTERFACE_CONFIGURED(Interfacep)) {
  1399. LeaveCriticalSection(&DnsInterfaceLock);
  1400. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1401. NhTrace(
  1402. TRACE_FLAG_IF,
  1403. "DnsQueryInterface: interface %d has no configuration",
  1404. Index
  1405. );
  1406. *InterfaceInfoSize = 0;
  1407. return NO_ERROR;
  1408. }
  1409. //
  1410. // See if there is enough buffer space
  1411. //
  1412. if (*InterfaceInfoSize < sizeof(IP_DNS_PROXY_INTERFACE_INFO)) {
  1413. LeaveCriticalSection(&DnsInterfaceLock);
  1414. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1415. *InterfaceInfoSize = sizeof(IP_DNS_PROXY_INTERFACE_INFO);
  1416. return ERROR_INSUFFICIENT_BUFFER;
  1417. }
  1418. if (!InterfaceInfo) {
  1419. LeaveCriticalSection(&DnsInterfaceLock);
  1420. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1421. return ERROR_INVALID_PARAMETER;
  1422. }
  1423. //
  1424. // Copy the requested data
  1425. //
  1426. CopyMemory(
  1427. InterfaceInfo,
  1428. &Interfacep->Info,
  1429. sizeof(IP_DNS_PROXY_INTERFACE_INFO)
  1430. );
  1431. *InterfaceInfoSize = sizeof(IP_DNS_PROXY_INTERFACE_INFO);
  1432. LeaveCriticalSection(&DnsInterfaceLock);
  1433. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1434. return NO_ERROR;
  1435. } // DnsQueryInterface
  1436. VOID
  1437. DnsReactivateEveryInterface(
  1438. VOID
  1439. )
  1440. /*++
  1441. Routine Description:
  1442. This routine is called to reactivate all activate interfaces
  1443. when a change occurs to the global DNS or WINS proxy setting.
  1444. Thus if, for instance, WINS proxy is disabled, during deactivation
  1445. all such sockets are closed, and during reactivation they are
  1446. not reopened.
  1447. Arguments:
  1448. none.
  1449. Return Value:
  1450. none.
  1451. Environment:
  1452. Invoked from a router-manager thread with no locks held.
  1453. --*/
  1454. {
  1455. PDNS_INTERFACE Interfacep;
  1456. PLIST_ENTRY Link;
  1457. PROFILE("DnsReactivateEveryInterface");
  1458. EnterCriticalSection(&DnsInterfaceLock);
  1459. for (Link = DnsInterfaceList.Flink;
  1460. Link != &DnsInterfaceList;
  1461. Link = Link->Flink
  1462. ) {
  1463. Interfacep = CONTAINING_RECORD(Link, DNS_INTERFACE, Link);
  1464. if (!DNS_REFERENCE_INTERFACE(Interfacep)) { continue; }
  1465. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  1466. DnsDeactivateInterface(Interfacep);
  1467. DnsActivateInterface(Interfacep);
  1468. }
  1469. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1470. }
  1471. LeaveCriticalSection(&DnsInterfaceLock);
  1472. } // DnsReactivateEveryInterface
  1473. ULONG NTAPI
  1474. DnspSaveFileWorkerRoutine(
  1475. PVOID Context
  1476. )
  1477. {
  1478. //
  1479. // Context unused
  1480. //
  1481. PROFILE("DnspSaveFileWorkerRoutine");
  1482. SaveHostsIcsFile(FALSE);
  1483. DEREFERENCE_DNS();
  1484. return NO_ERROR;
  1485. } // DnspSaveFileWorkerRoutine
  1486. VOID
  1487. DnsShutdownInterfaceManagement(
  1488. VOID
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This routine is called to shutdown the interface-management module.
  1493. Arguments:
  1494. none.
  1495. Return Value:
  1496. none.
  1497. Environment:
  1498. Invoked in an arbitrary thread context, after all references
  1499. to all interfaces have been released.
  1500. --*/
  1501. {
  1502. PDNS_INTERFACE Interfacep;
  1503. PLIST_ENTRY Link;
  1504. PROFILE("DnsShutdownInterfaceManagement");
  1505. while (!IsListEmpty(&DnsInterfaceList)) {
  1506. Link = RemoveHeadList(&DnsInterfaceList);
  1507. Interfacep = CONTAINING_RECORD(Link, DNS_INTERFACE, Link);
  1508. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  1509. DnsDeactivateInterface(Interfacep);
  1510. }
  1511. DnsCleanupInterface(Interfacep);
  1512. }
  1513. DeleteCriticalSection(&DnsInterfaceLock);
  1514. } // DnsShutdownInterfaceManagement
  1515. VOID
  1516. DnsSignalNatInterface(
  1517. ULONG Index,
  1518. BOOLEAN Boundary
  1519. )
  1520. /*++
  1521. Routine Description:
  1522. This routine is invoked upon reconfiguration of a NAT interface.
  1523. Note that this routine may be invoked even when the DNS proxy
  1524. is neither installed nor running; it operates as expected,
  1525. since the interface list and lock are always initialized.
  1526. Upon invocation, the routine activates or deactivates the interface
  1527. depending on whether the NAT is not or is running on the interface,
  1528. respectively.
  1529. Arguments:
  1530. Index - the reconfigured interface
  1531. Boundary - indicates whether the interface is now a boundary interface
  1532. Return Value:
  1533. none.
  1534. Environment:
  1535. Invoked from an arbitrary context.
  1536. --*/
  1537. {
  1538. PDNS_INTERFACE Interfacep;
  1539. PROFILE("DnsSignalNatInterface");
  1540. EnterCriticalSection(&DnsGlobalInfoLock);
  1541. if (!DnsGlobalInfo) {
  1542. LeaveCriticalSection(&DnsGlobalInfoLock);
  1543. return;
  1544. }
  1545. LeaveCriticalSection(&DnsGlobalInfoLock);
  1546. EnterCriticalSection(&DnsInterfaceLock);
  1547. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1548. LeaveCriticalSection(&DnsInterfaceLock);
  1549. return;
  1550. }
  1551. DnsDeactivateInterface(Interfacep);
  1552. if (DNS_INTERFACE_ACTIVE(Interfacep)) {
  1553. DnsActivateInterface(Interfacep);
  1554. }
  1555. LeaveCriticalSection(&DnsInterfaceLock);
  1556. } // DnsSignalNatInterface
  1557. ULONG
  1558. DnsUnbindInterface(
  1559. ULONG Index
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine is invoked to revoke the binding on an interface.
  1564. This involves deactivating the interface if it is active.
  1565. Arguments:
  1566. Index - the index of the interface to be unbound
  1567. Return Value:
  1568. none.
  1569. Environment:
  1570. Invoked internally in the context of an IP router-manager thread.
  1571. (See 'RMDNS.C').
  1572. --*/
  1573. {
  1574. PDNS_INTERFACE Interfacep;
  1575. PROFILE("DnsUnbindInterface");
  1576. //
  1577. // Retrieve the interface to be unbound
  1578. //
  1579. EnterCriticalSection(&DnsInterfaceLock);
  1580. if (!(Interfacep = DnsLookupInterface(Index, NULL))) {
  1581. LeaveCriticalSection(&DnsInterfaceLock);
  1582. NhTrace(
  1583. TRACE_FLAG_IF,
  1584. "DnsUnbindInterface: interface %d not found",
  1585. Index
  1586. );
  1587. return ERROR_NO_SUCH_INTERFACE;
  1588. }
  1589. //
  1590. // Make sure the interface is not already unbound
  1591. //
  1592. if (!DNS_INTERFACE_BOUND(Interfacep)) {
  1593. LeaveCriticalSection(&DnsInterfaceLock);
  1594. NhTrace(
  1595. TRACE_FLAG_IF,
  1596. "DnsUnbindInterface: interface %d already unbound",
  1597. Index
  1598. );
  1599. return ERROR_ADDRESS_NOT_ASSOCIATED;
  1600. }
  1601. //
  1602. // Reference the interface
  1603. //
  1604. if (!DNS_REFERENCE_INTERFACE(Interfacep)) {
  1605. LeaveCriticalSection(&DnsInterfaceLock);
  1606. NhTrace(
  1607. TRACE_FLAG_IF,
  1608. "DnsUnbindInterface: interface %d cannot be referenced",
  1609. Index
  1610. );
  1611. return ERROR_INTERFACE_DISABLED;
  1612. }
  1613. //
  1614. // Clear the 'bound' flag
  1615. //
  1616. Interfacep->Flags &= ~DNS_INTERFACE_FLAG_BOUND;
  1617. //
  1618. // Deactivate the interface, if necessary
  1619. //
  1620. if (DNS_INTERFACE_ENABLED(Interfacep)) {
  1621. DnsDeactivateInterface(Interfacep);
  1622. }
  1623. LeaveCriticalSection(&DnsInterfaceLock);
  1624. //
  1625. // Destroy the interface's binding
  1626. //
  1627. ACQUIRE_LOCK(Interfacep);
  1628. if (Interfacep->BindingArray)
  1629. {
  1630. NH_FREE(Interfacep->BindingArray);
  1631. Interfacep->BindingArray = NULL;
  1632. }
  1633. Interfacep->BindingCount = 0;
  1634. RELEASE_LOCK(Interfacep);
  1635. DNS_DEREFERENCE_INTERFACE(Interfacep);
  1636. return NO_ERROR;
  1637. } // DnsUnbindInterface
  1638. ULONG
  1639. DnsGetPrivateInterfaceAddress(
  1640. VOID
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. This routine is invoked to return the IP address on which DNS
  1645. has been enabled.
  1646. Arguments:
  1647. none.
  1648. Return Value:
  1649. Bound IP address if an address is found (else 0).
  1650. Environment:
  1651. Invoked from an arbitrary context.
  1652. --*/
  1653. {
  1654. PROFILE("DnsGetPrivateInterfaceAddress");
  1655. ULONG ipAddr = 0;
  1656. ULONG ulRet = NO_ERROR;
  1657. //
  1658. // Find out the first available interface on which we are enabled and
  1659. // return the primary IP address to which we are bound.
  1660. //
  1661. PDNS_INTERFACE Interfacep = NULL;
  1662. PLIST_ENTRY Link;
  1663. ULONG i;
  1664. BOOLEAN IsNatInterface;
  1665. EnterCriticalSection(&DnsInterfaceLock);
  1666. for (Link = DnsInterfaceList.Flink;
  1667. Link != &DnsInterfaceList;
  1668. Link = Link->Flink
  1669. )
  1670. {
  1671. Interfacep = CONTAINING_RECORD(Link, DNS_INTERFACE, Link);
  1672. ACQUIRE_LOCK(Interfacep);
  1673. if (DnsInterfacePrivate != Interfacep->DnsInterfaceType)
  1674. {
  1675. RELEASE_LOCK(Interfacep);
  1676. continue;
  1677. }
  1678. for (i = 0; i < Interfacep->BindingCount; i++)
  1679. {
  1680. NhTrace(
  1681. TRACE_FLAG_DNS,
  1682. "DnsGetPrivateInterfaceAddress: IP address %s (Index %d)",
  1683. INET_NTOA(Interfacep->BindingArray[i].Address),
  1684. Interfacep->Index
  1685. );
  1686. if (Interfacep->BindingArray[i].Address &
  1687. Interfacep->BindingArray[i].Mask)
  1688. {
  1689. ipAddr = Interfacep->BindingArray[i].Address;
  1690. break;
  1691. }
  1692. }
  1693. RELEASE_LOCK(Interfacep);
  1694. if (ipAddr)
  1695. {
  1696. LeaveCriticalSection(&DnsInterfaceLock);
  1697. NhTrace(
  1698. TRACE_FLAG_DNS,
  1699. "DnsGetPrivateInterfaceAddress: Dns private interface IP address %s (Index %d)",
  1700. INET_NTOA(ipAddr),
  1701. Interfacep->Index
  1702. );
  1703. return ipAddr;
  1704. }
  1705. }
  1706. LeaveCriticalSection(&DnsInterfaceLock);
  1707. return ipAddr;
  1708. } // DnsGetPrivateInterfaceAddress