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.

884 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. ops.c
  5. Abstract:
  6. DNS Resolver Service.
  7. Remote APIs to resolver service.
  8. Author:
  9. Jim Gilroy (jamesg) November 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Max number to enum at a time
  15. //
  16. #define MAX_CACHE_ENUM_COUNT (500)
  17. //
  18. // Enum operations
  19. //
  20. // Tag is DWORD with
  21. // - high word the hash bucket index
  22. // - low word the entry count
  23. //
  24. #define MakeEnumTag(h,e) MAKEDWORD( (WORD)e, (WORD)h )
  25. #define HashBucketFromEnumTag(t) HIWORD(t)
  26. #define EntryIndexFromEnumTag(t) LOWORD(t)
  27. #define GetRpcRecords(p,t,pi) (NULL)
  28. #define AllocRpcName( s ) Dns_StringCopyAllocate_W( (s), 0 )
  29. DNS_STATUS
  30. R_ResolverEnumCache(
  31. IN DNS_RPC_HANDLE Handle,
  32. IN PDNS_CACHE_ENUM_REQUEST pRequest,
  33. OUT PDNS_CACHE_ENUM * ppEnum
  34. )
  35. /*++
  36. Routine Description:
  37. Enumerate entries in cache.
  38. Arguments:
  39. RpcHandle -- RPC handle
  40. pRequest -- ptr to Enum request
  41. ppEnum -- addr to recv pointer to enumeration
  42. Return Value:
  43. ERROR_SUCCESS if successful.
  44. ErrorCode on failure to enum.
  45. --*/
  46. {
  47. DNS_STATUS status = ERROR_SUCCESS;
  48. PDNS_CACHE_ENUM penum = NULL;
  49. BOOL flocked = FALSE;
  50. DWORD count = 0;
  51. DWORD maxCount = 0;
  52. DWORD entryCount = 0;
  53. DWORD entryStart;
  54. WORD typeRequest = 0;
  55. DWORD hashStart;
  56. DWORD ihash;
  57. PDNS_RECORD prr;
  58. PDNS_CACHE_ENTRY prpcEntry;
  59. DNSDBG( RPC, ( "\nR_ResolverEnumCache\n" ));
  60. DNSLOG_F1( "Resolver - R_ResolverEnumCache" );
  61. if ( !ppEnum || !pRequest )
  62. {
  63. return ERROR_INVALID_PARAMETER;
  64. }
  65. *ppEnum = NULL;
  66. if ( ClientThreadNotAllowedAccess() )
  67. {
  68. status = ERROR_ACCESS_DENIED;
  69. goto Done;
  70. }
  71. //
  72. // allocate desired space
  73. //
  74. maxCount = pRequest->MaxCount;
  75. if ( maxCount > MAX_CACHE_ENUM_COUNT )
  76. {
  77. maxCount = MAX_CACHE_ENUM_COUNT;
  78. }
  79. penum = (PDNS_CACHE_ENUM)
  80. RPC_HEAP_ALLOC_ZERO(
  81. sizeof(DNS_CACHE_ENUM) +
  82. (maxCount * sizeof(DNS_CACHE_ENTRY)) );
  83. if ( !penum )
  84. {
  85. status = DNS_ERROR_NO_MEMORY;
  86. goto Done;
  87. }
  88. //
  89. // read entries starting from EnumTag
  90. //
  91. LOCK_CACHE();
  92. flocked = TRUE;
  93. count = 0;
  94. typeRequest = pRequest->Type;
  95. hashStart = HashBucketFromEnumTag( pRequest->EnumTag );
  96. entryStart = EntryIndexFromEnumTag( pRequest->EnumTag );
  97. //
  98. // enum next DCR: issue of CNAME here?
  99. //
  100. for ( ihash = hashStart; ihash < g_HashTableSize; ihash++ )
  101. {
  102. PCACHE_ENTRY pentry = g_HashTable[ihash];
  103. entryCount = 0;
  104. while ( pentry )
  105. {
  106. DWORD index = 0;
  107. // skip any entries in previous enum
  108. if ( ihash == hashStart &&
  109. entryCount < entryStart )
  110. {
  111. pentry = pentry->pNext;
  112. entryCount++;
  113. continue;
  114. }
  115. // write enum entries matching criteria
  116. while( count < maxCount )
  117. {
  118. prr = GetRpcRecords(
  119. pentry,
  120. typeRequest,
  121. & index );
  122. if ( !prr )
  123. {
  124. break;
  125. }
  126. prpcEntry = &penum->EntryArray[count];
  127. prpcEntry->pName = AllocRpcName( pentry->pName );
  128. prpcEntry->wType = typeRequest;
  129. count++;
  130. }
  131. pentry = pentry->pNext;
  132. entryCount++;
  133. }
  134. }
  135. //
  136. // set return params
  137. // if exhaust cache -- success
  138. // if more data, set termination tag to restart
  139. //
  140. penum->TotalCount = g_EntryCount;
  141. penum->EnumCount = count;
  142. penum->EnumTagStart = pRequest->EnumTag;
  143. if ( ihash == g_HashTableSize )
  144. {
  145. status = ERROR_SUCCESS;
  146. }
  147. else
  148. {
  149. status = ERROR_MORE_DATA;
  150. penum->EnumTagStop = (DWORD) MAKELONG( entryCount, ihash );
  151. }
  152. *ppEnum = penum;
  153. Done:
  154. UNLOCK_CACHE();
  155. DNSDBG( RPC, (
  156. "Leave R_ResolverEnumCache()\n"
  157. "\tstatus = %d\n"
  158. "\ttotal count = %d\n"
  159. "\ttag start = %p\n"
  160. "\ttag end = %p\n"
  161. "\tcount = %d\n\n",
  162. status,
  163. penum->TotalCount,
  164. penum->EnumTagStart,
  165. penum->EnumTagStop,
  166. penum->EnumCount ));
  167. return( status );
  168. }
  169. //
  170. // Cache operations
  171. //
  172. DNS_STATUS
  173. R_ResolverFlushCache(
  174. IN DNS_RPC_HANDLE Handle
  175. )
  176. /*++
  177. Routine Description:
  178. Flush resolver cache.
  179. Arguments:
  180. Handle -- RPC handle
  181. Return Value:
  182. ERROR_SUCCESS if successful.
  183. ERROR_ACCESS_DENIED if unable to flush.
  184. --*/
  185. {
  186. DNSDBG( RPC, ( "\nR_ResolverFlushCache\n" ));
  187. //
  188. // DCR: flush should have security
  189. //
  190. if ( ClientThreadNotAllowedAccess() )
  191. {
  192. DNSLOG_F1( "R_ResolverFlushCache - ERROR_ACCESS_DENIED" );
  193. return ERROR_ACCESS_DENIED;
  194. }
  195. //
  196. // flush cache
  197. //
  198. Cache_Flush();
  199. DNSDBG( RPC, ( "Leave R_ResolverFlushCache\n\n" ));
  200. return ERROR_SUCCESS;
  201. }
  202. DNS_STATUS
  203. R_ResolverFlushCacheEntry(
  204. IN DNS_RPC_HANDLE Handle,
  205. IN PWSTR pwsName,
  206. IN WORD wType
  207. )
  208. /*++
  209. Routine Description:
  210. Flush data from resolver cache.
  211. Arguments:
  212. Handle -- RPC handle
  213. pwsName -- name to flush (if NULL flush entire cache)
  214. wType -- type to flush; if zero, flush entire entry for name
  215. Return Value:
  216. ERROR_SUCCESS if successful.
  217. ERROR_ACCESS_DENIED if unable to flush.
  218. --*/
  219. {
  220. DNSLOG_F1( "R_ResolverFlushCacheEntry" );
  221. DNSLOG_F2( " Name : %S", pwsName );
  222. DNSLOG_F2( " Type : %d", wType );
  223. DNSDBG( RPC, (
  224. "R_ResolverFlushCacheEntry\n"
  225. "\tName = %p %S\n"
  226. "\tType = %d\n",
  227. pwsName, pwsName,
  228. wType ));
  229. if ( !pwsName )
  230. {
  231. return ERROR_INVALID_PARAMETER;
  232. }
  233. //
  234. // two levels
  235. // 1) - no type => flush the whole name entry
  236. // 2) - name and type => flush on particular RR set
  237. //
  238. Cache_FlushRecords(
  239. pwsName,
  240. wType
  241. ? FLUSH_LEVEL_NORMAL
  242. : FLUSH_LEVEL_WIRE,
  243. wType
  244. );
  245. DNSDBG( RPC, ( "Leave R_ResolverFlushCacheEntry\n\n" ));
  246. return ERROR_SUCCESS;
  247. }
  248. //
  249. // Query API utilities
  250. //
  251. DNS_STATUS
  252. ResolverQuery(
  253. IN OUT PQUERY_BLOB pBlob
  254. )
  255. /*++
  256. Routine Description:
  257. Make the query to DNS server.
  258. Arguments:
  259. pBlob -- query blob
  260. Return Value:
  261. ERROR_SUCCESS if successful response.
  262. DNS_INFO_NO_RECORDS on no records for type response.
  263. DNS_ERROR_RCODE_NAME_ERROR on name error.
  264. DNS_ERROR_INVALID_NAME on bad name.
  265. None
  266. --*/
  267. {
  268. DNS_STATUS status = ERROR_SUCCESS;
  269. PDNS_NETINFO pnetInfo = NULL;
  270. BOOL fadapterTimedOut = FALSE;
  271. DNS_STATUS statusNetFailure = ERROR_SUCCESS;
  272. DNSDBG( TRACE, (
  273. "ResolverQuery( %S, type=%d, f=%08x )\n",
  274. pBlob->pNameOrig,
  275. pBlob->wType,
  276. pBlob->Flags ));
  277. //
  278. // skip query -- timeouts -- entirely if net down
  279. //
  280. if ( IsKnownNetFailure() )
  281. {
  282. status = GetLastError();
  283. DNSLOG_F2(
  284. "Not going query since there is a known net failure: 0x%.8X",
  285. status );
  286. DNSDBG( ANY, (
  287. "WARNING: known net failure %d, suppressing queries!\n",
  288. status ));
  289. return status;
  290. }
  291. //
  292. // get valid network info
  293. //
  294. pnetInfo = GrabNetworkInfo();
  295. if ( ! pnetInfo )
  296. {
  297. DNSDBG( ANY, ( "ERROR: GrabNetworkInfo() failed!\n" ));
  298. return DNS_ERROR_NO_DNS_SERVERS;
  299. }
  300. pBlob->pNetworkInfo = pnetInfo;
  301. //
  302. // cluster filtering setup
  303. //
  304. if ( g_IsServer )
  305. {
  306. pBlob->pfnIsClusterIp = IsClusterAddress;
  307. }
  308. //
  309. // query
  310. // includes
  311. // - local name check
  312. // - wire query
  313. //
  314. status = Query_Main( pBlob );
  315. statusNetFailure = pBlob->NetFailureStatus;
  316. #if 0
  317. //
  318. // DCR: missing catching intermediate failures
  319. //
  320. //
  321. // reset server priorities on failures
  322. // do here to avoid washing out info in retry with new name
  323. //
  324. if ( status != ERROR_SUCCESS &&
  325. pnetInfo->ReturnFlags & DNS_FLAG_RESET_SERVER_PRIORITY )
  326. {
  327. if ( g_AdapterTimeoutCacheTime &&
  328. Dns_DisableTimedOutAdapters( pnetInfo ) )
  329. {
  330. fadapterTimedOut = TRUE;
  331. SetKnownTimedOutAdapter();
  332. }
  333. }
  334. #endif
  335. //
  336. // success
  337. // - drop message popup count
  338. //
  339. if ( status == ERROR_SUCCESS )
  340. {
  341. #if 0
  342. // don't see any point in locking for this crap
  343. // as long as don't decrement anywhere, and even
  344. // then success reset should make it ok
  345. LOCK_NET_FAILURE();
  346. if ( g_MessagePopupStrikes > 0 )
  347. g_MessagePopupStrikes--;
  348. UNLOCK_NET_FAILURE();
  349. #endif
  350. g_MessagePopupStrikes = 0;
  351. }
  352. //
  353. // network failure condition
  354. // - anything but ERROR_TIMEOUT is net failure
  355. //
  356. // timeout error indicates possible net down condition
  357. // - ping DNS servers
  358. // if down shutdown queries for short interval; this
  359. // eliminates long timeouts in boot up during netdown
  360. // condition
  361. //
  362. // DCR: this is stupid -- ping especially
  363. //
  364. // should just keep a count, if count rises back off;
  365. // why we should do useless query (ping) is beyond me
  366. // rather than just doing another query; only advantage
  367. // of ping is that it should succeed immediately
  368. //
  369. // furthermore any tracking for this that we do do should
  370. // be in single routine saving the network info
  371. //
  372. else if ( statusNetFailure )
  373. {
  374. if ( statusNetFailure == ERROR_TIMEOUT )
  375. {
  376. #if 0
  377. DWORD iter;
  378. BOOL fping = FALSE;
  379. PDNS_ADAPTER padapter;
  380. for ( iter = 0; iter < pnetInfo->cAdapterCount; iter++ )
  381. {
  382. padapter = pnetInfo->AdapterArray[iter];
  383. if ( padapter &&
  384. g_NetFailureCacheTime &&
  385. Dns_PingAdapterServers( padapter ) )
  386. {
  387. fping = TRUE;
  388. break;
  389. }
  390. }
  391. if ( !fping )
  392. {
  393. SetKnownNetFailure( status );
  394. }
  395. #endif
  396. }
  397. else
  398. {
  399. SetKnownNetFailure( status );
  400. }
  401. }
  402. //
  403. // save change in adapter priority
  404. //
  405. if ( pnetInfo->ReturnFlags & RUN_FLAG_RESET_SERVER_PRIORITY )
  406. {
  407. UpdateNetworkInfo( pnetInfo );
  408. }
  409. else
  410. {
  411. NetInfo_Free( pnetInfo );
  412. }
  413. pBlob->pNetworkInfo = NULL;
  414. DNSDBG( QUERY, (
  415. "Leave ResolverQuery() => %d\n",
  416. status ));
  417. IF_DNSDBG( QUERY )
  418. {
  419. DnsDbg_QueryBlob(
  420. "Blob leaving ResolverQuery()",
  421. pBlob );
  422. }
  423. return status;
  424. }
  425. //
  426. // Query API
  427. //
  428. #ifdef DNS_TRY_ASYNC
  429. VOID
  430. R_ResolverQueryAsync(
  431. IN PRPC_ASYNC_STATE AsyncHandle,
  432. IN DNS_RPC_HANDLE Handle,
  433. IN OUT PRPC_QUERY_BLOB pBlob
  434. )
  435. /*++
  436. Routine Description:
  437. Query the resolver.
  438. Arguments:
  439. pBlob -- ptr to query info and results buffer
  440. Return Value:
  441. ERROR_SUCCESS if successful.
  442. ErrorCode (including DNS RCODE) on failure.
  443. --*/
  444. {
  445. DNS_STATUS status = ERROR_SUCCESS;
  446. PDNS_RECORD prr = NULL;
  447. PDNS_RECORD prrQuery = NULL;
  448. PDNS_RECORD presultRR = NULL;
  449. PCACHE_ENTRY pentry = NULL;
  450. BOOL locked = FALSE;
  451. BOOL fcacheNegativeResponse = FALSE;
  452. CHAR nameUtf8[ DNS_MAX_NAME_BUFFER_LENGTH+1 ];
  453. DWORD nameBufLength = DNS_MAX_NAME_BUFFER_LENGTH;
  454. // DCR_CLEANUP: make local
  455. // quickie define to old args
  456. PWSTR pwsName = pBlob->pName;
  457. WORD Type = pBlob->wType;
  458. DWORD Flags = pBlob->Flags;
  459. DNSLOG_F1( "R_ResolverQuery" );
  460. DNSLOG_F1( " Arguments:" );
  461. DNSLOG_F2( " Name : %S", pwsName );
  462. DNSLOG_F2( " Type : %d", Type );
  463. DNSLOG_F2( " Flags : 0x%x", Flags );
  464. DNSDBG( RPC, (
  465. "\nR_ResolverQuery( %S, t=%d, f=%08x )\n",
  466. pwsName,
  467. Type,
  468. Flags ));
  469. //
  470. // cacheable response
  471. //
  472. Done:
  473. //
  474. // put results in blob
  475. //
  476. pBlob->pRecords = presultRR;
  477. pBlob->Status = status;
  478. DNSLOG_F3(
  479. "R_ResolverQuery - status : 0x%.8X\n\t%s",
  480. status,
  481. Dns_StatusString( status ) );
  482. DNSLOG_F1( "" );
  483. DNSDBG( RPC, (
  484. "Leave R_ResolverQuery( %S, t=%d, f=%08x )\n\n",
  485. pwsName,
  486. Type,
  487. Flags ));
  488. }
  489. #endif
  490. BOOL
  491. ResolverCacheQueryCallback(
  492. IN OUT PQUERY_BLOB pBlob
  493. )
  494. /*++
  495. Routine Description:
  496. Check cache for name.
  497. This is callback to check appended names.
  498. Arguments:
  499. pBlob -- query blob
  500. Return Value:
  501. TRUE if name and type found.
  502. FALSE otherwise.
  503. --*/
  504. {
  505. //
  506. // check cache for name and type
  507. //
  508. if ( SKIP_CACHE_LOOKUP(pBlob->Flags) )
  509. {
  510. return FALSE;
  511. }
  512. //
  513. // copy name back to unicode
  514. //
  515. if ( ! Dns_NameCopyWireToUnicode(
  516. pBlob->NameBufferWide,
  517. pBlob->pNameWire ) )
  518. {
  519. DNSDBG( ANY, (
  520. "Invalid name %s.\n",
  521. pBlob->pNameWire ));
  522. DNS_ASSERT( FALSE );
  523. return FALSE;
  524. }
  525. //
  526. // lookup in cache
  527. //
  528. return Cache_GetRecordsForRpc(
  529. & pBlob->pRecords,
  530. & pBlob->Status,
  531. pBlob->NameBufferWide,
  532. pBlob->wType,
  533. pBlob->Flags
  534. );
  535. }
  536. DNS_STATUS
  537. R_ResolverQuery(
  538. IN DNS_RPC_HANDLE Handle,
  539. IN PWSTR pwsName,
  540. IN WORD wType,
  541. IN DWORD Flags,
  542. OUT PDNS_RECORD * ppResultRecords
  543. )
  544. /*++
  545. Routine Description:
  546. Simple query to resolver.
  547. Arguments:
  548. Return Value:
  549. ERROR_SUCCESS if query successful.
  550. ErrorCode on failure.
  551. --*/
  552. {
  553. DNS_STATUS status = ERROR_SUCCESS;
  554. PDNS_RECORD prrReturn = NULL;
  555. QUERY_BLOB blob;
  556. DNSLOG_F1( "DNS Caching Resolver Service - R_ResolverQuery" );
  557. DNSLOG_F1( " Arguments:" );
  558. DNSLOG_F2( " Name : %S", pwsName );
  559. DNSLOG_F2( " Type : %d", wType );
  560. DNSLOG_F2( " Flags : 0x%x", Flags );
  561. DNSDBG( RPC, (
  562. "\nR_ResolverQuery( %S, t=%d, f=%08x )\n",
  563. pwsName,
  564. wType,
  565. Flags ));
  566. if ( !ppResultRecords )
  567. {
  568. return ERROR_INVALID_PARAMETER;
  569. }
  570. if ( ClientThreadNotAllowedAccess() )
  571. {
  572. DNSLOG_F1( "R_ResolverQuery - ERROR_ACCESS_DENIED" );
  573. status = ERROR_ACCESS_DENIED;
  574. goto Done;
  575. }
  576. //
  577. // check cache for name and type
  578. //
  579. // DCR: functionalize to take QUERY_BLOB
  580. //
  581. if ( !(Flags & DNS_QUERY_BYPASS_CACHE) )
  582. {
  583. if ( Cache_GetRecordsForRpc(
  584. & prrReturn,
  585. & status,
  586. pwsName,
  587. wType,
  588. Flags ) )
  589. {
  590. goto Done;
  591. }
  592. }
  593. //
  594. // setup query blob
  595. //
  596. RtlZeroMemory(
  597. & blob,
  598. sizeof(blob) );
  599. blob.pNameOrig = pwsName;
  600. blob.wType = wType;
  601. blob.Flags = Flags | DNSQUERY_UNICODE_OUT;
  602. // callbacks
  603. // - address info func for prioritize
  604. // - cache query for intermediate names
  605. blob.pfnGetAddrArray = GetLocalAddrArray;
  606. blob.pfnQueryCache = ResolverCacheQueryCallback;
  607. //
  608. // do query
  609. // - local lookup
  610. // - then wire query
  611. //
  612. status = ResolverQuery( &blob );
  613. if ( status != ERROR_SUCCESS &&
  614. status != DNS_ERROR_RCODE_NAME_ERROR &&
  615. status != DNS_INFO_NO_RECORDS )
  616. {
  617. goto Done;
  618. }
  619. prrReturn = blob.pRecords;
  620. //
  621. // local results
  622. // - not cached
  623. // but note that still going through Cache_QueryResponse()
  624. // to get proper RPC preparation
  625. #if 0
  626. if ( blob.pLocalRecords )
  627. {
  628. }
  629. #endif
  630. //
  631. // cache results
  632. // - don't cache local lookup records
  633. //
  634. // DCR: should have simple "CacheResults" flag
  635. //
  636. // note: even local records are going through here
  637. // now to clean them up for RPC; they are not
  638. // cached
  639. //
  640. status = Cache_QueryResponse( &blob );
  641. prrReturn = blob.pRecords;
  642. Done:
  643. // dump any unused query records
  644. if ( prrReturn && status != ERROR_SUCCESS )
  645. {
  646. Dns_RecordListFree( prrReturn );
  647. prrReturn = NULL;
  648. }
  649. // set out pointer
  650. *ppResultRecords = prrReturn;
  651. DNSLOG_F3(
  652. " R_ResolverQuery - Returning status : 0x%.8X\n\t%s",
  653. status,
  654. Dns_StatusString(status) );
  655. DNSLOG_F1( "" );
  656. IF_DNSDBG( RPC )
  657. {
  658. DnsDbg_RecordSet(
  659. "R_ResolverQuery Result List:",
  660. prrReturn );
  661. }
  662. DNSDBG( RPC, (
  663. "Leave R_ResolverQuery( %S, t=%d, f=%08x )\n\n"
  664. "\tstatus = %d\n\n",
  665. pwsName,
  666. wType,
  667. Flags,
  668. status ));
  669. return status;
  670. }
  671. //
  672. // End ops.c
  673. //