|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
FwLogger.cpp
Abstract:
Simple console logger for the personal firewall.
Author:
Jonathan Burstein (jonburs) 12-April-2000
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Name of the event trace session
//
_TCHAR cszLogSession[] = _T("FirewallLogSession");
//
// Event counters
//
LONG g_lDropped = 0; LONG g_lCCreated = 0; LONG g_lCDeleted = 0;
//
// GUIDs corresponding to the firewall trace events
//
GUID ConnectionCreationEventGuid = MSIPNAT_ConnectionCreationEventGuid; GUID ConnectionDeletionEventGuid = MSIPNAT_ConnectionDeletionEventGuid; GUID PacketDroppedEventGuid = MSIPNAT_PacketDroppedEventGuid;
//
// Event to signal for shutdown
//
HANDLE g_hShutdownEvent;
//
// Function prototypes
//
VOID CALLBACK ConnectionCreationCallback( PEVENT_TRACE pEvent );
VOID CALLBACK ConnectionDeletionCallback( PEVENT_TRACE pEvent );
BOOL WINAPI ControlHandler( DWORD dwCtrlType );
VOID CALLBACK PacketDroppedCallback( PEVENT_TRACE pEvent );
UINT WINAPI ProcessTraceRoutine( PVOID pvThreadParam );
int __cdecl main( int argc, _TCHAR **argv )
/*++
Routine Description:
Program entry point. Starts the logging session and launches the processing thread. Arguments:
argc -- count of command line arguments.
argv -- command line arguments
Return Value:
Error code.
--*/
{ TRACEHANDLE hSession; HANDLE hThread; HANDLE rghWaitHandles[2]; PEVENT_TRACE_PROPERTIES pProperties; ULONG ulError; ULONG ulSize; UINT uiThreadId; BOOL fWaitForThread = FALSE;
//
// Create the event used to signal that the program should exit
//
g_hShutdownEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( NULL == g_hShutdownEvent ) { _tprintf( _T("FwLogger: CreateEvent returned NULL (%08x)\n"), GetLastError() ); return -1; }
//
// Set our control handler. The handler will signal the shutdown event;
//
if( !SetConsoleCtrlHandler( ControlHandler, TRUE )) { _tprintf( _T("FwLogger: SetConsoleCtrlHandler failed (%08x)\n"), GetLastError() ); CloseHandle( g_hShutdownEvent ); return -1; }
//
// Initialize our trace properties and start the tracing session.
//
ulSize = sizeof(*pProperties) + (_tcslen( cszLogSession ) + 1) * sizeof(_TCHAR); pProperties = (PEVENT_TRACE_PROPERTIES) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize ); if( NULL == pProperties ) { _tprintf( _T("FwLogger: allocation failed\n" )); CloseHandle( g_hShutdownEvent ); return -1; }
pProperties->Wnode.BufferSize = ulSize; pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; pProperties->FlushTimer = 1; pProperties->BufferSize = 4; ulError = StartTrace( &hSession, cszLogSession, pProperties ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: StartTrace returned 0x%08x\n"), ulError ); CloseHandle( g_hShutdownEvent ); HeapFree( GetProcessHeap(), 0, pProperties ); return -1; }
//
// Enable the trace control guids
//
ulError = EnableTrace( TRUE, 0, 0, &PacketDroppedEventGuid, hSession );
if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: EnableTrace (PacketDropped) returned 0x%08x\n"), ulError ); goto StopTrace; }
ulError = EnableTrace( TRUE, 0, 0, &ConnectionCreationEventGuid, hSession );
if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: EnableTrace (ConnectionCreation) returned 0x%08x\n"), ulError ); goto StopTrace; }
//
// Launch a thread to process the trace data. This needs to happen in a
// separate thread as ProcessTrace blocks.
//
hThread = (HANDLE) _beginthreadex( NULL, 0, ProcessTraceRoutine, NULL, 0, &uiThreadId );
if( NULL == hThread ) { _tprintf( _T("FwLogger: Unable to create thread (0x%08x)\n"), GetLastError() ); goto StopTrace; }
//
// Wait for the shutdown event to be signalled, or for our
// thread to exit.
//
rghWaitHandles[0] = g_hShutdownEvent; rghWaitHandles[1] = hThread;
ulError = WaitForMultipleObjects( 2, rghWaitHandles, FALSE, INFINITE ); if( WAIT_OBJECT_0 == ulError ) { //
// User wants program to finish. After we shutdownt the trace session,
// we'll need to wait for the processing thread to cleanup and exit.
//
fWaitForThread = TRUE; _tprintf( _T("FwLogger: Shutdown event signaled\n") ); } else if( WAIT_OBJECT_0 + 1 == ulError ) { //
// Thread exited early, due to some problem...
//
_tprintf( _T("FwLogger: Trace process thread finished early.\n") ); }
StopTrace:
//
// Disable the events we previously enabled
//
ulError = EnableTrace( FALSE, 0, 0, &PacketDroppedEventGuid, hSession );
if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: EnableTrace (PacketDropped - FALSE) returned 0x%08x\n"), ulError ); }
ulError = EnableTrace( FALSE, 0, 0, &ConnectionCreationEventGuid, hSession );
if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: EnableTrace (ConnectionCreation - FALSE) returned 0x%08x\n"), ulError ); }
//
// Stop the trace
//
ZeroMemory( pProperties, ulSize ); pProperties->Wnode.BufferSize = ulSize; ulError = StopTrace( hSession, NULL, pProperties ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: StopTrace returned 0x%08x\n"), ulError ); } else { _tprintf( _T("FwLogger: Trace stopped\n\n") );
//
// Print out statistics
//
_tprintf( _T("**Packets dropped: %i\n"), g_lDropped ); _tprintf( _T("**Connections created: %i\n"), g_lCCreated ); _tprintf( _T("**Connections deleted: %i\n"), g_lCDeleted ); _tprintf( _T("**Events lost: %u\n"), pProperties->EventsLost ); _tprintf( _T("**Buffers lost: %u\n"), pProperties->LogBuffersLost ); _tprintf( _T("**Realtime buffers lost: %u\n\n"), pProperties->RealTimeBuffersLost ); }
//
// Give processing thread 15 seconds to finish
//
if( fWaitForThread ) { _tprintf( _T("FwLogger: Waiting for thread to exit...\n") ); ulError = WaitForSingleObject( hThread, 15 * 1000 ); if( WAIT_OBJECT_0 != ulError ) { _tprintf( _T("FwLogger: Wait failed (timeout = %s)\n"), WAIT_TIMEOUT == ulError ? _T("true") : _T("false") ); } }
CloseHandle( g_hShutdownEvent ); CloseHandle( hThread ); HeapFree( GetProcessHeap(), 0, pProperties ); return 0; }
VOID CALLBACK ConnectionCreationCallback( PEVENT_TRACE pEvent )
/*++
Routine Description:
Called when a ConnectionCreationEvent occurs. Arguments:
pEvent -- pointer to the event trace structure
Return Value:
None.
--*/
{ FILETIME ftUtcTime; FILETIME ftLocalTime; SYSTEMTIME stLocalTime; PMSIPNAT_ConnectionCreationEvent pEventData; struct in_addr inAddr;
InterlockedIncrement( &g_lCCreated ); pEventData = (PMSIPNAT_ConnectionCreationEvent) pEvent->MofData;
//
// Convert the event timestamp to local systemtime structure
//
ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart; ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart; if( !FileTimeToLocalFileTime( &ftUtcTime, &ftLocalTime ) || !FileTimeToSystemTime( &ftLocalTime, &stLocalTime )) { //
// Conversion failed -- use zero time
//
ZeroMemory( &stLocalTime, sizeof( SYSTEMTIME )); }
//
// Print timestamp (yyyy/mm/dd hh:mm:ss)
//
_tprintf( _T("%i/%02i/%02i %02i:%02i:%02i ++"), stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond );
//
// Connection details.
//
if( NAT_PROTOCOL_TCP == pEventData->Protocol ) { _tprintf( _T("TCP ") ); } else { _tprintf( _T("UDP ") ); }
if( pEventData->InboundConnection ) { _tprintf( _T("inbound ") ); } else { _tprintf( _T("outbound ") ); }
inAddr.s_addr = pEventData->LocalAddress; printf( inet_ntoa( inAddr )); _tprintf( _T("/%u :: "), ntohs( (u_short) pEventData->LocalPort ) );
inAddr.s_addr = pEventData->RemoteAddress; printf( inet_ntoa( inAddr ));
_tprintf( _T("/%u\n"), ntohs( (u_short) pEventData->RemotePort ) ); }
VOID CALLBACK ConnectionDeletionCallback( PEVENT_TRACE pEvent )
/*++
Routine Description:
Called when a ConnectionDeletionEvent occurs. Arguments:
pEvent -- pointer to the event trace structure
Return Value:
None.
--*/
{ FILETIME ftUtcTime; FILETIME ftLocalTime; SYSTEMTIME stLocalTime; PMSIPNAT_ConnectionDeletionEvent pEventData; struct in_addr inAddr;
InterlockedIncrement( &g_lCDeleted ); pEventData = (PMSIPNAT_ConnectionDeletionEvent) pEvent->MofData;
//
// Convert the event timestamp to local systemtime structure
//
ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart; ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart; if( !FileTimeToLocalFileTime( &ftUtcTime, &ftLocalTime ) || !FileTimeToSystemTime( &ftLocalTime, &stLocalTime )) { //
// Conversion failed -- use zero time
//
ZeroMemory( &stLocalTime, sizeof( SYSTEMTIME )); }
//
// Print timestamp (yyyy/mm/dd hh:mm:ss)
//
_tprintf( _T("%i/%02i/%02i %02i:%02i:%02i --"), stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond );
//
// Connection details.
//
if( NAT_PROTOCOL_TCP == pEventData->Protocol ) { _tprintf( _T("TCP ") ); } else { _tprintf( _T("UDP ") ); }
inAddr.s_addr = pEventData->LocalAddress; printf( inet_ntoa( inAddr )); _tprintf( _T("/%u :: "), ntohs( (u_short) pEventData->LocalPort ) );
inAddr.s_addr = pEventData->RemoteAddress; printf( inet_ntoa( inAddr ));
_tprintf( _T("/%u\n"), ntohs( (u_short) pEventData->RemotePort ) ); }
VOID CALLBACK PacketDroppedCallback( PEVENT_TRACE pEvent )
/*++
Routine Description:
Called when a PacketDroppedEvent occurs. Arguments:
pEvent -- pointer to the event trace structure
Return Value:
None.
--*/
{ FILETIME ftUtcTime; FILETIME ftLocalTime; SYSTEMTIME stLocalTime; PMSIPNAT_PacketDroppedEvent pEventData; struct in_addr inAddr;
InterlockedIncrement( &g_lDropped ); pEventData = (PMSIPNAT_PacketDroppedEvent) pEvent->MofData;
//
// Convert the event timestamp to local systemtime structure
//
ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart; ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart; if( !FileTimeToLocalFileTime( &ftUtcTime, &ftLocalTime ) || !FileTimeToSystemTime( &ftLocalTime, &stLocalTime )) { //
// Conversion failed -- use zero time
//
ZeroMemory( &stLocalTime, sizeof( SYSTEMTIME )); }
//
// Print timestamp (yyyy/mm/dd hh:mm:ss)
//
_tprintf( _T("%i/%02i/%02i %02i:%02i:%02i - "), stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond );
switch( pEventData->Protocol ) { case NAT_PROTOCOL_TCP: { _tprintf( _T("TCP: ") ); inAddr.s_addr = pEventData->SourceAddress; printf( inet_ntoa( inAddr )); _tprintf( _T("/%u -> "), ntohs( (u_short) pEventData->SourceIdentifier ) );
inAddr.s_addr = pEventData->DestinationAddress; printf( inet_ntoa( inAddr ));
_tprintf( _T("/%u "), ntohs( (u_short) pEventData->DestinationIdentifier ) );
if( pEventData->ProtocolData4 & TCP_FLAG_SYN ) { _tprintf( _T("S") ); }
if( pEventData->ProtocolData4 & TCP_FLAG_FIN ) { _tprintf( _T("F") ); }
if( pEventData->ProtocolData4 & TCP_FLAG_ACK ) { _tprintf( _T("A") ); } if( pEventData->ProtocolData4 & TCP_FLAG_RST ) { _tprintf( _T("R") ); } if( pEventData->ProtocolData4 & TCP_FLAG_URG ) { _tprintf( _T("U") ); }
if( pEventData->ProtocolData4 & TCP_FLAG_PSH ) { _tprintf( _T("P") ); }
_tprintf( _T("\n") ); break; }
case NAT_PROTOCOL_UDP: { _tprintf( _T("UDP: ") ); inAddr.s_addr = pEventData->SourceAddress; printf( inet_ntoa( inAddr )); _tprintf( _T("/%u -> "), ntohs( (u_short) pEventData->SourceIdentifier ) );
inAddr.s_addr = pEventData->DestinationAddress; printf( inet_ntoa( inAddr ));
_tprintf( _T("/%u\n"), ntohs( (u_short) pEventData->DestinationIdentifier ) ); break; }
case NAT_PROTOCOL_ICMP: { _tprintf( _T("ICMP: ") ); inAddr.s_addr = pEventData->SourceAddress; printf( inet_ntoa( inAddr )); _tprintf( _T(" -> ") );
inAddr.s_addr = pEventData->DestinationAddress; printf( "%s\n", inet_ntoa( inAddr ));
break; }
default: { _tprintf( _T("Prot. %i: "), pEventData->Protocol ); inAddr.s_addr = pEventData->SourceAddress; printf( inet_ntoa( inAddr )); _tprintf( _T(" -> ") );
inAddr.s_addr = pEventData->DestinationAddress; printf( "%s\n", inet_ntoa( inAddr )); } } }
UINT WINAPI ProcessTraceRoutine( PVOID pvThreadParam )
/*++
Routine Description:
Thread routine for trace processing. Arguments:
pvThreadParam -- unused. Return Value:
Thread exit code.
--*/
{ TRACEHANDLE hStream; EVENT_TRACE_LOGFILE LogFile; ULONG ulError; //
// Register our trace callbacks
//
ulError = SetTraceCallback( &PacketDroppedEventGuid, PacketDroppedCallback ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: SetTraceCallback (PacketDropped) returned 0x%08x\n"), ulError ); return -1; }
ulError = SetTraceCallback( &ConnectionCreationEventGuid, ConnectionCreationCallback ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: SetTraceCallback (ConnectionCreation) returned 0x%08x\n"), ulError ); return -1; }
ulError = SetTraceCallback( &ConnectionDeletionEventGuid, ConnectionDeletionCallback ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: SetTraceCallback (ConnectionDeletion) returned 0x%08x\n"), ulError ); return -1; }
//
// Open the event stream.
//
ZeroMemory( &LogFile, sizeof(LogFile) ); LogFile.LoggerName = cszLogSession; LogFile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
hStream = OpenTrace( &LogFile ); if( (TRACEHANDLE)INVALID_HANDLE_VALUE == hStream ) { _tprintf( _T("FwLogger: OpenTrace returned 0x%08x\n"), GetLastError() ); return -1; }
//
// Process the trace stream
//
_tprintf( _T("FwLogger: Calling ProcessTrace...\n") ); ulError = ProcessTrace( &hStream, 1, NULL, NULL ); if( ERROR_SUCCESS != ulError ) { _tprintf( _T("FwLogger: ProcessTrace returned 0x%08x\n"), ulError ); CloseTrace( hStream ); return -1; }
//
// Close the stream and exit
//
CloseTrace( hStream ); return 0; }
BOOL WINAPI ControlHandler( DWORD dwCtrlType )
/*++
Routine Description:
Signals our shutdown event when the user wants to exit. Arguments:
dwCtrlType -- control signal type
Return Value:
TRUE if we handled the control signal.
--*/
{ if( CTRL_LOGOFF_EVENT != dwCtrlType ) { SetEvent( g_hShutdownEvent ); return TRUE; }
return FALSE; }
|