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.

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