|
|
/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
trace.c
Abstract:
Domain Name System ( DNS ) API
DNS performance tracing functions.
Author:
Inder Sethi (bsethi) December, 2000
Revision History:
Jim Gilroy (jamesg) January 2001 cleanup, format, integrate, checkin
--*/
#include "local.h"
#include "trace.h"
#include <tchar.h>
#include <wmistr.h>
#include <guiddef.h>
#include <evntrace.h>
//
// FIX6: No IP6 support
//
// Message address extraction IP4
//
#define MSG_REMOTE_IP4(pMsg) \
( (pMsg)->RemoteAddress.SockaddrIn.sin_addr.s_addr )
//
// Tracing definitions
//
#define EVENT_TRACE_TYPE_UDP 9
#define EVENT_TRACE_TYPE_TCP 10
typedef struct _DnsSendEvent { EVENT_TRACE_HEADER EventHeader; DNS_HEADER DnsHeader; IP4_ADDRESS DnsServer; DNS_STATUS ReturnStatus; } DNS_SEND_EVENT, *PDNS_SEND_EVENT;
typedef struct _DnsRecvEvent { EVENT_TRACE_HEADER EventHeader; DNS_HEADER DnsHeader; IP4_ADDRESS DnsServer; DNS_STATUS ReturnStatus; } DNS_RECV_EVENT, *PDNS_RECV_EVENT;
typedef struct _DnsQueryEvent { EVENT_TRACE_HEADER EventHeader; WORD Xid; WORD QueryType; CHAR Query[256]; } DNS_QUERY_EVENT, *PDNS_QUERY_EVENT;
typedef struct _DnsResponseEvent { EVENT_TRACE_HEADER EventHeader; WORD Xid; WORD RespType; DNS_STATUS ReturnStatus; } DNS_RESPONSE_EVENT, *PDNS_RESPONSE_EVENT;
//
// Tracing globals
//
TRACEHANDLE g_LoggerHandle; TRACEHANDLE g_TraceRegHandle;
BOOL g_TraceOn; BOOL g_TraceInit; BOOL g_TraceInitInProgress; DWORD g_TraceLastInitAttempt;
ULONG g_NumEventGuids = 4;
//
// Allow retry on init every minute
//
#define TRACE_INIT_RETRY_TIME (60)
//
// MAX ???
//
#define MAXSTR 1024
//
// GUIDs
//
// Provider Guid: 1540ff4c-3fd7-4bba-9938-1d1bf31573a7
GUID ProviderGuid = {0x1540ff4c, 0x3fd7, 0x4bba, 0x99, 0x38, 0x1d, 0x1b, 0xf3, 0x15, 0x73, 0xa7};
//
// Event Guids:
// cc0c571b-d5f2-44fd-8b7f-de7770cc1984
// 6ddef4b8-9c60-423e-b1a6-deb9286fff1e
// 75f0c316-7bab-4e66-bed1-24091b1ac49e
// 9929b1c7-9e6a-4fc9-830a-f684e64f8aab
//
GUID DnsSendGuid = {0xcc0c571b, 0xd5f2, 0x44fd, 0x8b, 0x7f, 0xde, 0x77, 0x70, 0xcc, 0x19, 0x84};
GUID DnsRecvGuid = {0x6ddef4b8, 0x9c60, 0x423e, 0xb1, 0xa6, 0xde, 0xb9, 0x28, 0x6f, 0xff, 0x1e};
GUID DnsQueryGuid = {0x75f0c316, 0x7bab, 0x4e66, 0xbe, 0xd1, 0x24, 0x09, 0x1b, 0x1a, 0xc4, 0x9e};
GUID DnsResponseGuid = {0x9929b1c7, 0x9e6a, 0x4fc9, 0x83, 0x0a, 0xf6, 0x84, 0xe6, 0x4f, 0x8a, 0xab};
TRACE_GUID_REGISTRATION TraceGuidReg[] = { { &DnsSendGuid , NULL}, { &DnsRecvGuid , NULL}, { &DnsQueryGuid , NULL}, { &DnsResponseGuid, NULL} };
ULONG ControlCallback( IN WMIDPREQUESTCODE RequestCode, IN PVOID Context, IN OUT ULONG * InOutBufferSize, IN OUT PVOID Buffer ) /*++
Routine Description:
ControlCallback is the callback which ETW will call to enable or disable logging. This is called by the caller in a thread-safe manner ( only one call at any time ).
Meaning of arguments in MSDN.
--*/ { ULONG Status;
Status = ERROR_SUCCESS;
switch ( RequestCode ) { case WMI_ENABLE_EVENTS: { g_LoggerHandle = GetTraceLoggerHandle( Buffer ); g_TraceOn = TRUE; break; } case WMI_DISABLE_EVENTS: { g_TraceOn = FALSE; g_LoggerHandle = 0; break; } default: { Status = ERROR_INVALID_PARAMETER; break; } } return( Status ); }
VOID Trace_Initialize( VOID ) /*++
Routine Description:
Init DNS client tracing for DLL process attach.
Note, does not actually init the tracing, just inits tracing variables.
Arguments:
None.
Return Value:
None.
--*/ { g_TraceOn = FALSE; g_TraceInit = FALSE; g_TraceInitInProgress = FALSE; g_TraceLastInitAttempt = 0; }
VOID Trace_Cleanup( VOID ) /*++
Routine Description:
Cleaning tracing for DLL process detach.
Arguments:
None.
Return Value:
None.
--*/ { if ( g_TraceInit ) { UnregisterTraceGuids( g_TraceRegHandle ); } }
VOID InitializeTracePrivate( VOID ) /*++
Routine Description:
Real tracing init.
Arguments:
None
Globals:
g_TraceInit -- is set if successful
g_TraceLastInitAttempt -- is set with timestamp (in secs) if init attempt is made
g_TraceRegHandle -- if set if init was successful
Return Value:
None.
--*/ { ULONG status; TCHAR imagePath[MAXSTR]; DWORD currentTime; HMODULE hModule;
//
// don't try init if recently tried
//
currentTime = GetCurrentTimeInSeconds();
if ( currentTime < g_TraceLastInitAttempt + TRACE_INIT_RETRY_TIME ) { return; }
//
// protect init attempts
//
// note: use separate flag for interlock
// since the actual use of tracing is protected by a separate
// flag (g_TraceOn), it looks like we could directly use g_TraceInit
// as lock, as it can safely be set even when not initialize;
// however the cleanup function will attempt cleanup of g_TraceRegHandle
// and i'm using g_TraceInit to protect that;
// in theory we shouldn't get to cleanup function with a thread
// still active attempting this init, but better to lock it down
//
if ( InterlockedIncrement( &g_TraceInitInProgress ) != 1 ) { goto Unlock; }
g_TraceLastInitAttempt = currentTime;
hModule = GetModuleHandle(L"dnsapi.dll");
status = GetModuleFileName( hModule, &imagePath[0], MAXSTR);
if ( status == 0 ) { status = GetLastError(); DNSDBG( INIT, ( "Trace init failed GetModuleFileName() => %d\n", status )); goto Unlock; }
__try { status = RegisterTraceGuids( (WMIDPREQUEST) ControlCallback, //use same callback function
NULL, (LPCGUID ) &ProviderGuid, g_NumEventGuids, &TraceGuidReg[0], (LPCTSTR) &imagePath[0], (LPCTSTR) _T( "MofResource" ), &g_TraceRegHandle );
if ( status == ERROR_SUCCESS ) { g_TraceInit = TRUE; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { status = GetExceptionCode(); }
Unlock:
// clear init lockout
InterlockedDecrement( &g_TraceInitInProgress ); }
//
// Public DNS trace functions
//
VOID Trace_LogQueryEvent( IN PDNS_MSG_BUF pMsg, IN WORD wQuestionType ) /*++
Routine Description:
Logs query attempts.
Arguments:
pMsg -- Ptr to query sent
wQuestionType -- Query type
Return:
None
--*/ { DNS_QUERY_EVENT queryEvent;
if ( !g_TraceInit ) { InitializeTracePrivate(); }
if ( g_TraceOn ) { INT i; INT j; INT k;
RtlZeroMemory( &queryEvent, sizeof(DNS_QUERY_EVENT) );
queryEvent.EventHeader.Class.Type = 1; queryEvent.EventHeader.Guid = DnsQueryGuid; queryEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID; queryEvent.Xid = pMsg->MessageHead.Xid; queryEvent.QueryType = wQuestionType;
i = 0; j = pMsg->MessageBody[i]; i++;
while ( j != 0 ) { for( k = 0; k < j; k++, i++ ) { queryEvent.Query[i-1] = pMsg->MessageBody[i]; } j = pMsg->MessageBody[i]; queryEvent.Query[i-1] = '.'; i++; } queryEvent.Query[i-1] = '\0';
queryEvent.EventHeader.Size = sizeof(DNS_QUERY_EVENT) + strlen( queryEvent.Query ) - 255;
TraceEvent( g_LoggerHandle, (PEVENT_TRACE_HEADER) &queryEvent ); } }
VOID Trace_LogResponseEvent( IN PDNS_MSG_BUF pMsg, IN WORD wRespType, IN DNS_STATUS Status ) /*++
Routine Description:
Used to log information about the final response of a DNS query.
Arguments:
pMsg -- Address of the DNS_MSG_BUF containing response
wRespType -- Type of the first response record
Status -- Status returned
Return:
None
--*/ { DNS_RESPONSE_EVENT respEvent;
if ( !g_TraceInit ) { InitializeTracePrivate(); }
if ( g_TraceOn ) { RtlZeroMemory( &respEvent, sizeof(DNS_RESPONSE_EVENT) );
respEvent.EventHeader.Class.Type = 1; respEvent.EventHeader.Size = sizeof(DNS_RESPONSE_EVENT); respEvent.EventHeader.Guid = DnsResponseGuid; respEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID; respEvent.Xid = pMsg->MessageHead.Xid; respEvent.RespType = wRespType; respEvent.ReturnStatus = Status;
TraceEvent( g_LoggerHandle, (PEVENT_TRACE_HEADER) &respEvent ); } }
VOID Trace_LogSendEvent( IN PDNS_MSG_BUF pMsg, IN DNS_STATUS Status ) /*++
Routine Description:
Logs a TCP or UDP send event.
Arguments:
pMsg - message sent
Status - status of the send attempt
Return Value:
None
--*/ { DNS_SEND_EVENT sendEvent;
if ( !g_TraceInit ) { InitializeTracePrivate(); }
if ( g_TraceOn ) { UCHAR eventType = EVENT_TRACE_TYPE_UDP;
if ( pMsg->fTcp ) { eventType = EVENT_TRACE_TYPE_TCP; }
RtlZeroMemory( &sendEvent, sizeof(DNS_SEND_EVENT) );
sendEvent.EventHeader.Class.Type = eventType; sendEvent.EventHeader.Size = sizeof(DNS_SEND_EVENT); sendEvent.EventHeader.Guid = DnsSendGuid; sendEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID; sendEvent.DnsServer = MSG_REMOTE_IP4(pMsg); sendEvent.ReturnStatus = Status;
RtlCopyMemory( & sendEvent.DnsHeader, & pMsg->MessageHead, sizeof(DNS_HEADER) );
TraceEvent( g_LoggerHandle, (PEVENT_TRACE_HEADER) &sendEvent ); } }
VOID Trace_LogRecvEvent( IN PDNS_MSG_BUF pMsg, IN DNS_STATUS Status, IN BOOL fTcp ) /*++
Routine Description:
Logs information about a receive event.
Arguments:
pMsg - message received
Status - status returned from receive call
fTcp - TRUE for TCP recv; FALSE for UDP
Return Value:
None
--*/ { DNS_RECV_EVENT recvEvent;
if ( !g_TraceInit ) { InitializeTracePrivate(); }
if ( g_TraceOn ) { IP4_ADDRESS ipAddr = 0; UCHAR eventType = EVENT_TRACE_TYPE_UDP;
if ( fTcp ) { eventType = EVENT_TRACE_TYPE_TCP; } if ( pMsg ) {
ipAddr = MSG_REMOTE_IP4(pMsg); }
RtlZeroMemory( & recvEvent, sizeof(DNS_RECV_EVENT) );
recvEvent.EventHeader.Class.Type = eventType; recvEvent.EventHeader.Size = sizeof(DNS_RECV_EVENT); recvEvent.EventHeader.Guid = DnsRecvGuid; recvEvent.EventHeader.Flags = WNODE_FLAG_TRACED_GUID; recvEvent.DnsServer = ipAddr; recvEvent.ReturnStatus = Status;
if ( pMsg ) { RtlCopyMemory( & recvEvent.DnsHeader, & pMsg->MessageHead, sizeof(DNS_HEADER) ); }
TraceEvent( g_LoggerHandle, (PEVENT_TRACE_HEADER) &recvEvent ); } }
//
// End trace.c
//
|