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.

633 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. trace.c
  5. Abstract:
  6. Domain Name System ( DNS ) API
  7. DNS performance tracing functions.
  8. Author:
  9. Inder Sethi (bsethi) December, 2000
  10. Revision History:
  11. Jim Gilroy (jamesg) January 2001 cleanup, format, integrate, checkin
  12. --*/
  13. #include "local.h"
  14. #include "trace.h"
  15. #include <tchar.h>
  16. #include <wmistr.h>
  17. #include <guiddef.h>
  18. #include <evntrace.h>
  19. //
  20. // Tracing definitions
  21. //
  22. #define EVENT_TRACE_TYPE_UDP 9
  23. #define EVENT_TRACE_TYPE_TCP 10
  24. typedef struct _DnsSendEvent
  25. {
  26. EVENT_TRACE_HEADER EventHeader;
  27. DNS_HEADER DnsHeader;
  28. IP4_ADDRESS DnsServer;
  29. DNS_STATUS ReturnStatus;
  30. }
  31. DNS_SEND_EVENT, *PDNS_SEND_EVENT;
  32. typedef struct _DnsRecvEvent
  33. {
  34. EVENT_TRACE_HEADER EventHeader;
  35. DNS_HEADER DnsHeader;
  36. IP4_ADDRESS DnsServer;
  37. DNS_STATUS ReturnStatus;
  38. }
  39. DNS_RECV_EVENT, *PDNS_RECV_EVENT;
  40. typedef struct _DnsQueryEvent
  41. {
  42. EVENT_TRACE_HEADER EventHeader;
  43. WORD Xid;
  44. WORD QueryType;
  45. CHAR Query[256];
  46. }
  47. DNS_QUERY_EVENT, *PDNS_QUERY_EVENT;
  48. typedef struct _DnsResponseEvent
  49. {
  50. EVENT_TRACE_HEADER EventHeader;
  51. WORD Xid;
  52. WORD RespType;
  53. DNS_STATUS ReturnStatus;
  54. }
  55. DNS_RESPONSE_EVENT, *PDNS_RESPONSE_EVENT;
  56. //
  57. // Tracing globals
  58. //
  59. TRACEHANDLE g_LoggerHandle;
  60. TRACEHANDLE g_TraceRegHandle;
  61. BOOL g_TraceOn;
  62. BOOL g_TraceInit;
  63. BOOL g_TraceInitInProgress;
  64. DWORD g_TraceLastInitAttempt;
  65. ULONG g_NumEventGuids = 4;
  66. //
  67. // Allow retry on init every minute
  68. //
  69. #define TRACE_INIT_RETRY_TIME (60)
  70. //
  71. // MAX ???
  72. //
  73. #define MAXSTR 1024
  74. //
  75. // GUIDs
  76. //
  77. // Provider Guid: 1540ff4c-3fd7-4bba-9938-1d1bf31573a7
  78. GUID ProviderGuid =
  79. {0x1540ff4c, 0x3fd7, 0x4bba, 0x99, 0x38, 0x1d, 0x1b, 0xf3, 0x15, 0x73, 0xa7};
  80. //
  81. // Event Guids:
  82. // cc0c571b-d5f2-44fd-8b7f-de7770cc1984
  83. // 6ddef4b8-9c60-423e-b1a6-deb9286fff1e
  84. // 75f0c316-7bab-4e66-bed1-24091b1ac49e
  85. // 9929b1c7-9e6a-4fc9-830a-f684e64f8aab
  86. //
  87. GUID DnsSendGuid =
  88. {0xcc0c571b, 0xd5f2, 0x44fd, 0x8b, 0x7f, 0xde, 0x77, 0x70, 0xcc, 0x19, 0x84};
  89. GUID DnsRecvGuid =
  90. {0x6ddef4b8, 0x9c60, 0x423e, 0xb1, 0xa6, 0xde, 0xb9, 0x28, 0x6f, 0xff, 0x1e};
  91. GUID DnsQueryGuid =
  92. {0x75f0c316, 0x7bab, 0x4e66, 0xbe, 0xd1, 0x24, 0x09, 0x1b, 0x1a, 0xc4, 0x9e};
  93. GUID DnsResponseGuid =
  94. {0x9929b1c7, 0x9e6a, 0x4fc9, 0x83, 0x0a, 0xf6, 0x84, 0xe6, 0x4f, 0x8a, 0xab};
  95. TRACE_GUID_REGISTRATION TraceGuidReg[] =
  96. {
  97. { &DnsSendGuid , NULL},
  98. { &DnsRecvGuid , NULL},
  99. { &DnsQueryGuid , NULL},
  100. { &DnsResponseGuid, NULL}
  101. };
  102. ULONG
  103. ControlCallback(
  104. IN WMIDPREQUESTCODE RequestCode,
  105. IN PVOID Context,
  106. IN OUT ULONG * InOutBufferSize,
  107. IN OUT PVOID Buffer
  108. )
  109. /*++
  110. Routine Description:
  111. ControlCallback is the callback which ETW will call to enable or disable
  112. logging. This is called by the caller in a thread-safe manner ( only one
  113. call at any time ).
  114. Meaning of arguments in MSDN.
  115. --*/
  116. {
  117. ULONG Status;
  118. Status = ERROR_SUCCESS;
  119. switch ( RequestCode )
  120. {
  121. case WMI_ENABLE_EVENTS:
  122. {
  123. g_LoggerHandle = GetTraceLoggerHandle( Buffer );
  124. g_TraceOn = TRUE;
  125. break;
  126. }
  127. case WMI_DISABLE_EVENTS:
  128. {
  129. g_TraceOn = FALSE;
  130. g_LoggerHandle = 0;
  131. break;
  132. }
  133. default:
  134. {
  135. Status = ERROR_INVALID_PARAMETER;
  136. break;
  137. }
  138. }
  139. return( Status );
  140. }
  141. VOID
  142. Trace_Initialize(
  143. VOID
  144. )
  145. /*++
  146. Routine Description:
  147. Init DNS client tracing for DLL process attach.
  148. Note, does not actually init the tracing, just inits
  149. tracing variables.
  150. Arguments:
  151. None.
  152. Return Value:
  153. None.
  154. --*/
  155. {
  156. g_TraceOn = FALSE;
  157. g_TraceInit = FALSE;
  158. g_TraceInitInProgress = FALSE;
  159. g_TraceLastInitAttempt = 0;
  160. }
  161. VOID
  162. Trace_Cleanup(
  163. VOID
  164. )
  165. /*++
  166. Routine Description:
  167. Cleaning tracing for DLL process detach.
  168. Arguments:
  169. None.
  170. Return Value:
  171. None.
  172. --*/
  173. {
  174. if ( g_TraceInit )
  175. {
  176. UnregisterTraceGuids( g_TraceRegHandle );
  177. }
  178. }
  179. VOID
  180. InitializeTracePrivate(
  181. VOID
  182. )
  183. /*++
  184. Routine Description:
  185. Real tracing init.
  186. Arguments:
  187. None
  188. Globals:
  189. g_TraceInit -- is set if successful
  190. g_TraceLastInitAttempt -- is set with timestamp (in secs) if
  191. init attempt is made
  192. g_TraceRegHandle -- if set if init was successful
  193. Return Value:
  194. None.
  195. --*/
  196. {
  197. ULONG status;
  198. TCHAR imagePath[MAXSTR];
  199. DWORD currentTime;
  200. HMODULE hModule;
  201. //
  202. // don't try init if recently tried
  203. //
  204. currentTime = GetCurrentTimeInSeconds();
  205. if ( currentTime < g_TraceLastInitAttempt + TRACE_INIT_RETRY_TIME )
  206. {
  207. return;
  208. }
  209. //
  210. // protect init attempts
  211. //
  212. // note: use separate flag for interlock
  213. // since the actual use of tracing is protected by a separate
  214. // flag (g_TraceOn), it looks like we could directly use g_TraceInit
  215. // as lock, as it can safely be set even when not initialize;
  216. // however the cleanup function will attempt cleanup of g_TraceRegHandle
  217. // and i'm using g_TraceInit to protect that;
  218. // in theory we shouldn't get to cleanup function with a thread
  219. // still active attempting this init, but better to lock it down
  220. //
  221. if ( InterlockedIncrement( &g_TraceInitInProgress ) != 1 )
  222. {
  223. goto Unlock;
  224. }
  225. g_TraceLastInitAttempt = currentTime;
  226. hModule = GetModuleHandle("dnsapi.dll");
  227. status = GetModuleFileName(
  228. hModule,
  229. &imagePath[0],
  230. MAXSTR);
  231. if ( status == 0 )
  232. {
  233. status = GetLastError();
  234. DNSDBG( INIT, (
  235. "Trace init failed GetModuleFileName() => %d\n",
  236. status ));
  237. goto Unlock;
  238. }
  239. __try
  240. {
  241. status = RegisterTraceGuids(
  242. (WMIDPREQUEST) ControlCallback, //use same callback function
  243. NULL,
  244. (LPCGUID ) &ProviderGuid,
  245. g_NumEventGuids,
  246. &TraceGuidReg[0],
  247. (LPCTSTR) &imagePath[0],
  248. (LPCTSTR) _T( "MofResource" ),
  249. &g_TraceRegHandle
  250. );
  251. if ( status == ERROR_SUCCESS )
  252. {
  253. g_TraceInit = TRUE;
  254. }
  255. }
  256. __except ( EXCEPTION_EXECUTE_HANDLER )
  257. {
  258. status = GetExceptionCode();
  259. }
  260. Unlock:
  261. // clear init lockout
  262. InterlockedDecrement( &g_TraceInitInProgress );
  263. }
  264. //
  265. // Public DNS trace functions
  266. //
  267. VOID
  268. Trace_LogQueryEvent(
  269. IN PDNS_MSG_BUF pMsg,
  270. IN WORD wQuestionType
  271. )
  272. /*++
  273. Routine Description:
  274. Logs query attempts.
  275. Arguments:
  276. pMsg -- Ptr to query sent
  277. wQuestionType -- Query type
  278. Return:
  279. None
  280. --*/
  281. {
  282. DNS_QUERY_EVENT queryEvent;
  283. if ( !g_TraceInit )
  284. {
  285. InitializeTracePrivate();
  286. }
  287. if ( g_TraceOn )
  288. {
  289. INT i;
  290. INT j;
  291. INT k;
  292. RtlZeroMemory(
  293. &queryEvent,
  294. sizeof(DNS_QUERY_EVENT) );
  295. queryEvent.EventHeader.Class.Type = 1;
  296. queryEvent.EventHeader.Guid = DnsQueryGuid;
  297. queryEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID;
  298. queryEvent.Xid = pMsg->MessageHead.Xid;
  299. queryEvent.QueryType = wQuestionType;
  300. i = 0;
  301. j = pMsg->MessageBody[i];
  302. i++;
  303. while ( j != 0 )
  304. {
  305. for( k = 0; k < j; k++, i++ )
  306. {
  307. queryEvent.Query[i-1] = pMsg->MessageBody[i];
  308. }
  309. j = pMsg->MessageBody[i];
  310. queryEvent.Query[i-1] = '.';
  311. i++;
  312. }
  313. queryEvent.Query[i-1] = '\0';
  314. queryEvent.EventHeader.Size =
  315. sizeof(DNS_QUERY_EVENT) + strlen( queryEvent.Query ) - 255;
  316. TraceEvent(
  317. g_LoggerHandle,
  318. (PEVENT_TRACE_HEADER) &queryEvent );
  319. }
  320. }
  321. VOID
  322. Trace_LogResponseEvent(
  323. IN PDNS_MSG_BUF pMsg,
  324. IN WORD wRespType,
  325. IN DNS_STATUS Status
  326. )
  327. /*++
  328. Routine Description:
  329. Used to log information about the final response of a DNS query.
  330. Arguments:
  331. pMsg -- Address of the DNS_MSG_BUF containing response
  332. wRespType -- Type of the first response record
  333. Status -- Status returned
  334. Return:
  335. None
  336. --*/
  337. {
  338. DNS_RESPONSE_EVENT respEvent;
  339. if ( !g_TraceInit )
  340. {
  341. InitializeTracePrivate();
  342. }
  343. if ( g_TraceOn )
  344. {
  345. RtlZeroMemory(
  346. &respEvent,
  347. sizeof(DNS_RESPONSE_EVENT) );
  348. respEvent.EventHeader.Class.Type = 1;
  349. respEvent.EventHeader.Size = sizeof(DNS_RESPONSE_EVENT);
  350. respEvent.EventHeader.Guid = DnsResponseGuid;
  351. respEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID;
  352. respEvent.Xid = pMsg->MessageHead.Xid;
  353. respEvent.RespType = wRespType;
  354. respEvent.ReturnStatus = Status;
  355. TraceEvent(
  356. g_LoggerHandle,
  357. (PEVENT_TRACE_HEADER) &respEvent );
  358. }
  359. }
  360. VOID
  361. Trace_LogSendEvent(
  362. IN PDNS_MSG_BUF pMsg,
  363. IN DNS_STATUS Status
  364. )
  365. /*++
  366. Routine Description:
  367. Logs a TCP or UDP send event.
  368. Arguments:
  369. pMsg - message sent
  370. Status - status of the send attempt
  371. Return Value:
  372. None
  373. --*/
  374. {
  375. DNS_SEND_EVENT sendEvent;
  376. if ( !g_TraceInit )
  377. {
  378. InitializeTracePrivate();
  379. }
  380. if ( g_TraceOn )
  381. {
  382. UCHAR eventType = EVENT_TRACE_TYPE_UDP;
  383. if ( pMsg->fTcp )
  384. {
  385. eventType = EVENT_TRACE_TYPE_TCP;
  386. }
  387. RtlZeroMemory(
  388. &sendEvent,
  389. sizeof(DNS_SEND_EVENT) );
  390. sendEvent.EventHeader.Class.Type = eventType;
  391. sendEvent.EventHeader.Size = sizeof(DNS_SEND_EVENT);
  392. sendEvent.EventHeader.Guid = DnsSendGuid;
  393. sendEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID;
  394. sendEvent.DnsServer = MSG_REMOTE_IP4(pMsg);
  395. sendEvent.ReturnStatus = Status;
  396. RtlCopyMemory(
  397. & sendEvent.DnsHeader,
  398. & pMsg->MessageHead,
  399. sizeof(DNS_HEADER) );
  400. TraceEvent(
  401. g_LoggerHandle,
  402. (PEVENT_TRACE_HEADER) &sendEvent );
  403. }
  404. }
  405. VOID
  406. Trace_LogRecvEvent(
  407. IN PDNS_MSG_BUF pMsg,
  408. IN DNS_STATUS Status,
  409. IN BOOL fTcp
  410. )
  411. /*++
  412. Routine Description:
  413. Logs information about a receive event.
  414. Arguments:
  415. pMsg - message received
  416. Status - status returned from receive call
  417. fTcp - TRUE for TCP recv; FALSE for UDP
  418. Return Value:
  419. None
  420. --*/
  421. {
  422. DNS_RECV_EVENT recvEvent;
  423. if ( !g_TraceInit )
  424. {
  425. InitializeTracePrivate();
  426. }
  427. if ( g_TraceOn )
  428. {
  429. IP4_ADDRESS ipAddr = 0;
  430. UCHAR eventType = EVENT_TRACE_TYPE_UDP;
  431. if ( fTcp )
  432. {
  433. eventType = EVENT_TRACE_TYPE_TCP;
  434. }
  435. if ( pMsg )
  436. {
  437. ipAddr = MSG_REMOTE_IP4(pMsg);
  438. }
  439. RtlZeroMemory(
  440. & recvEvent,
  441. sizeof(DNS_RECV_EVENT) );
  442. recvEvent.EventHeader.Class.Type = eventType;
  443. recvEvent.EventHeader.Size = sizeof(DNS_RECV_EVENT);
  444. recvEvent.EventHeader.Guid = DnsRecvGuid;
  445. recvEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID;
  446. recvEvent.DnsServer = ipAddr;
  447. recvEvent.ReturnStatus = Status;
  448. if ( pMsg )
  449. {
  450. RtlCopyMemory(
  451. & recvEvent.DnsHeader,
  452. & pMsg->MessageHead,
  453. sizeof(DNS_HEADER) );
  454. }
  455. TraceEvent(
  456. g_LoggerHandle,
  457. (PEVENT_TRACE_HEADER) &recvEvent );
  458. }
  459. }
  460. //
  461. // End trace.c
  462. //