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.

1815 lines
50 KiB

  1. /*-----------------------------------------------------------------------------
  2. Copyright (c) 2001 Microsoft Corporation
  3. DNS Server debugger extension
  4. Written by Jeff Westhead Feb 2001
  5. -----------------------------------------------------------------------------*/
  6. #include "dbgexts.h"
  7. //
  8. // DNS Server includes
  9. //
  10. #define LDAP_UNICODE 1
  11. #include <winldap.h> // public LDAP
  12. #include <winber.h> // for ber formatting
  13. #include <ntldap.h> // public server ldap constants
  14. #include <rpc.h> // RPC def needed for ntdsapi.h
  15. #include <ntdsapi.h> // DS access bit definitions
  16. #include <ntdsadef.h> // DS constants
  17. #include <dsrole.h>
  18. #include <time.h>
  19. #define DNSLIB_SECURITY // include security defs
  20. #define SDK_DNS_RECORD // DNS_RECORD in SDK format
  21. #define NO_DNSAPI_DLL // build without requiring dnsapi.dll
  22. #include <dnslib.h> // DNS library routines
  23. #ifndef FASTCALL
  24. #define FASTCALL
  25. #endif
  26. #include "dnsrpc_s.h" // DNS RPC definitions
  27. #include "srvcfg.h"
  28. #include "file.h"
  29. #include "tree.h"
  30. #include "name.h"
  31. #include "record.h"
  32. #include "update.h"
  33. #include "dpart.h"
  34. #include "EventControl.h"
  35. #include "zone.h"
  36. #include "registry.h"
  37. #include "msginfo.h"
  38. #include "socket.h"
  39. #include "packetq.h"
  40. #include "dbase.h"
  41. #include "recurse.h"
  42. #include "nameutil.h"
  43. #include "stats.h"
  44. #include "debug.h"
  45. #include "memory.h"
  46. #include "dfile.h"
  47. #include "wins.h"
  48. #include "rrfunc.h"
  49. #include "dnsprocs.h"
  50. #include "rescodes.h"
  51. #include "sdutl.h"
  52. #include "ds.h"
  53. #include "timeout.h"
  54. //
  55. // Print DNS server statistics
  56. //
  57. LPSTR MemTagStrings[] = // Stolen from dns\server\client\print.c
  58. {
  59. MEMTAG_NAME_NONE ,
  60. MEMTAG_NAME_PACKET_UDP ,
  61. MEMTAG_NAME_PACKET_TCP ,
  62. MEMTAG_NAME_NAME ,
  63. MEMTAG_NAME_ZONE ,
  64. MEMTAG_NAME_UPDATE ,
  65. MEMTAG_NAME_UPDATE_LIST ,
  66. MEMTAG_NAME_TIMEOUT ,
  67. MEMTAG_NAME_NODEHASH ,
  68. MEMTAG_NAME_DS_DN ,
  69. MEMTAG_NAME_DS_MOD , // 10
  70. MEMTAG_NAME_DS_RECORD ,
  71. MEMTAG_NAME_DS_OTHER ,
  72. MEMTAG_NAME_THREAD ,
  73. MEMTAG_NAME_NBSTAT ,
  74. MEMTAG_NAME_DNSLIB ,
  75. MEMTAG_NAME_TABLE ,
  76. MEMTAG_NAME_SOCKET ,
  77. MEMTAG_NAME_CONNECTION ,
  78. MEMTAG_NAME_REGISTRY ,
  79. MEMTAG_NAME_RPC , // 20
  80. MEMTAG_NAME_STUFF ,
  81. MEMTAG_NAME_FILEBUF ,
  82. MEMTAG_NAME_REMOTE ,
  83. MEMTAG_NAME_SAFE ,
  84. MEMTAG_NAME_RECORD ,
  85. MEMTAG_NAME_RECORD_FILE ,
  86. MEMTAG_NAME_RECORD_DS ,
  87. MEMTAG_NAME_RECORD_AXFR ,
  88. MEMTAG_NAME_RECORD_IXFR ,
  89. MEMTAG_NAME_RECORD_DYNUP , // 30
  90. MEMTAG_NAME_RECORD_ADMIN ,
  91. MEMTAG_NAME_RECORD_AUTO ,
  92. MEMTAG_NAME_RECORD_CACHE ,
  93. MEMTAG_NAME_RECORD_NOEXIST ,
  94. MEMTAG_NAME_RECORD_WINS ,
  95. MEMTAG_NAME_RECORD_WINSPTR ,
  96. MEMTAG_NAME_RECORD_COPY ,
  97. MEMTAG_NAME_NODE ,
  98. MEMTAG_NAME_NODE_FILE ,
  99. MEMTAG_NAME_NODE_DS , // 40
  100. MEMTAG_NAME_NODE_AXFR ,
  101. MEMTAG_NAME_NODE_IXFR ,
  102. MEMTAG_NAME_NODE_DYNUP ,
  103. MEMTAG_NAME_NODE_ADMIN ,
  104. MEMTAG_NAME_NODE_AUTO ,
  105. MEMTAG_NAME_NODE_CACHE ,
  106. MEMTAG_NAME_NODE_NOEXIST ,
  107. MEMTAG_NAME_NODE_WINS ,
  108. MEMTAG_NAME_NODE_WINSPTR ,
  109. MEMTAG_NAME_NODE_COPY ,
  110. NULL, // safety
  111. NULL,
  112. NULL,
  113. NULL
  114. };
  115. //
  116. // Functions
  117. //
  118. //
  119. // Iteration control. Be sure to call resetIterationCount at
  120. // the start of any iterating operation that will call checkIterationCount.
  121. // Note: call checkIterationCount aggressively, meaning at the top of
  122. // every single loop that iterates through a server data structure. It
  123. // is important that we be able to preset a limit to ALL iterating
  124. // functions.
  125. //
  126. int g_iIterationCount = 0;
  127. int g_iMaxIterations = 0;
  128. void
  129. resetIterationCount()
  130. {
  131. g_iIterationCount = 0;
  132. } // resetIterationCount
  133. bool
  134. checkIterationCount()
  135. {
  136. if ( g_iMaxIterations != 0 && g_iIterationCount++ > g_iMaxIterations )
  137. {
  138. dprintf(
  139. "Max iteration count (%d) reached - terminating operation\n",
  140. g_iMaxIterations );
  141. return false;
  142. }
  143. return true;
  144. } // checkIterationCount
  145. bool
  146. myReadMemory(
  147. ULONG64 pMemory,
  148. void * ppBuffer,
  149. ULONG lLength,
  150. bool fQuiet )
  151. {
  152. bool okay = true;
  153. DWORD bytes = 0;
  154. if ( !ReadMemory( pMemory, ppBuffer, lLength, &bytes ) ||
  155. bytes != lLength )
  156. {
  157. if ( !fQuiet )
  158. {
  159. dprintf(
  160. "DNSDBG: error reading %lu bytes of process memory at %p\n",
  161. lLength,
  162. pMemory );
  163. }
  164. okay = false;
  165. }
  166. return okay;
  167. } // myReadMemory
  168. bool
  169. myReadString(
  170. ULONG64 pString,
  171. char * pszStringBuffer,
  172. ULONG lLength )
  173. {
  174. bool okay = true;
  175. for ( ULONG i = 0; i < lLength - 1; ++i )
  176. {
  177. CHAR szbuffer[ 2 ];
  178. if ( !myReadMemory( pString + i, &szbuffer , 1, true ) )
  179. {
  180. okay = false;
  181. break;
  182. }
  183. pszStringBuffer[ i ] = szbuffer[ 0 ];
  184. if ( pszStringBuffer[ i ] == '\0' )
  185. {
  186. break;
  187. }
  188. }
  189. pszStringBuffer[ i ] = '\0';
  190. return okay;
  191. } // myReadMemory
  192. HRESULT CALLBACK
  193. Stats(
  194. PDEBUG_CLIENT Client,
  195. PCSTR args )
  196. {
  197. INIT_API();
  198. DWORD bytes;
  199. bool okay = true;
  200. ULONG64 pstatsTable = GetExpression( args );
  201. dprintf( "DNS Server statistics at %p\n", ( ULONG64 ) pstatsTable );
  202. for ( int i = 0; ; ++i )
  203. {
  204. struct StatsTableEntry statsEntry;
  205. if ( !ReadMemory(
  206. pstatsTable + i * sizeof( StatsTableEntry ),
  207. &statsEntry,
  208. sizeof( statsEntry ),
  209. &bytes ) ||
  210. bytes != sizeof( statsEntry ) )
  211. {
  212. dprintf(
  213. "Unable to read stat at %p index %d\n",
  214. ( ULONG64 ) ( ( PBYTE ) pstatsTable + i * sizeof( statsEntry ) ),
  215. i );
  216. okay = false;
  217. break;
  218. }
  219. if ( statsEntry.Id == 0 )
  220. {
  221. break; // Stat array terminator found!
  222. }
  223. #if 0
  224. dprintf(
  225. "Stat entry %d id=%08X length=%d\n",
  226. i,
  227. statsEntry.Id,
  228. statsEntry.wLength );
  229. #endif
  230. switch( statsEntry.Id )
  231. {
  232. #define StatDword( szIndent, statStruct, statMember ) \
  233. dprintf( \
  234. "%s%-25s = %d\n", \
  235. szIndent, \
  236. #statMember, \
  237. statStruct.##statMember )
  238. case DNSSRV_STATID_MEMORY:
  239. {
  240. dprintf( "\n***** Memory Stats id 0x%08X\n\n", statsEntry.Id );
  241. DNSSRV_MEMORY_STATS s;
  242. if ( ( okay = myReadMemory(
  243. ( ULONG64 ) statsEntry.pStats,
  244. &s,
  245. sizeof( s ),
  246. false ) ) == false )
  247. {
  248. break;
  249. }
  250. #define StatIndent " "
  251. StatDword( StatIndent, s, Memory );
  252. StatDword( StatIndent, s, Alloc );
  253. StatDword( StatIndent, s, Free );
  254. dprintf( "\n" );
  255. StatDword( StatIndent, s, StdUsed );
  256. StatDword( StatIndent, s, StdReturn );
  257. StatDword( StatIndent, s, StdInUse );
  258. StatDword( StatIndent, s, StdMemory );
  259. dprintf( "\n" );
  260. StatDword( StatIndent, s, StdToHeapAlloc );
  261. StatDword( StatIndent, s, StdToHeapFree );
  262. StatDword( StatIndent, s, StdToHeapInUse );
  263. StatDword( StatIndent, s, StdToHeapMemory );
  264. dprintf( "\n" );
  265. StatDword( StatIndent, s, StdBlockAlloc );
  266. StatDword( StatIndent, s, StdBlockUsed );
  267. StatDword( StatIndent, s, StdBlockReturn );
  268. StatDword( StatIndent, s, StdBlockInUse );
  269. StatDword( StatIndent, s, StdBlockFreeList );
  270. StatDword( StatIndent, s, StdBlockFreeListMemory );
  271. StatDword( StatIndent, s, StdBlockMemory );
  272. dprintf( "\n" );
  273. dprintf( " Memtag Name Alloc Free InUse Memory\n" );
  274. for ( int m = 0; m < MEMTAG_COUNT; ++m )
  275. {
  276. dprintf(
  277. " %2d %-14s %10d %10d %10d %10d\n",
  278. m,
  279. MemTagStrings[ m ],
  280. s.MemTags[ m ].Alloc,
  281. s.MemTags[ m ].Free,
  282. s.MemTags[ m ].Alloc - s.MemTags[ m ].Free,
  283. s.MemTags[ m ].Memory );
  284. }
  285. #if 0
  286. // THIS WOULD BE COOL BUT IT DOESN'T QUITE WORK!!
  287. ULONG64 module = 0;
  288. ULONG typeId = 0;
  289. CHAR szField[ MAX_PATH ];
  290. ULONG offset = 0;
  291. int iField;
  292. HRESULT hr;
  293. hr = g_ExtSymbols->GetSymbolTypeId(
  294. "DNSSRV_MEMORY_STATS", &typeId, &module );
  295. dprintf( "GetSymbolTypeId returned 0x%lx\n", hr );
  296. for ( iField = 0; ; ++i )
  297. {
  298. *szField = '\0';
  299. hr = g_ExtSymbols2->GetFieldName(
  300. module, typeId, iField,
  301. szField, sizeof( szField ), NULL );
  302. if ( hr == S_OK )
  303. {
  304. hr = g_ExtSymbols->GetFieldOffset(
  305. module, typeId, szField, &offset);
  306. if ( hr == S_OK )
  307. {
  308. dprintf( "Field %s at offset %d\n", szField, offset );
  309. }
  310. else
  311. {
  312. dprintf(
  313. "GetFieldOffset %s iField=%d failed 0x%lx\n",
  314. szField, iField, hr );
  315. break;
  316. }
  317. }
  318. else if ( hr == E_INVALIDARG )
  319. {
  320. // Done enumerating fields
  321. break;
  322. }
  323. else
  324. {
  325. dprintf(
  326. "GetFieldName iField=%d failed 0x%lx \"%s\"\n",
  327. iField, hr, szField );
  328. break;
  329. }
  330. }
  331. #endif
  332. break;
  333. }
  334. default:
  335. dprintf(
  336. "Unknown stat entry %d id=%08X length=%d\n",
  337. i,
  338. statsEntry.Id,
  339. statsEntry.wLength );
  340. break;
  341. }
  342. }
  343. EXIT_API();
  344. return S_OK;
  345. } // TimeoutArrays
  346. bool
  347. printNode(
  348. char * pszIndent,
  349. ULONG64 pNodeFull,
  350. bool fVerbose )
  351. {
  352. bool okay = true;
  353. char szEmptyString[] = "";
  354. if ( !pszIndent )
  355. {
  356. pszIndent = szEmptyString;
  357. }
  358. DB_NODE node;
  359. okay = myReadMemory( pNodeFull, &node, sizeof( node ), false );
  360. if ( !okay )
  361. {
  362. okay = false;
  363. goto Cleanup;
  364. }
  365. //
  366. // Force NULL termination in case this node was allocated
  367. // longer than a standard node.
  368. //
  369. * ( ( PUCHAR ) &node + sizeof( node ) - 1 ) = '\0';
  370. //
  371. // Read the string separately to try and get the whole string.
  372. //
  373. char szNodeName[ 65 ];
  374. if ( !myReadString(
  375. ( ULONG64 ) node.szLabel,
  376. szNodeName,
  377. sizeof( szNodeName ) ) )
  378. {
  379. strcpy( szNodeName, node.szLabel );
  380. }
  381. dprintf(
  382. "%sNODE %p %s%s %-16s abin %03d tbin %03d c%d",
  383. pszIndent,
  384. pNodeFull,
  385. node.pZone ? "Z" : " ", // has zone pointer?
  386. node.pRRList ? "R" : " ", // has RR list pointer?
  387. szNodeName ? szNodeName : "(ROOT)",
  388. node.uchAccessBin,
  389. node.uchTimeoutBin,
  390. node.cReferenceCount );
  391. int flags = node.dwNodeFlags;
  392. dprintf(
  393. " f%04X %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
  394. flags,
  395. flags & NODE_NO_DELETE ? "Nodel" : "",
  396. flags & NODE_SELECT ? "Sel" : "",
  397. flags & NODE_FORCE_ENUM ? "Enum" : "",
  398. flags & NODE_IN_TIMEOUT ? "Tmot" : "",
  399. flags & NODE_AVAIL_TO_AUTHUSER ? "Avauth" : "",
  400. flags & NODE_ZONETREE ? "Ztree" : "",
  401. flags & NODE_AUTH_ZONE_ROOT ? "Authrt" : "",
  402. flags & NODE_WILDCARD_PARENT ? "Wildp" : "",
  403. flags & NODE_CNAME ? "Cname" : "",
  404. flags & NODE_ZONE_ROOT ? "Zroot" : "",
  405. flags & NODE_SECURE_EXPIRED ? "Secexp" : "",
  406. flags & NODE_TOMBSTONE ? "Tomb" : "",
  407. flags & NODE_THIS_HOST ? "This" : "",
  408. flags & NODE_NOEXIST ? "Noex" : "" );
  409. if ( fVerbose )
  410. {
  411. dprintf(
  412. "%s par %p up %p left %p right %p children %p\n",
  413. pszIndent,
  414. ( ULONG64 ) node.pParent,
  415. ( ULONG64 ) node.pSibUp,
  416. ( ULONG64 ) node.pSibLeft,
  417. ( ULONG64 ) node.pSibRight,
  418. ( ULONG64 ) node.pChildren );
  419. }
  420. Cleanup:
  421. return okay;
  422. } // printNode
  423. //
  424. // Print summary of timeout system
  425. //
  426. void
  427. internalTimeoutScanner(
  428. ULONG64 pTimeoutBinArray,
  429. bool fPrintStats,
  430. bool fPrintArrays,
  431. bool fPrintNodes,
  432. bool fPrintNodesHighDetail )
  433. {
  434. DWORD nonEmptyTopLevelBins = 0;
  435. DWORD arraysFound = 0;
  436. DWORD nodesFound = 0;
  437. DWORD maxBinDepth = 0;
  438. DWORD maxNodesInBin = 0;
  439. DWORD bytes;
  440. bool okay = true;
  441. PTIMEOUT_ARRAY timeoutBinArray[ TIMEOUT_BIN_COUNT ];
  442. //
  443. // Read the timeout bin array
  444. //
  445. if ( !ReadMemory(
  446. pTimeoutBinArray,
  447. timeoutBinArray,
  448. sizeof( timeoutBinArray ),
  449. &bytes ) ||
  450. bytes != sizeof( timeoutBinArray ) )
  451. {
  452. dprintf(
  453. "Unable to read timeout bin array (%d bytes) at %p\n",
  454. sizeof( timeoutBinArray ),
  455. ( ULONG64 ) pTimeoutBinArray );
  456. goto Cleanup;
  457. }
  458. //
  459. // For each bin in the array, traverse the bin to count
  460. // nodes.
  461. //
  462. resetIterationCount();
  463. for ( int i = 0; okay && i < TIMEOUT_BIN_COUNT; ++i )
  464. {
  465. if ( !checkIterationCount() )
  466. {
  467. break;
  468. }
  469. if ( !timeoutBinArray[ i ] )
  470. {
  471. continue;
  472. }
  473. //
  474. // Traverse all the arrays in this bin.
  475. //
  476. ++nonEmptyTopLevelBins;
  477. DWORD nodesInThisBin = 0;
  478. DWORD arraysInThisBin = 0;
  479. DWORD depth = 0;
  480. TIMEOUT_ARRAY array;
  481. for ( ULONG64 pArray = ( ULONG64 ) timeoutBinArray[ i ];
  482. okay && pArray != NULL;
  483. pArray = ( ULONG64 ) array.pNext )
  484. {
  485. if ( !checkIterationCount() )
  486. {
  487. break;
  488. }
  489. //
  490. // Read this array.
  491. //
  492. if ( !ReadMemory(
  493. pArray,
  494. &array,
  495. sizeof( array ),
  496. &bytes ) ||
  497. bytes != sizeof( array ) )
  498. {
  499. dprintf(
  500. "Unable to read timeout array for bin %d (%d bytes) at %p\n",
  501. i,
  502. sizeof( array ),
  503. ( ULONG64 ) pArray );
  504. okay = false;
  505. break;
  506. }
  507. ++arraysInThisBin;
  508. ++arraysFound;
  509. ++depth;
  510. nodesInThisBin += array.Count;
  511. nodesFound += array.Count;
  512. if ( fPrintArrays )
  513. {
  514. dprintf(
  515. " ARRAY %3d in bin %3d has %2d elements %p\n",
  516. arraysInThisBin,
  517. i,
  518. array.Count,
  519. ( ULONG64 ) pArray );
  520. }
  521. if ( !fPrintNodes && !fPrintNodesHighDetail )
  522. {
  523. continue;
  524. }
  525. //
  526. // Traverse all the nodes in this array.
  527. //
  528. for ( DWORD j = 0; okay && j < array.Count; ++j )
  529. {
  530. if ( !checkIterationCount() )
  531. {
  532. break;
  533. }
  534. char sz[ 20 ];
  535. sprintf( sz, " %2d ", j + 1 );
  536. okay = printNode(
  537. sz,
  538. ( ULONG64 ) array.pNode[ j ],
  539. false );
  540. }
  541. }
  542. if ( !okay )
  543. {
  544. break;
  545. }
  546. if ( fPrintArrays && arraysInThisBin )
  547. {
  548. dprintf(
  549. "BIN %3d has %3d arrays %5d nodes\n",
  550. i,
  551. arraysInThisBin,
  552. nodesInThisBin );
  553. }
  554. //
  555. // Record high water marks.
  556. //
  557. if ( nodesInThisBin > maxNodesInBin )
  558. {
  559. maxNodesInBin = nodesInThisBin;
  560. }
  561. if ( depth > maxBinDepth )
  562. {
  563. maxBinDepth = depth;
  564. }
  565. }
  566. if ( okay && fPrintStats )
  567. {
  568. dprintf(
  569. "Timeout summary for TimeoutBinArray at %p\n",
  570. pTimeoutBinArray );
  571. dprintf(
  572. " nodes found in timeout system %d\n"
  573. " arrays found in timeout system %d\n"
  574. " non-empty top level bins %d out of %d\n"
  575. " maximum bin depth %d\n"
  576. " maximum nodes in single bin %d\n"
  577. " average arrays per non-empty bin %.2f\n",
  578. nodesFound,
  579. arraysFound,
  580. nonEmptyTopLevelBins,
  581. TIMEOUT_BIN_COUNT,
  582. maxBinDepth,
  583. maxNodesInBin,
  584. nonEmptyTopLevelBins ?
  585. ( ( double ) arraysFound /
  586. ( double ) nonEmptyTopLevelBins + 0.5 ) : 0 );
  587. }
  588. Cleanup:
  589. return;
  590. } // internalTimeoutScanner
  591. HRESULT CALLBACK
  592. TimeoutSummary(
  593. PDEBUG_CLIENT Client,
  594. PCSTR args )
  595. {
  596. INIT_API();
  597. ULONG64 ptimeoutBinArray = GetExpression( args );
  598. internalTimeoutScanner(
  599. ptimeoutBinArray,
  600. true, // print stats
  601. false, // print arrays
  602. false, // print nodes
  603. false ); // print nodes - high detail
  604. EXIT_API();
  605. return S_OK;
  606. } // TimeoutSummary
  607. HRESULT CALLBACK
  608. TimeoutArrays(
  609. PDEBUG_CLIENT Client,
  610. PCSTR args )
  611. {
  612. INIT_API();
  613. ULONG64 ptimeoutBinArray = GetExpression( args );
  614. internalTimeoutScanner(
  615. ptimeoutBinArray,
  616. true, // print stats
  617. true, // print arrays
  618. false, // print nodes
  619. false ); // print nodes - high detail
  620. EXIT_API();
  621. return S_OK;
  622. } // TimeoutArrays
  623. HRESULT CALLBACK
  624. TimeoutNodes(
  625. PDEBUG_CLIENT Client,
  626. PCSTR args )
  627. {
  628. INIT_API();
  629. ULONG64 ptimeoutBinArray = GetExpression( args );
  630. internalTimeoutScanner(
  631. ptimeoutBinArray,
  632. true, // print stats
  633. true, // print arrays
  634. true, // print nodes
  635. false ); // print nodes - high detail
  636. EXIT_API();
  637. return S_OK;
  638. } // TimeoutNodes
  639. /*
  640. This gets called (by DebugExtensionNotify when target is halted and is accessible
  641. */
  642. HRESULT
  643. NotifyOnTargetAccessible(PDEBUG_CONTROL Control)
  644. {
  645. dprintf( "DNS Server debugger extension dll detected a break" );
  646. if ( Connected )
  647. {
  648. dprintf( " (" );
  649. switch (TargetMachine) {
  650. case IMAGE_FILE_MACHINE_I386:
  651. dprintf( "x86" );
  652. break;
  653. case IMAGE_FILE_MACHINE_IA64:
  654. dprintf( "ia64" );
  655. break;
  656. default:
  657. dprintf( "Unknown Architecture" );
  658. break;
  659. }
  660. }
  661. dprintf( ")\n" );
  662. dprintf( "\nDebugger extension build at " __DATE__ " " __TIME__ "\n\n" );
  663. //
  664. // show the top frame and execute dv to dump the locals here and return
  665. //
  666. Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  667. DEBUG_OUTCTL_OVERRIDE_MASK |
  668. DEBUG_OUTCTL_NOT_LOGGED,
  669. ".frame", // Command to be executed
  670. DEBUG_EXECUTE_DEFAULT );
  671. Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS |
  672. DEBUG_OUTCTL_OVERRIDE_MASK |
  673. DEBUG_OUTCTL_NOT_LOGGED,
  674. "dv", // Command to be executed
  675. DEBUG_EXECUTE_DEFAULT );
  676. return S_OK;
  677. }
  678. char * g_ZoneTypeNames[] =
  679. {
  680. "Cache",
  681. "Primary",
  682. "Secondary",
  683. "Stub",
  684. "Forwarder"
  685. };
  686. bool
  687. printZoneProperties(
  688. ULONG64 pZoneFull,
  689. bool fVerbose )
  690. {
  691. bool okay = true;
  692. ZONE_INFO zone;
  693. if ( !myReadMemory( pZoneFull, &zone, sizeof( zone ), false ) )
  694. {
  695. okay = false;
  696. goto Cleanup;
  697. }
  698. char sz[ 256 ];
  699. if ( !myReadString(
  700. ( ULONG64 ) zone.pszZoneName,
  701. sz,
  702. sizeof( sz ) ) )
  703. {
  704. okay = false;
  705. goto Cleanup;
  706. }
  707. if ( fVerbose )
  708. {
  709. dprintf( "\n" );
  710. }
  711. dprintf(
  712. "ZONE %p %s (%d)%-9s %s\n",
  713. pZoneFull,
  714. zone.fDsIntegrated ? "DS " : "File",
  715. zone.fZoneType,
  716. zone.fZoneType <= DNS_ZONE_TYPE_FORWARDER ?
  717. g_ZoneTypeNames[ zone.fZoneType ] : "UNKNOWN-TYPE",
  718. sz );
  719. if ( fVerbose )
  720. {
  721. #define ZonePtr( szIndent, zoneMember ) \
  722. dprintf( \
  723. "%s%-25s = %p\n", \
  724. szIndent, \
  725. #zoneMember, \
  726. ( ULONG64 ) zone.##zoneMember )
  727. #define ZoneStr( szIndent, zoneMember, stringValue ) \
  728. dprintf( \
  729. "%s%-25s = %s\n", \
  730. szIndent, \
  731. #zoneMember, \
  732. stringValue )
  733. #define ZoneDword( szIndent, zoneMember ) \
  734. dprintf( \
  735. "%s%-25s = %8d = 0x%08X\n", \
  736. szIndent, \
  737. #zoneMember, \
  738. zone.##zoneMember, \
  739. zone.##zoneMember )
  740. #define ZoneIndent " "
  741. *sz = '\0';
  742. if ( zone.pszDataFile )
  743. {
  744. if ( !myReadString(
  745. ( ULONG64 ) zone.pszDataFile,
  746. sz,
  747. sizeof( sz ) ) )
  748. {
  749. okay = false;
  750. goto Cleanup;
  751. }
  752. }
  753. ZoneStr( ZoneIndent, pszDataFile, sz );
  754. if ( zone.fDsIntegrated )
  755. {
  756. *sz = '\0';
  757. if ( zone.pwszZoneDN )
  758. {
  759. if ( !myReadString(
  760. ( ULONG64 ) zone.pwszZoneDN,
  761. sz,
  762. sizeof( sz ) ) )
  763. {
  764. okay = false;
  765. goto Cleanup;
  766. }
  767. }
  768. ZoneStr( ZoneIndent, pwszZoneDN, sz );
  769. ZonePtr( ZoneIndent, pDpInfo );
  770. }
  771. ZonePtr( ZoneIndent, pSoaRR );
  772. ZonePtr( ZoneIndent, pZoneRoot );
  773. ZonePtr( ZoneIndent, pTreeRoot );
  774. ZonePtr( ZoneIndent, pZoneTreeLink );
  775. dprintf( "\n" );
  776. ZonePtr( ZoneIndent, pLoadZoneRoot );
  777. ZonePtr( ZoneIndent, pLoadTreeRoot );
  778. ZonePtr( ZoneIndent, pLoadOrigin );
  779. ZonePtr( ZoneIndent, pOldTree );
  780. dprintf( "\n" );
  781. ZoneDword( ZoneIndent, iRRCount );
  782. ZoneDword( ZoneIndent, dwSerialNo );
  783. ZoneDword( ZoneIndent, dwLoadSerialNo );
  784. ZoneDword( ZoneIndent, dwLastXfrSerialNo );
  785. ZoneDword( ZoneIndent, dwNewSerialNo );
  786. ZoneDword( ZoneIndent, dwDefaultTtl );
  787. dprintf( "\n" );
  788. ZoneDword( ZoneIndent, dwNextTransferTime );
  789. dprintf( "\n" );
  790. ZoneDword( ZoneIndent, dwDcPromoConvert );
  791. dprintf( "\n" );
  792. }
  793. Cleanup:
  794. return okay;
  795. } // printZoneProperties
  796. //
  797. // Dump zone list with basic info on each zone.
  798. //
  799. HRESULT CALLBACK
  800. ZoneList(
  801. PDEBUG_CLIENT Client,
  802. PCSTR args )
  803. {
  804. INIT_API();
  805. bool okay = true;
  806. int zoneIdx = 0;
  807. ULONG64 plistheadZone = GetExpression( args );
  808. LIST_ENTRY listEntry;
  809. if ( !myReadMemory( plistheadZone, &listEntry, sizeof( listEntry ), false ) )
  810. {
  811. goto Cleanup;
  812. }
  813. resetIterationCount();
  814. ZONE_INFO zone;
  815. for ( ULONG64 pzone = ( ULONG64 ) listEntry.Flink;
  816. pzone;
  817. pzone = ( ULONG64 ) zone.ListEntry.Flink )
  818. {
  819. if ( !checkIterationCount() )
  820. {
  821. break;
  822. }
  823. if ( zoneIdx != 0 && pzone == plistheadZone )
  824. {
  825. break; // Looped back to list head, so we're done.
  826. }
  827. if ( ++zoneIdx > 1000 )
  828. {
  829. dprintf( "Runaway zone list? Aborting enumeration...\n" );
  830. break;
  831. }
  832. if ( !myReadMemory( pzone, &zone, sizeof( zone ), false ) )
  833. {
  834. break;
  835. }
  836. printZoneProperties( pzone, false );
  837. }
  838. Cleanup:
  839. EXIT_API();
  840. return S_OK;
  841. } // ZoneList
  842. //
  843. // Dump zone info.
  844. //
  845. HRESULT CALLBACK
  846. Zone(
  847. PDEBUG_CLIENT Client,
  848. PCSTR args )
  849. {
  850. INIT_API();
  851. ULONG64 p = GetExpression( args );
  852. printZoneProperties( p, true );
  853. EXIT_API();
  854. return S_OK;
  855. } // Zone
  856. //
  857. // Dump node info.
  858. //
  859. HRESULT CALLBACK
  860. Node(
  861. PDEBUG_CLIENT Client,
  862. PCSTR args )
  863. {
  864. INIT_API();
  865. ULONG64 p = GetExpression( args );
  866. printNode( NULL, p, true );
  867. EXIT_API();
  868. return S_OK;
  869. } // Node
  870. bool
  871. printHash(
  872. char * pszIndent,
  873. ULONG64 pHashFull,
  874. bool fVerbose )
  875. {
  876. bool okay = true;
  877. char szEmptyString[] = "";
  878. if ( !pszIndent )
  879. {
  880. pszIndent = szEmptyString;
  881. }
  882. SIB_HASH_TABLE hash;
  883. okay = myReadMemory( pHashFull, &hash, sizeof( hash ), false );
  884. if ( !okay )
  885. {
  886. okay = false;
  887. goto Cleanup;
  888. }
  889. dprintf(
  890. "%sHASH %p lvl%02d\n",
  891. pszIndent,
  892. pHashFull,
  893. hash.cLevel );
  894. Cleanup:
  895. return okay;
  896. } // printHash
  897. //
  898. // Traverse a database tree of hashes and nodes. This function
  899. // is called recursively.
  900. //
  901. struct
  902. {
  903. int iRecurseCalls;
  904. int iHashTables;
  905. int iEmptyHashBuckets;
  906. int iNonEmptyHashBuckets;
  907. int iNodes;
  908. int iNoExistNodes;
  909. int iTimeoutNodes;
  910. int iNodesWithNoRRs;
  911. int iNodesWithNoChildren;
  912. } g_TreeScannerStats;
  913. //
  914. // iRecurseLevel: true level of function recursion
  915. // iChildLevel: level of node depth
  916. //
  917. bool
  918. internalTreeScanner(
  919. ULONG64 pTreeRoot,
  920. bool fPrintSummary,
  921. bool fPrintHashNodes,
  922. bool fPrintHashBuckets,
  923. bool fPrintNodes,
  924. bool fPrintNodesHighDetail,
  925. int iRecurseLevel, // pass 0 on initial call
  926. int iChildLevel ) // pass 0 on initial call
  927. {
  928. bool okay = true;
  929. // dprintf( "internalTreeScanner p=%p level=%d\n", pTreeRoot, iRecurseLevel );
  930. if ( !checkIterationCount() )
  931. {
  932. return false;
  933. }
  934. if ( iRecurseLevel == 0 )
  935. {
  936. RtlZeroMemory( &g_TreeScannerStats, sizeof( g_TreeScannerStats ) );
  937. }
  938. if ( ++g_TreeScannerStats.iRecurseCalls > 10000000 )
  939. {
  940. dprintf( "Aborting: hit limit of 10000000 recurse calls\n" );
  941. return true;
  942. }
  943. char szIndent[] =
  944. " "
  945. " ";
  946. szIndent[ min( ( int ) strlen( szIndent ), iChildLevel * 2 ) ] = '\0';
  947. //
  948. // Grab the first DWORD so we can determine if this is
  949. // a hash or a node.
  950. //
  951. DWORD dw;
  952. if ( !myReadMemory( pTreeRoot, &dw, sizeof( dw ), false ) )
  953. {
  954. okay = false;
  955. goto Cleanup;
  956. }
  957. if ( IS_HASH_TABLE( &dw ) )
  958. {
  959. ++g_TreeScannerStats.iHashTables;
  960. if ( fPrintHashNodes )
  961. {
  962. okay = printHash( szIndent, pTreeRoot, false );
  963. }
  964. SIB_HASH_TABLE hash;
  965. okay = myReadMemory( pTreeRoot, &hash, sizeof( hash ), false );
  966. if ( !okay )
  967. {
  968. okay = false;
  969. goto Cleanup;
  970. }
  971. //
  972. // Iterate through all the buckets in this hash node.
  973. //
  974. for ( int i = 0; i <= LAST_HASH_INDEX; ++i )
  975. {
  976. PDB_NODE pnode = hash.aBuckets[ i ];
  977. DWORD count = hash.aBucketCount[ i ];
  978. if ( pnode )
  979. {
  980. ++g_TreeScannerStats.iNonEmptyHashBuckets;
  981. if ( fPrintHashBuckets )
  982. {
  983. dprintf(
  984. "%sBUCKET %p index %3d count %3d\n",
  985. szIndent,
  986. ( ULONG64 ) pnode,
  987. i,
  988. count );
  989. }
  990. okay = internalTreeScanner(
  991. ( ULONG64 ) pnode,
  992. fPrintSummary,
  993. fPrintHashNodes,
  994. fPrintHashBuckets,
  995. fPrintNodes,
  996. fPrintNodesHighDetail,
  997. iRecurseLevel + 1,
  998. iChildLevel );
  999. if ( !okay )
  1000. {
  1001. break;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. ++g_TreeScannerStats.iEmptyHashBuckets;
  1007. }
  1008. }
  1009. }
  1010. else
  1011. {
  1012. //
  1013. // This is a node.
  1014. //
  1015. ++g_TreeScannerStats.iNodes;
  1016. DB_NODE node;
  1017. okay = myReadMemory( pTreeRoot, &node, sizeof( node ), false );
  1018. if ( !okay )
  1019. {
  1020. okay = false;
  1021. goto Cleanup;
  1022. }
  1023. //
  1024. // Force NULL termination in case this node was allocated
  1025. // longer than a standard node.
  1026. //
  1027. * ( ( PUCHAR ) &node + sizeof( node ) - 1 ) = '\0';
  1028. //
  1029. // Scan the left child tree then this node then the right child tree.
  1030. //
  1031. if ( node.pSibLeft )
  1032. {
  1033. okay = internalTreeScanner(
  1034. ( ULONG64 ) node.pSibLeft,
  1035. fPrintSummary,
  1036. fPrintHashNodes,
  1037. fPrintHashBuckets,
  1038. fPrintNodes,
  1039. fPrintNodesHighDetail,
  1040. iRecurseLevel + 1,
  1041. iChildLevel );
  1042. if ( !okay )
  1043. {
  1044. goto Cleanup;
  1045. }
  1046. }
  1047. if ( node.dwNodeFlags & NODE_NOEXIST )
  1048. {
  1049. ++g_TreeScannerStats.iNoExistNodes;
  1050. }
  1051. if ( node.dwNodeFlags & NODE_IN_TIMEOUT )
  1052. {
  1053. ++g_TreeScannerStats.iTimeoutNodes;
  1054. }
  1055. if ( !node.pRRList )
  1056. {
  1057. ++g_TreeScannerStats.iNodesWithNoRRs;
  1058. }
  1059. if ( !node.pChildren )
  1060. {
  1061. ++g_TreeScannerStats.iNodesWithNoChildren;
  1062. }
  1063. if ( fPrintNodes )
  1064. {
  1065. okay = printNode( szIndent, pTreeRoot, fPrintNodesHighDetail );
  1066. if ( !okay )
  1067. {
  1068. goto Cleanup;
  1069. }
  1070. }
  1071. if ( node.pChildren )
  1072. {
  1073. okay = internalTreeScanner(
  1074. ( ULONG64 ) node.pChildren,
  1075. fPrintSummary,
  1076. fPrintHashNodes,
  1077. fPrintHashBuckets,
  1078. fPrintNodes,
  1079. fPrintNodesHighDetail,
  1080. iRecurseLevel + 1,
  1081. iChildLevel + 1 );
  1082. if ( !okay )
  1083. {
  1084. goto Cleanup;
  1085. }
  1086. }
  1087. if ( node.pSibRight )
  1088. {
  1089. okay = internalTreeScanner(
  1090. ( ULONG64 ) node.pSibRight,
  1091. fPrintSummary,
  1092. fPrintHashNodes,
  1093. fPrintHashBuckets,
  1094. fPrintNodes,
  1095. fPrintNodesHighDetail,
  1096. iRecurseLevel + 1,
  1097. iChildLevel );
  1098. if ( !okay )
  1099. {
  1100. goto Cleanup;
  1101. }
  1102. }
  1103. }
  1104. Cleanup:
  1105. if ( iRecurseLevel == 0 )
  1106. {
  1107. if ( !okay )
  1108. {
  1109. dprintf( "\nERROR ITERATING TREE - STATS INCOMPLETE!\n\n" );
  1110. }
  1111. if ( fPrintSummary )
  1112. {
  1113. dprintf(
  1114. "Tree summary for tree rooted at %p\n",
  1115. pTreeRoot );
  1116. dprintf(
  1117. " hash tables %d\n"
  1118. " empty hash buckets %d\n"
  1119. " non-empty hash buckets %d\n"
  1120. "\n"
  1121. " nodes %d\n"
  1122. " no-exist nodes %d\n"
  1123. " timeout nodes %d\n"
  1124. " nodes with no RRs %d\n"
  1125. " nodes with no children %d\n",
  1126. g_TreeScannerStats.iHashTables,
  1127. g_TreeScannerStats.iEmptyHashBuckets,
  1128. g_TreeScannerStats.iNonEmptyHashBuckets,
  1129. g_TreeScannerStats.iNodes,
  1130. g_TreeScannerStats.iNoExistNodes,
  1131. g_TreeScannerStats.iTimeoutNodes,
  1132. g_TreeScannerStats.iNodesWithNoRRs,
  1133. g_TreeScannerStats.iNodesWithNoChildren );
  1134. }
  1135. }
  1136. return okay;
  1137. }
  1138. //
  1139. // Dump node tree.
  1140. //
  1141. HRESULT CALLBACK
  1142. Tree(
  1143. PDEBUG_CLIENT Client,
  1144. PCSTR args )
  1145. {
  1146. INIT_API();
  1147. ULONG64 p = GetExpression( args );
  1148. resetIterationCount();
  1149. internalTreeScanner(
  1150. p,
  1151. true,
  1152. true,
  1153. true,
  1154. true,
  1155. false,
  1156. 0, 0 );
  1157. EXIT_API();
  1158. return S_OK;
  1159. } // Node
  1160. //
  1161. // Print summary of a node tree.
  1162. //
  1163. HRESULT CALLBACK
  1164. TreeSummary(
  1165. PDEBUG_CLIENT Client,
  1166. PCSTR args )
  1167. {
  1168. INIT_API();
  1169. ULONG64 p = GetExpression( args );
  1170. resetIterationCount();
  1171. internalTreeScanner(
  1172. p,
  1173. true,
  1174. false,
  1175. false,
  1176. false,
  1177. false,
  1178. 0, 0 );
  1179. EXIT_API();
  1180. return S_OK;
  1181. } // Node
  1182. //
  1183. // Print info about a packet queue.
  1184. //
  1185. HRESULT CALLBACK
  1186. PacketQ(
  1187. PDEBUG_CLIENT Client,
  1188. PCSTR args )
  1189. {
  1190. INIT_API();
  1191. ULONG64 p = GetExpression( args );
  1192. PACKET_QUEUE q;
  1193. CHAR szQueueName[ 80 ];
  1194. if ( !myReadMemory(
  1195. ( ULONG64 ) p,
  1196. &q,
  1197. sizeof( q ),
  1198. false ) )
  1199. {
  1200. goto Cleanup;
  1201. }
  1202. if ( !myReadMemory(
  1203. ( ULONG64 ) q.pszName,
  1204. szQueueName,
  1205. sizeof( szQueueName ),
  1206. false ) )
  1207. {
  1208. goto Cleanup;
  1209. }
  1210. #define BoolFlagStr( f ) ( ( f ) ? "true" : "false" )
  1211. dprintf(
  1212. "Packet queue %p\n"
  1213. " queue name %s\n"
  1214. " first message %p\n"
  1215. " event %p\n"
  1216. " default timeout %d\n"
  1217. " minimum timeout %d\n",
  1218. p,
  1219. szQueueName,
  1220. ( ULONG64 ) q.listHead.Flink,
  1221. ( ULONG64 ) q.hEvent,
  1222. q.dwDefaultTimeout,
  1223. q.dwMinimumTimeout );
  1224. dprintf(
  1225. " counters:\n"
  1226. " length %d\n"
  1227. " queued %d\n"
  1228. " dequeued %d\n"
  1229. " timed out %d\n",
  1230. q.cLength,
  1231. q.cQueued,
  1232. q.cDequeued,
  1233. q.cTimedOut );
  1234. dprintf(
  1235. " flags:\n"
  1236. " query time order %s\n"
  1237. " discard expired on queuing %s\n"
  1238. " discard dups on queuing %s\n"
  1239. " XID for referrals %d\n",
  1240. BoolFlagStr( q.fQueryTimeOrder ),
  1241. BoolFlagStr( q.fDiscardExpiredOnQueuing ),
  1242. BoolFlagStr( q.fDiscardDuplicatesOnQueuing ),
  1243. ( int ) q.wXid );
  1244. #undef BoolFlagStr
  1245. Cleanup:
  1246. EXIT_API();
  1247. return S_OK;
  1248. } // PacketQ
  1249. //
  1250. // Print info about a packet queue.
  1251. //
  1252. void
  1253. execDebugCmd(
  1254. char * pszDebuggerCommand )
  1255. {
  1256. g_ExtControl->Execute(
  1257. DEBUG_OUTCTL_ALL_CLIENTS |
  1258. DEBUG_OUTCTL_OVERRIDE_MASK |
  1259. DEBUG_OUTCTL_NOT_LOGGED,
  1260. pszDebuggerCommand,
  1261. DEBUG_EXECUTE_DEFAULT );
  1262. } // execDebugCmd
  1263. HRESULT CALLBACK
  1264. Globals(
  1265. PDEBUG_CLIENT Client,
  1266. PCSTR args )
  1267. {
  1268. INIT_API();
  1269. char szIndent1[] = " ";
  1270. char szIndent2[] = " ";
  1271. dprintf( "Zone list\n%s", szIndent1 );
  1272. execDebugCmd( "dd dns!listheadZone l 2" );
  1273. dprintf( "\nStatistics table\n%s", szIndent1 );
  1274. execDebugCmd( "dd dns!StatsTable l 1" );
  1275. dprintf( "\nPacket queues\n" );
  1276. dprintf( "%sRecursion packet queue\n%s", szIndent1, szIndent2 );
  1277. execDebugCmd( "dd dns!g_pRecursionQueue l 1" );
  1278. dprintf( "%sSecondary packet queue\n%s", szIndent1, szIndent2 );
  1279. execDebugCmd( "dd dns!g_SecondaryQueue l 1" );
  1280. dprintf( "%sUpdate packet queue\n%s", szIndent1, szIndent2 );
  1281. execDebugCmd( "dd dns!g_UpdateQueue l 1" );
  1282. dprintf( "%sUpdate forwarding packet queue\n%s", szIndent1, szIndent2 );
  1283. execDebugCmd( "dd dns!g_UpdateForwardingQueue l 1" );
  1284. dprintf( "%sSecure negotiation packet queue\n%s", szIndent1, szIndent2 );
  1285. execDebugCmd( "dd dns!g_SecureNegoQueue l 1" );
  1286. dprintf( "%sWINS packet queue\n%s", szIndent1, szIndent2 );
  1287. execDebugCmd( "dd dns!g_pWinsQueue l 1" );
  1288. EXIT_API();
  1289. return S_OK;
  1290. } // Globals
  1291. //
  1292. // Dump a message.
  1293. //
  1294. HRESULT CALLBACK
  1295. Msg(
  1296. PDEBUG_CLIENT Client,
  1297. PCSTR args )
  1298. {
  1299. INIT_API();
  1300. ULONG64 p = GetExpression( args );
  1301. BYTE msg[ sizeof( DNS_MSGINFO ) + 512 ];
  1302. PDNS_MSGINFO pmsg = ( PDNS_MSGINFO ) msg;
  1303. if ( !myReadMemory( p, msg, sizeof( msg ), false ) )
  1304. {
  1305. goto Cleanup;
  1306. }
  1307. #define BoolFlagStr( f ) ( ( f ) ? "true" : "false" )
  1308. dprintf(
  1309. "DNS message %p\n"
  1310. "Buffer info:\n"
  1311. " Tag %08X\n"
  1312. " BufferLength %d\n"
  1313. " MaxBufferLength %d\n"
  1314. " MessageLength %d\n"
  1315. " BytesToReceive %d\n"
  1316. " pBufferEnd %p\n"
  1317. " pCurrent %p\n",
  1318. ( ULONG64 ) p,
  1319. pmsg->Tag,
  1320. pmsg->BufferLength,
  1321. pmsg->MaxBufferLength,
  1322. ( int ) pmsg->MessageLength,
  1323. ( int ) pmsg->BytesToReceive,
  1324. ( ULONG64 ) pmsg->pBufferEnd,
  1325. ( ULONG64 ) pmsg->pCurrent );
  1326. dprintf(
  1327. "Remote info:\n"
  1328. " Socket %d\n"
  1329. " RemoteAddr Family %d\n"
  1330. " RemoteAddr Length %d\n"
  1331. " RemoteAddr %08X = %d.%d.%d.%d\n",
  1332. ( int ) pmsg->Socket,
  1333. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_family,
  1334. ( int ) pmsg->RemoteAddr.SockaddrLength,
  1335. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_addr.s_addr,
  1336. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_addr.S_un.S_un_b.s_b1,
  1337. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_addr.S_un.S_un_b.s_b2,
  1338. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_addr.S_un.S_un_b.s_b3,
  1339. ( int ) pmsg->RemoteAddr.SockaddrIn.sin_addr.S_un.S_un_b.s_b4 );
  1340. dprintf(
  1341. "Lookup info:\n"
  1342. " pnodeCurrent %p\n"
  1343. " pnodeClosest %p\n"
  1344. " pzoneCurrent %p\n"
  1345. " pnodeGlue %p\n"
  1346. " pnodeDelegation %p\n"
  1347. " pnodeCache %p\n"
  1348. " pnodeCacheClosest %p\n",
  1349. ( ULONG64 ) pmsg->pnodeCurrent,
  1350. ( ULONG64 ) pmsg->pnodeClosest,
  1351. ( ULONG64 ) pmsg->pzoneCurrent,
  1352. ( ULONG64 ) pmsg->pnodeGlue,
  1353. ( ULONG64 ) pmsg->pnodeDelegation,
  1354. ( ULONG64 ) pmsg->pnodeCache,
  1355. ( ULONG64 ) pmsg->pnodeCacheClosest );
  1356. dprintf(
  1357. " pnodeNxt %p\n"
  1358. " wTypeCurrent %d\n"
  1359. " wOffsetCurrent %d\n"
  1360. " pNodeQuestion %p\n"
  1361. " pNodeQuestionClosest %p\n"
  1362. " pQuestion %p\n"
  1363. " wQuestionType %d\n",
  1364. ( ULONG64 ) pmsg->pnodeNxt,
  1365. ( int ) pmsg->wTypeCurrent,
  1366. ( int ) pmsg->wOffsetCurrent,
  1367. ( ULONG64 ) pmsg->pNodeQuestion,
  1368. ( ULONG64 ) pmsg->pNodeQuestionClosest,
  1369. ( ULONG64 ) pmsg->pQuestion,
  1370. ( int ) pmsg->wQuestionType );
  1371. dprintf(
  1372. "Queuing info:\n"
  1373. " wQueuingXid %d\n"
  1374. " dwQueryTime %d\n"
  1375. " dwMsQueryTime %d\n"
  1376. " dwQueuingTime %d\n"
  1377. " dwExpireTime %d\n",
  1378. ( int ) pmsg->wQueuingXid,
  1379. pmsg->dwQueryTime,
  1380. pmsg->dwMsQueryTime,
  1381. pmsg->dwQueuingTime,
  1382. pmsg->dwExpireTime );
  1383. dprintf(
  1384. "EDNS info\n"
  1385. " fFoundOptInIncomingMsg %s\n"
  1386. " fInsertOptInOutgoingMsg %s\n"
  1387. " cExtendedRCodeBits %d\n"
  1388. " cVersion %d\n"
  1389. " wUdpPayloadSize %d\n"
  1390. " wOptOffset %d\n"
  1391. " wOriginalQueryPayloadSize %d\n",
  1392. BoolFlagStr( pmsg->Opt.fFoundOptInIncomingMsg ),
  1393. BoolFlagStr( pmsg->Opt.fInsertOptInOutgoingMsg ),
  1394. ( int ) pmsg->Opt.cExtendedRCodeBits,
  1395. ( int ) pmsg->Opt.cVersion,
  1396. ( int ) pmsg->Opt.wUdpPayloadSize,
  1397. ( int ) pmsg->Opt.wOptOffset,
  1398. ( int ) pmsg->Opt.wOriginalQueryPayloadSize );
  1399. dprintf(
  1400. "Recursion info:\n"
  1401. " pRecurseMsg %p\n"
  1402. " pnodeRecurseRetry %p\n"
  1403. " pNsList %p\n",
  1404. ( ULONG64 ) pmsg->pRecurseMsg,
  1405. ( ULONG64 ) pmsg->pnodeRecurseRetry,
  1406. ( ULONG64 ) pmsg->pNsList );
  1407. dprintf(
  1408. "Flags:\n"
  1409. " fDelete %s\n"
  1410. " fTcp %s\n"
  1411. " fMessageComplete %s\n"
  1412. " Section %d\n"
  1413. " fDoAdditional %s\n"
  1414. " fRecurseIfNecessary %s\n"
  1415. " fRecursePacket %s\n"
  1416. " fQuestionRecursed %s\n"
  1417. " fQuestionCompleted %s\n",
  1418. BoolFlagStr( pmsg->fDelete ),
  1419. BoolFlagStr( pmsg->fTcp ),
  1420. BoolFlagStr( pmsg->fMessageComplete ),
  1421. ( int ) pmsg->Section,
  1422. BoolFlagStr( pmsg->fDoAdditional ),
  1423. BoolFlagStr( pmsg->fRecurseIfNecessary ),
  1424. BoolFlagStr( pmsg->fRecursePacket ),
  1425. BoolFlagStr( pmsg->fQuestionRecursed ),
  1426. BoolFlagStr( pmsg->fQuestionCompleted ) );
  1427. dprintf(
  1428. " fRecurseQuestionSent %s\n"
  1429. " fRecurseTimeoutWait %s\n"
  1430. " nTimeoutCount %d\n"
  1431. " nForwarder %d\n"
  1432. " fReplaceCname %s\n"
  1433. " cCnameAnswerCount %d\n"
  1434. " fNoCompressionWrite %s\n"
  1435. " fWins %s\n"
  1436. " fQuestionWildcard %s\n"
  1437. " fNsList %s\n",
  1438. BoolFlagStr( pmsg->fRecurseQuestionSent ),
  1439. BoolFlagStr( pmsg->fRecurseTimeoutWait ),
  1440. ( int ) pmsg->nTimeoutCount,
  1441. ( int ) pmsg->nForwarder,
  1442. BoolFlagStr( pmsg->fReplaceCname ),
  1443. ( int ) pmsg->cCnameAnswerCount,
  1444. BoolFlagStr( pmsg->fNoCompressionWrite ),
  1445. BoolFlagStr( pmsg->fWins ),
  1446. BoolFlagStr( pmsg->fQuestionWildcard ),
  1447. BoolFlagStr( pmsg->fNsList ) );
  1448. dprintf(
  1449. "DNS header:\n"
  1450. " Xid %04X\n"
  1451. " RecursionDesired %d\n"
  1452. " Truncation %d\n"
  1453. " Authoritative %d\n"
  1454. " Opcode %d\n"
  1455. " IsResponse %d\n",
  1456. ( int ) pmsg->Head.Xid,
  1457. ( int ) pmsg->Head.RecursionDesired,
  1458. ( int ) pmsg->Head.Truncation,
  1459. ( int ) pmsg->Head.Authoritative,
  1460. ( int ) pmsg->Head.Opcode,
  1461. ( int ) pmsg->Head.IsResponse );
  1462. dprintf(
  1463. " ResponseCode %d\n"
  1464. " RecursionAvailable %d\n"
  1465. " QuestionCount %d\n"
  1466. " AnswerCount %d\n"
  1467. " NameServerCount %d\n"
  1468. " AdditionalCount %d\n",
  1469. ( int ) pmsg->Head.ResponseCode,
  1470. ( int ) pmsg->Head.RecursionAvailable,
  1471. ( int ) pmsg->Head.QuestionCount,
  1472. ( int ) pmsg->Head.AnswerCount,
  1473. ( int ) pmsg->Head.NameServerCount,
  1474. ( int ) pmsg->Head.AdditionalCount );
  1475. ULONG64 pmsgbody = ( ULONG64 ) ( ( PBYTE ) p +
  1476. ( ( PBYTE ) pmsg->MessageBody -
  1477. ( PBYTE ) pmsg ) );
  1478. dprintf(
  1479. "DNS message body at %p\n",
  1480. pmsgbody );
  1481. Cleanup:
  1482. EXIT_API();
  1483. return S_OK;
  1484. } // Msg
  1485. //
  1486. // Set a max count to be respected by all other iterating commands.
  1487. // This is cool for example if you have a tree with a million nodes
  1488. // and you just want to dump the first few hundred to get an idea of
  1489. // what's going on.
  1490. //
  1491. HRESULT CALLBACK
  1492. MaxIterations(
  1493. PDEBUG_CLIENT Client,
  1494. PCSTR args )
  1495. {
  1496. INIT_API();
  1497. g_iMaxIterations = ( int ) GetExpression( args );
  1498. dprintf(
  1499. "MaxIterations set to %d%s\n",
  1500. g_iMaxIterations,
  1501. g_iMaxIterations == 0 ? " (unlimited)" : "" );
  1502. EXIT_API();
  1503. return S_OK;
  1504. } // MaxIterations
  1505. //
  1506. // Help for the other commands
  1507. //
  1508. HRESULT CALLBACK
  1509. help(
  1510. PDEBUG_CLIENT Client,
  1511. PCSTR args )
  1512. {
  1513. INIT_API();
  1514. dprintf(
  1515. "Help for dnsdbg.dll\n"
  1516. " Globals"
  1517. " Print current values of various globals.\n"
  1518. " ZoneList ADDR\n"
  1519. " Print zone list. Argument is address of listheadZone.\n"
  1520. " Zone ADDR\n"
  1521. " Print zone info. Argument is address of ZONE_INFO struct.\n"
  1522. " Node ADDR\n"
  1523. " Print node info. Argument is address of DB_NODE struct.\n" );
  1524. dprintf(
  1525. " Tree ADDR\n"
  1526. " Traverse and print a tree of nodes. Argument is address of the\n"
  1527. " tree root. The tree root can be a hash table or a DB_NODE.\n"
  1528. " TreeSummary ADDR\n"
  1529. " Traverse and print summary for a node tree. Argument same as Tree.\n"
  1530. " Stats ADDR\n"
  1531. " Print server statistics. Argument is address of StatsTable\n" );
  1532. dprintf(
  1533. " TimeoutSummary ADDR\n"
  1534. " Print summary of nodes in the timeout system.\n"
  1535. " Argument is address of TimeoutBinArray\n"
  1536. " TimeoutArrays ADDR\n"
  1537. " Print timeout system arrays. Argument is address of TimeoutBinArray\n"
  1538. " TimeoutNodes ADDR\n"
  1539. " Print timeout system arrays and nodes.\n"
  1540. " Argument is address of TimeoutBinArray\n"
  1541. " PacketQ ADDR\n"
  1542. " Print packet queue info. Argument is address of PACKET_QUEUE struct.\n"
  1543. " Msg ADDR\n"
  1544. " Print message info. Argument is address of DNS_MSGINFO struct.\n" );
  1545. dprintf(
  1546. " MaxIterations COUNT\n"
  1547. " Set max nodes or objects to visit. Argument is count in hex.\n"
  1548. " help - shows this help\n" );
  1549. EXIT_API();
  1550. return S_OK;
  1551. } // help