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.

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