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.

2921 lines
66 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. fwlogger.cpp
  5. Abstract:
  6. Support for firewall logging to a text file.
  7. Author:
  8. Jonathan Burstein (jonburs) 18 September 2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #if DBG
  14. //
  15. // Module state -- interlocked access only. This information
  16. // is only used on debug builds.
  17. //
  18. typedef enum {
  19. FwUninitialized = 0,
  20. FwInitialized
  21. } FW_MODULE_STATE;
  22. FW_MODULE_STATE FwpModuleState = FwUninitialized;
  23. #endif // DBG
  24. //
  25. // Globals. If both locks need to be held at the same time,
  26. // g_FwFileLock must be acquired first.
  27. //
  28. CRITICAL_SECTION g_FwLock;
  29. HNET_FW_LOGGING_SETTINGS *g_pSettings;
  30. TRACEHANDLE g_hSession;
  31. HANDLE g_hThread;
  32. BOOLEAN g_fTracingActive;
  33. ULONG g_ulKernelEventsLostAtShutdown;
  34. CRITICAL_SECTION g_FwFileLock;
  35. HANDLE g_hFile;
  36. DWORD g_dwFileOffset;
  37. PFW_LOG_BUFFER g_pCurrentBuffer;
  38. PFW_LOG_BUFFER g_pReserveBuffer;
  39. BOOLEAN g_fIOPending;
  40. HANDLE g_hIOEvent;
  41. ULONG g_ulDroppedEventCount;
  42. ULONG g_ulKernelEventsLost;
  43. HANDLE g_hDroppedEventTimer;
  44. //
  45. // Constants
  46. //
  47. GUID c_ConnectionCreationEventGuid = MSIPNAT_ConnectionCreationEventGuid;
  48. GUID c_ConnectionDeletionEventGuid = MSIPNAT_ConnectionDeletionEventGuid;
  49. GUID c_PacketDroppedEventGuid = MSIPNAT_PacketDroppedEventGuid;
  50. WCHAR c_wszLogSessionName[] = L"FirewallLogSession";
  51. WCHAR c_wszBackupFileExtension[] = L".old";
  52. CHAR c_szConnectionFormat[] = "%04d-%02d-%02d %02d:%02d:%02d %s %s %s %s %u %u - - - - - - - -\r\n";
  53. CHAR c_szTcpPacketFormat[] = "%04d-%02d-%02d %02d:%02d:%02d DROP TCP %s %s %u %u %u %s %u %u %u - - -\r\n";
  54. CHAR c_szUdpPacketFormat[] = "%04d-%02d-%02d %02d:%02d:%02d DROP UDP %s %s %u %u %u - - - - - - -\r\n";
  55. CHAR c_szIcmpPacketFormat[] = "%04d-%02d-%02d %02d:%02d:%02d DROP ICMP %s %s - - %u - - - - %u %u -\r\n";
  56. CHAR c_szDroppedPacketFormat[] = "%04d-%02d-%02d %02d:%02d:%02d DROP %u %s %s - - %u - - - - - - -\r\n";
  57. CHAR c_szEventsLostFormat[] = "%04d-%02d-%02d %02d:%02d:%02d INFO-EVENTS-LOST - - - - - - - - - - - - %u\r\n";
  58. CHAR c_szAcceptInbound[] = "OPEN-INBOUND";
  59. CHAR c_szAcceptOutbound[] = "OPEN";
  60. CHAR c_szTcp[] = "TCP";
  61. CHAR c_szUdp[] = "UDP";
  62. CHAR c_szLogFileHeader[]
  63. = "#Verson: 1.0\r\n#Software: Microsoft Internet Connection Firewall\r\n#Time Format: Local\r\n#Fields: date time action protocol src-ip dst-ip src-port dst-port size tcpflags tcpsyn tcpack tcpwin icmptype icmpcode info\r\n\r\n";
  64. //
  65. // Function Prototypes
  66. //
  67. DWORD
  68. FwpAllocateBuffer(
  69. PFW_LOG_BUFFER *ppBuffer
  70. );
  71. PEVENT_TRACE_PROPERTIES
  72. FwpAllocateTraceProperties(
  73. VOID
  74. );
  75. DWORD
  76. FwpBackupFile(
  77. LPWSTR pszwPath
  78. );
  79. VOID
  80. FwpCleanupTraceThreadResources(
  81. VOID
  82. );
  83. VOID
  84. CALLBACK
  85. FwpCompletionRoutine(
  86. DWORD dwErrorCode,
  87. DWORD dwBytesTransferred,
  88. LPOVERLAPPED pOverlapped
  89. );
  90. VOID
  91. WINAPI
  92. FwpConnectionCreationCallback(
  93. PEVENT_TRACE pEvent
  94. );
  95. VOID
  96. WINAPI
  97. FwpConnectionDeletionCallback(
  98. PEVENT_TRACE pEvent
  99. );
  100. VOID
  101. FwpConvertUtcFiletimeToLocalSystemtime(
  102. FILETIME *pFiletime,
  103. SYSTEMTIME *pSystemtime
  104. );
  105. VOID
  106. CALLBACK
  107. FwpDroppedEventTimerRoutine(
  108. PVOID pvParameter,
  109. BOOLEAN fWaitTimeout
  110. );
  111. DWORD
  112. FwpFlushCurrentBuffer(
  113. VOID
  114. );
  115. DWORD
  116. FwpOpenLogFile(
  117. HANDLE *phFile,
  118. BOOLEAN *pfNewFile
  119. );
  120. VOID
  121. WINAPI
  122. FwpPacketDroppedCallback(
  123. PEVENT_TRACE pEvent
  124. );
  125. DWORD
  126. FwpLaunchTraceSession(
  127. HNET_FW_LOGGING_SETTINGS *pSettings,
  128. TRACEHANDLE *phSession
  129. );
  130. HRESULT
  131. FwpLoadSettings(
  132. HNET_FW_LOGGING_SETTINGS **ppSettings
  133. );
  134. DWORD
  135. WINAPI
  136. FwpTraceProcessingThreadRoutine(
  137. LPVOID pvParam
  138. );
  139. DWORD
  140. FwpWriteLogHeaderToBuffer(
  141. PFW_LOG_BUFFER pBuffer
  142. );
  143. VOID
  144. FwCleanupLogger(
  145. VOID
  146. )
  147. /*++
  148. Routine Description:
  149. This routine is called to cleanup the logging subsystem. All
  150. resources in use will be freed. After this call, the only valid
  151. routine in this module is FwInitializeLogger.
  152. Arguments:
  153. none.
  154. Return Value:
  155. none.
  156. Environment:
  157. Caller must not be holding g_FwFileLock or g_FwLock
  158. --*/
  159. {
  160. PROFILE("FwCleanupLogger");
  161. //
  162. // Make sure the logging is stopped
  163. //
  164. FwStopLogging();
  165. ASSERT(FwInitialized ==
  166. (FW_MODULE_STATE) InterlockedExchange(
  167. (LPLONG) &FwpModuleState,
  168. (LONG) FwUninitialized
  169. ));
  170. EnterCriticalSection(&g_FwLock);
  171. ASSERT(NULL == g_hSession);
  172. ASSERT(NULL == g_hThread);
  173. ASSERT(INVALID_HANDLE_VALUE == g_hFile);
  174. if (g_pSettings) HNetFreeFirewallLoggingSettings(g_pSettings);
  175. LeaveCriticalSection(&g_FwLock);
  176. DeleteCriticalSection(&g_FwLock);
  177. DeleteCriticalSection(&g_FwFileLock);
  178. } // FwCleanupLogger
  179. DWORD
  180. FwInitializeLogger(
  181. VOID
  182. )
  183. /*++
  184. Routine Description:
  185. This routine is called to control to initialize the logging subsystem.
  186. It must be called before any of the other routines in this module, and
  187. may not be called again until after a call to FwCleanupLogger.
  188. Arguments:
  189. none.
  190. Return Value:
  191. DWORD -- Win32 error code
  192. --*/
  193. {
  194. DWORD dwError = NO_ERROR;
  195. BOOLEAN fFirstLockInitialized = FALSE;
  196. PROFILE("FwInitializeLogger");
  197. ASSERT(FwUninitialized ==
  198. (FW_MODULE_STATE) InterlockedExchange(
  199. (LPLONG) &FwpModuleState,
  200. (LONG) FwInitialized
  201. ));
  202. __try
  203. {
  204. InitializeCriticalSection(&g_FwLock);
  205. fFirstLockInitialized = TRUE;
  206. InitializeCriticalSection(&g_FwFileLock);
  207. }
  208. __except(EXCEPTION_EXECUTE_HANDLER)
  209. {
  210. NhTrace(
  211. TRACE_FLAG_FWLOG,
  212. "FwInitializeLogger: exception %d creating lock",
  213. dwError = GetExceptionCode()
  214. );
  215. if (fFirstLockInitialized)
  216. {
  217. DeleteCriticalSection(&g_FwLock);
  218. }
  219. #if DBG
  220. InterlockedExchange(
  221. (LPLONG) &FwpModuleState,
  222. (LONG) FwUninitialized
  223. );
  224. #endif
  225. }
  226. g_pSettings = NULL;
  227. g_hSession = NULL;
  228. g_hThread = NULL;
  229. g_fTracingActive = FALSE;
  230. g_ulKernelEventsLostAtShutdown = 0;
  231. g_hFile = INVALID_HANDLE_VALUE;
  232. g_dwFileOffset = 0;
  233. g_pCurrentBuffer = NULL;
  234. g_pReserveBuffer = NULL;
  235. g_fIOPending = FALSE;
  236. g_hIOEvent = NULL;
  237. g_ulDroppedEventCount = 0;
  238. g_ulKernelEventsLost = 0;
  239. g_hDroppedEventTimer = NULL;
  240. return dwError;
  241. } // FwInitializeLogger
  242. DWORD
  243. FwpAllocateBuffer(
  244. PFW_LOG_BUFFER *ppBuffer
  245. )
  246. /*++
  247. Routine Description:
  248. Allocates an initializes an FW_LOG_BUFFER structure
  249. Arguments:
  250. ppBuffer - receives a pointer to the newly-allocated structure
  251. Return Value:
  252. DWORD - Win32 error code
  253. --*/
  254. {
  255. DWORD dwError = ERROR_SUCCESS;
  256. PROFILE("FwpAllocateBuffer");
  257. ASSERT(NULL != ppBuffer);
  258. *ppBuffer =
  259. reinterpret_cast<PFW_LOG_BUFFER>(
  260. NH_ALLOCATE(sizeof(**ppBuffer))
  261. );
  262. if (NULL != *ppBuffer)
  263. {
  264. ZeroMemory(&(*ppBuffer)->Overlapped, sizeof(OVERLAPPED));
  265. (*ppBuffer)->pChar = (*ppBuffer)->Buffer;
  266. }
  267. else
  268. {
  269. dwError = ERROR_NOT_ENOUGH_MEMORY;
  270. }
  271. return dwError;
  272. } // FwpAllocateBuffer
  273. PEVENT_TRACE_PROPERTIES
  274. FwpAllocateTraceProperties(
  275. VOID
  276. )
  277. /*++
  278. Routine Description:
  279. Allocates and partially initializes an EVENT_TRACE_PROPERTIES structure.
  280. Arguments:
  281. none.
  282. Return Value:
  283. PEVENT_TRACE_PROPERTIES - pointer to the allocated structure. The caller
  284. must call HeapFree(GetProcessHeap(),...) on this pointer.
  285. --*/
  286. {
  287. PEVENT_TRACE_PROPERTIES pProperties = NULL;
  288. ULONG ulSize;
  289. ulSize = sizeof(*pProperties)
  290. + ((wcslen(c_wszLogSessionName) + 1) * sizeof(WCHAR));
  291. pProperties = (PEVENT_TRACE_PROPERTIES) HeapAlloc(
  292. GetProcessHeap(),
  293. HEAP_ZERO_MEMORY,
  294. ulSize
  295. );
  296. if (NULL == pProperties)
  297. {
  298. NhTrace(
  299. TRACE_FLAG_FWLOG,
  300. "FwpAllocateTraceProperties: Unable to allocate %d bytes",
  301. ulSize
  302. );
  303. return NULL;
  304. }
  305. pProperties->Wnode.BufferSize = ulSize;
  306. pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  307. pProperties->Wnode.ClientContext = EVENT_TRACE_CLOCK_SYSTEMTIME;
  308. pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
  309. pProperties->LoggerNameOffset = sizeof(*pProperties);
  310. return pProperties;
  311. } // FwpAllocateTraceProperties
  312. DWORD
  313. FwpBackupFile(
  314. LPWSTR pszwPath
  315. )
  316. /*++
  317. Routine Description:
  318. Backs-up a file to filename.xxx.old
  319. Arguments:
  320. pszwPath - path to the file to backup
  321. Return Value:
  322. DWORD - Win32 error code
  323. --*/
  324. {
  325. DWORD dwError = ERROR_SUCCESS;
  326. BOOL fResult;
  327. LPWSTR wszBuffer;
  328. ASSERT(NULL != pszwPath);
  329. //
  330. // Allocate buffer to hold new filename
  331. //
  332. wszBuffer =
  333. new WCHAR[wcslen(pszwPath) + wcslen(c_wszBackupFileExtension) + 1];
  334. if (NULL != wszBuffer)
  335. {
  336. lstrcpyW(wszBuffer, pszwPath);
  337. lstrcatW(wszBuffer, c_wszBackupFileExtension);
  338. fResult = MoveFileEx(pszwPath, wszBuffer, MOVEFILE_REPLACE_EXISTING);
  339. if (FALSE == fResult)
  340. {
  341. dwError = GetLastError();
  342. NhTrace(
  343. TRACE_FLAG_FWLOG,
  344. "FwpBackupFile: MoveFileEx = %d",
  345. dwError
  346. );
  347. }
  348. }
  349. else
  350. {
  351. dwError = ERROR_NOT_ENOUGH_MEMORY;
  352. NhTrace(
  353. TRACE_FLAG_FWLOG,
  354. "FwpBackupFile: Unable to allolcate buffer"
  355. );
  356. }
  357. return dwError;
  358. } // FwpBackupFile
  359. VOID
  360. FwpCleanupTraceThreadResources(
  361. VOID
  362. )
  363. /*++
  364. Routine Description:
  365. Cleans up resources used by the trace processing thread:
  366. * revokes event callbacks
  367. * waits for IO to complete, if pending
  368. * closes the log file
  369. * frees buffers
  370. Arguments:
  371. none.
  372. Return Value:
  373. none.
  374. Environment:
  375. The caller must not hold g_FwFileLock or g_FwLock.
  376. --*/
  377. {
  378. DWORD dwError;
  379. PROFILE("FwpCleanupTraceThreadResources");
  380. //
  381. // Unregister the trace callbacks. It is safe to call these even
  382. // if the callbacks weren't registered to begin with.
  383. //
  384. RemoveTraceCallback(&c_PacketDroppedEventGuid);
  385. RemoveTraceCallback(&c_ConnectionCreationEventGuid);
  386. RemoveTraceCallback(&c_ConnectionDeletionEventGuid);
  387. EnterCriticalSection(&g_FwFileLock);
  388. //
  389. // Cancel the dropped packet timer
  390. //
  391. if (NULL != g_hDroppedEventTimer)
  392. {
  393. DeleteTimerQueueTimer(
  394. NULL,
  395. g_hDroppedEventTimer,
  396. INVALID_HANDLE_VALUE
  397. );
  398. g_hDroppedEventTimer = NULL;
  399. }
  400. //
  401. // If necessary, wait for any pending IO operations to complete
  402. //
  403. if (g_fIOPending)
  404. {
  405. g_hIOEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  406. if (NULL != g_hIOEvent)
  407. {
  408. HANDLE hEvent = g_hIOEvent;
  409. LeaveCriticalSection(&g_FwFileLock);
  410. dwError = WaitForSingleObject(hEvent, 20 * 1000);
  411. if (WAIT_OBJECT_0 != dwError)
  412. {
  413. NhTrace(
  414. TRACE_FLAG_FWLOG,
  415. "FwpTraceProcessingRoutine: Wait(g_hIOEvent) = %d/%d",
  416. dwError,
  417. GetLastError()
  418. );
  419. //
  420. // It should never take 20 seconds for an IO to complete,
  421. // so let's get immediate notification of this on debug
  422. // builds.
  423. //
  424. ASSERT(WAIT_OBJECT_0 == dwError);
  425. }
  426. EnterCriticalSection(&g_FwFileLock);
  427. CloseHandle(g_hIOEvent);
  428. g_hIOEvent = NULL;
  429. }
  430. }
  431. g_fIOPending = FALSE;
  432. //
  433. // Close the log file
  434. //
  435. if (INVALID_HANDLE_VALUE != g_hFile)
  436. {
  437. CloseHandle(g_hFile);
  438. g_hFile = INVALID_HANDLE_VALUE;
  439. }
  440. g_dwFileOffset = 0;
  441. //
  442. // Clean up our buffers
  443. //
  444. if (NULL != g_pCurrentBuffer)
  445. {
  446. NH_FREE(g_pCurrentBuffer);
  447. g_pCurrentBuffer = NULL;
  448. }
  449. if (NULL != g_pReserveBuffer)
  450. {
  451. NH_FREE(g_pReserveBuffer);
  452. g_pReserveBuffer = NULL;
  453. }
  454. //
  455. // Reset dropped event counts
  456. //
  457. g_ulDroppedEventCount = 0;
  458. g_ulKernelEventsLost = 0;
  459. LeaveCriticalSection(&g_FwFileLock);
  460. } // FwpCleanupTraceThreadResources
  461. VOID
  462. CALLBACK
  463. FwpCompletionRoutine(
  464. DWORD dwErrorCode,
  465. DWORD dwBytesTransferred,
  466. LPOVERLAPPED pOverlapped
  467. )
  468. /*++
  469. Routine Description:
  470. Completion routine called by the system thread pool when our
  471. IO operation is finished. Responsible for updating the file
  472. position and starting a new IO operation if necessary.
  473. Arguments:
  474. dwErrorCode - result of the IO operation
  475. dwBytesTransferred - number of bytes transferred during the operation
  476. pOverlapped - pointer to the overlapped structure for the operation. We
  477. can recover the FW_LOG_BUFFER structure from this pointer.
  478. Return Value:
  479. none.
  480. --*/
  481. {
  482. PFW_LOG_BUFFER pBuffer;
  483. EnterCriticalSection(&g_FwFileLock);
  484. //
  485. // Adjust our file offset
  486. //
  487. if (ERROR_SUCCESS == dwErrorCode)
  488. {
  489. g_dwFileOffset += dwBytesTransferred;
  490. }
  491. else
  492. {
  493. NhTrace(
  494. TRACE_FLAG_FWLOG,
  495. "FwpCompletionRoutine: dwErrorCode = %d",
  496. dwErrorCode
  497. );
  498. }
  499. g_fIOPending = FALSE;
  500. //
  501. // Reset the buffer that was passed in
  502. //
  503. ASSERT(NULL != pOverlapped);
  504. pBuffer = CONTAINING_RECORD(pOverlapped, FW_LOG_BUFFER, Overlapped);
  505. ZeroMemory(&pBuffer->Overlapped, sizeof(OVERLAPPED));
  506. pBuffer->pChar = pBuffer->Buffer;
  507. //
  508. // Check if the file is at the size limit
  509. //
  510. EnterCriticalSection(&g_FwLock);
  511. ASSERT(NULL != g_pSettings);
  512. if (g_dwFileOffset >= g_pSettings->ulMaxFileSize)
  513. {
  514. DWORD dwError;
  515. BOOLEAN fNewFile;
  516. CloseHandle(g_hFile);
  517. g_hFile = INVALID_HANDLE_VALUE;
  518. //
  519. // If FwpBackupFile fails, FwpOpenFile will still do
  520. // the right thing.
  521. //
  522. FwpBackupFile(g_pSettings->pszwPath);
  523. g_dwFileOffset = 0;
  524. dwError = FwpOpenLogFile(&g_hFile, &fNewFile);
  525. if (ERROR_SUCCESS != dwError)
  526. {
  527. NhTrace(
  528. TRACE_FLAG_FWLOG,
  529. "FwpCompletionRoutine: FwpOpenLogFile = %d",
  530. dwError
  531. );
  532. NH_FREE(pBuffer);
  533. LeaveCriticalSection(&g_FwLock);
  534. LeaveCriticalSection(&g_FwFileLock);
  535. FwStopLogging();
  536. return;
  537. }
  538. else if (TRUE == fNewFile)
  539. {
  540. //
  541. // Need to write header.
  542. //
  543. if (ERROR_SUCCESS == FwpWriteLogHeaderToBuffer(pBuffer))
  544. {
  545. PFW_LOG_BUFFER pTempBuffer = g_pCurrentBuffer;
  546. g_pCurrentBuffer = pBuffer;
  547. FwpFlushCurrentBuffer();
  548. g_pCurrentBuffer = pTempBuffer;
  549. pBuffer = NULL;
  550. }
  551. }
  552. else
  553. {
  554. g_dwFileOffset = GetFileSize(g_hFile, NULL);
  555. if ((DWORD)-1 == g_dwFileOffset)
  556. {
  557. NhTrace(
  558. TRACE_FLAG_FWLOG,
  559. "FwpCompletionRoutine: GetFileSize = %d",
  560. GetLastError()
  561. );
  562. NH_FREE(pBuffer);
  563. LeaveCriticalSection(&g_FwLock);
  564. LeaveCriticalSection(&g_FwFileLock);
  565. FwStopLogging();
  566. return;
  567. }
  568. }
  569. }
  570. LeaveCriticalSection(&g_FwLock);
  571. //
  572. // See if we need to start a new operation.
  573. //
  574. if (FALSE == g_fIOPending && NULL != g_pCurrentBuffer)
  575. {
  576. if (g_pCurrentBuffer->pChar != g_pCurrentBuffer->Buffer)
  577. {
  578. //
  579. // Current buffer needs to be flushed
  580. //
  581. FwpFlushCurrentBuffer();
  582. }
  583. }
  584. //
  585. // Place buffer into storage. If we're using the buffer
  586. // to write the log header, it will be NULL at this point
  587. //
  588. if (NULL != pBuffer)
  589. {
  590. if (NULL == g_pCurrentBuffer)
  591. {
  592. g_pCurrentBuffer = pBuffer;
  593. }
  594. else if (NULL == g_pReserveBuffer)
  595. {
  596. g_pReserveBuffer = pBuffer;
  597. }
  598. else
  599. {
  600. //
  601. // Both buffer slots are already in use -- unexpected.
  602. // Assert and free the extra buffer
  603. //
  604. ASSERT(NULL == g_pCurrentBuffer || NULL == g_pReserveBuffer);
  605. NH_FREE(pBuffer);
  606. }
  607. }
  608. //
  609. // Check to see if we need to signal the IO finished event
  610. //
  611. if (!g_fIOPending && NULL != g_hIOEvent)
  612. {
  613. if (!SetEvent(g_hIOEvent))
  614. {
  615. NhTrace(
  616. TRACE_FLAG_FWLOG,
  617. "FwpCompletionRoutine: SetEvent = %d",
  618. GetLastError()
  619. );
  620. }
  621. }
  622. LeaveCriticalSection(&g_FwFileLock);
  623. } // FwpCompletionRoutine
  624. VOID
  625. WINAPI
  626. FwpConnectionCreationCallback(
  627. PEVENT_TRACE pEvent
  628. )
  629. /*++
  630. Routine Description:
  631. This routine is called to process a connection creation event.
  632. Arguments:
  633. pEvent - pointer to the event structure
  634. Return Value:
  635. none.
  636. --*/
  637. {
  638. PMSIPNAT_ConnectionCreationEvent pEventData;
  639. FILETIME ftUtcTime;
  640. SYSTEMTIME stLocalTime;
  641. PCHAR pszAction;
  642. PCHAR pszProtocol;
  643. CHAR szSrcAddress[16];
  644. CHAR szDstAddress[16];
  645. USHORT usSrcPort;
  646. USHORT usDstPort;
  647. int cch;
  648. EnterCriticalSection(&g_FwFileLock);
  649. //
  650. // Get a buffer to write to.
  651. //
  652. if (NULL == g_pCurrentBuffer)
  653. {
  654. if (NULL == g_pReserveBuffer)
  655. {
  656. if (ERROR_SUCCESS != FwpAllocateBuffer(&g_pCurrentBuffer))
  657. {
  658. NhTrace(
  659. TRACE_FLAG_FWLOG,
  660. "FwpConnectionCreationCallback: Unable to allocate buffer"
  661. );
  662. //
  663. // Record the dropped event
  664. //
  665. g_ulDroppedEventCount += 1;
  666. LeaveCriticalSection(&g_FwFileLock);
  667. return;
  668. }
  669. }
  670. else
  671. {
  672. g_pCurrentBuffer = g_pReserveBuffer;
  673. g_pReserveBuffer = NULL;
  674. }
  675. }
  676. ASSERT(NULL != g_pCurrentBuffer);
  677. //
  678. // Crack logging data
  679. //
  680. pEventData = (PMSIPNAT_ConnectionCreationEvent) pEvent->MofData;
  681. ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart;
  682. ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart;
  683. FwpConvertUtcFiletimeToLocalSystemtime(&ftUtcTime, &stLocalTime);
  684. if (pEventData->InboundConnection)
  685. {
  686. pszAction = c_szAcceptInbound;
  687. lstrcpyA(szSrcAddress, INET_NTOA(pEventData->RemoteAddress));
  688. usSrcPort = ntohs(pEventData->RemotePort);
  689. lstrcpyA(szDstAddress, INET_NTOA(pEventData->LocalAddress));
  690. usDstPort = ntohs(pEventData->LocalPort);
  691. }
  692. else
  693. {
  694. pszAction = c_szAcceptOutbound;
  695. lstrcpyA(szSrcAddress, INET_NTOA(pEventData->LocalAddress));
  696. usSrcPort = ntohs(pEventData->LocalPort);
  697. lstrcpyA(szDstAddress, INET_NTOA(pEventData->RemoteAddress));
  698. usDstPort = ntohs(pEventData->RemotePort);
  699. }
  700. pszProtocol =
  701. NAT_PROTOCOL_TCP == pEventData->Protocol ?
  702. c_szTcp :
  703. c_szUdp;
  704. //
  705. // Write the event data to the buffer
  706. //
  707. cch =
  708. _snprintf(
  709. g_pCurrentBuffer->pChar,
  710. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  711. c_szConnectionFormat,
  712. stLocalTime.wYear,
  713. stLocalTime.wMonth,
  714. stLocalTime.wDay,
  715. stLocalTime.wHour,
  716. stLocalTime.wMinute,
  717. stLocalTime.wSecond,
  718. pszAction,
  719. pszProtocol,
  720. szSrcAddress,
  721. szDstAddress,
  722. usSrcPort,
  723. usDstPort
  724. );
  725. if (cch > 0)
  726. {
  727. //
  728. // Move the buffer pointer to the end of the data we just wrote.
  729. // If cch were negative, then there wasn't enough room to write
  730. // then entire entry; by not adjusting the pointer, we essentially
  731. // drop this event.
  732. //
  733. g_pCurrentBuffer->pChar += cch;
  734. }
  735. else
  736. {
  737. //
  738. // Record the dropped event
  739. //
  740. g_ulDroppedEventCount += 1;
  741. }
  742. //
  743. // If there is no current IO, flush the buffer
  744. //
  745. if (FALSE == g_fIOPending)
  746. {
  747. FwpFlushCurrentBuffer();
  748. }
  749. LeaveCriticalSection(&g_FwFileLock);
  750. } // FwpConnectionCreationCallback
  751. VOID
  752. WINAPI
  753. FwpConnectionDeletionCallback(
  754. PEVENT_TRACE pEvent
  755. )
  756. /*++
  757. Routine Description:
  758. This routine is called to process a connection deletion event.
  759. Arguments:
  760. pEvent - pointer to the event structure
  761. Return Value:
  762. none.
  763. --*/
  764. {
  765. PMSIPNAT_ConnectionDeletionEvent pEventData;
  766. FILETIME ftUtcTime;
  767. SYSTEMTIME stLocalTime;
  768. PCHAR pszProtocol;
  769. CHAR szSrcAddress[16];
  770. CHAR szDstAddress[16];
  771. USHORT usSrcPort;
  772. USHORT usDstPort;
  773. int cch;
  774. EnterCriticalSection(&g_FwFileLock);
  775. //
  776. // Get a buffer to write to.
  777. //
  778. if (NULL == g_pCurrentBuffer)
  779. {
  780. if (NULL == g_pReserveBuffer)
  781. {
  782. if (ERROR_SUCCESS != FwpAllocateBuffer(&g_pCurrentBuffer))
  783. {
  784. NhTrace(
  785. TRACE_FLAG_FWLOG,
  786. "FwpConnectionDeletionCallback: Unable to allocate buffer"
  787. );
  788. //
  789. // Record the dropped event
  790. //
  791. g_ulDroppedEventCount += 1;
  792. LeaveCriticalSection(&g_FwFileLock);
  793. return;
  794. }
  795. }
  796. else
  797. {
  798. g_pCurrentBuffer = g_pReserveBuffer;
  799. g_pReserveBuffer = NULL;
  800. }
  801. }
  802. ASSERT(NULL != g_pCurrentBuffer);
  803. //
  804. // Crack logging data
  805. //
  806. pEventData = (PMSIPNAT_ConnectionDeletionEvent) pEvent->MofData;
  807. ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart;
  808. ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart;
  809. FwpConvertUtcFiletimeToLocalSystemtime(&ftUtcTime, &stLocalTime);
  810. if (pEventData->InboundConnection)
  811. {
  812. lstrcpyA(szSrcAddress, INET_NTOA(pEventData->RemoteAddress));
  813. usSrcPort = ntohs(pEventData->RemotePort);
  814. lstrcpyA(szDstAddress, INET_NTOA(pEventData->LocalAddress));
  815. usDstPort = ntohs(pEventData->LocalPort);
  816. }
  817. else
  818. {
  819. lstrcpyA(szSrcAddress, INET_NTOA(pEventData->LocalAddress));
  820. usSrcPort = ntohs(pEventData->LocalPort);
  821. lstrcpyA(szDstAddress, INET_NTOA(pEventData->RemoteAddress));
  822. usDstPort = ntohs(pEventData->RemotePort);
  823. }
  824. pszProtocol =
  825. NAT_PROTOCOL_TCP == pEventData->Protocol ?
  826. c_szTcp :
  827. c_szUdp;
  828. //
  829. // Write the event data to the buffer
  830. //
  831. cch =
  832. _snprintf(
  833. g_pCurrentBuffer->pChar,
  834. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  835. c_szConnectionFormat,
  836. stLocalTime.wYear,
  837. stLocalTime.wMonth,
  838. stLocalTime.wDay,
  839. stLocalTime.wHour,
  840. stLocalTime.wMinute,
  841. stLocalTime.wSecond,
  842. "CLOSE",
  843. pszProtocol,
  844. szSrcAddress,
  845. szDstAddress,
  846. usSrcPort,
  847. usDstPort
  848. );
  849. if (cch > 0)
  850. {
  851. //
  852. // Move the buffer pointer to the end of the data we just wrote.
  853. // If cch were negative, then there wasn't enough room to write
  854. // then entire entry; by not adjusting the pointer, we essentially
  855. // drop this event.
  856. //
  857. g_pCurrentBuffer->pChar += cch;
  858. }
  859. else
  860. {
  861. //
  862. // Record the dropped event
  863. //
  864. g_ulDroppedEventCount += 1;
  865. }
  866. //
  867. // If there is no current IO, flush the buffer
  868. //
  869. if (FALSE == g_fIOPending)
  870. {
  871. FwpFlushCurrentBuffer();
  872. }
  873. LeaveCriticalSection(&g_FwFileLock);
  874. } // FwpConnectionDeletionCallback
  875. VOID
  876. FwpConvertUtcFiletimeToLocalSystemtime(
  877. FILETIME *pFiletime,
  878. SYSTEMTIME *pSystemtime
  879. )
  880. /*++
  881. Routine Description:
  882. Converts UTC time in a FILETIME struct to local time in
  883. a SYSTEMTIME struct
  884. Arguments:
  885. pFiletime - pointer to UTC filetime structure
  886. pSystemtime - pointer to systemtime structure that is to receive
  887. the local time
  888. Return Value:
  889. none.
  890. --*/
  891. {
  892. FILETIME ftLocalTime;
  893. ASSERT(NULL != pFiletime);
  894. ASSERT(NULL != pSystemtime);
  895. if (!FileTimeToLocalFileTime(pFiletime, &ftLocalTime)
  896. || !FileTimeToSystemTime(&ftLocalTime, pSystemtime))
  897. {
  898. //
  899. // Conversion failed -- use zero time
  900. //
  901. ZeroMemory( pSystemtime, sizeof(*pSystemtime));
  902. }
  903. } // FwpConvertUtcFiletimeToLocalSystemtime
  904. VOID
  905. CALLBACK
  906. FwpDroppedEventTimerRoutine(
  907. PVOID pvParameter,
  908. BOOLEAN fWaitTimeout
  909. )
  910. /*++
  911. Routine Description:
  912. Checks if there are any dropped events, and, if so, writes
  913. an event to the log.
  914. Arguments:
  915. pvParameter -- NULL if called by the timer. If called directly, a PULONG
  916. to the number of events dropped by WMI. In the later situation, this
  917. routine will not query the trace session for the number of dropped
  918. events.
  919. fWaitTimeout -- unused
  920. Return Value:
  921. none.
  922. --*/
  923. {
  924. ULONG ulKernelEvents = 0;
  925. PEVENT_TRACE_PROPERTIES pProperties;
  926. SYSTEMTIME stLocalTime;
  927. DWORD dwError;
  928. int cch;
  929. EnterCriticalSection(&g_FwFileLock);
  930. //
  931. // Check to see if we we're given the kernel mode drop count, as
  932. // would happen during shutdown
  933. //
  934. if (NULL != pvParameter)
  935. {
  936. ulKernelEvents = *((PULONG)pvParameter);
  937. }
  938. else
  939. {
  940. //
  941. // Query the trace session for number of events dropped
  942. // in kernel mode. If g_hSession is NULL, then we are shutting
  943. // down and should exit w/o logging -- this call is the result
  944. // of the timer firing after FwStopLogging has stopped the
  945. // trace session.
  946. //
  947. EnterCriticalSection(&g_FwLock);
  948. if (NULL != g_hSession)
  949. {
  950. pProperties = FwpAllocateTraceProperties();
  951. if (NULL != pProperties)
  952. {
  953. dwError =
  954. ControlTrace(
  955. g_hSession,
  956. NULL,
  957. pProperties,
  958. EVENT_TRACE_CONTROL_QUERY
  959. );
  960. if (ERROR_SUCCESS == dwError)
  961. {
  962. ulKernelEvents = pProperties->EventsLost;
  963. }
  964. else
  965. {
  966. NhTrace(
  967. TRACE_FLAG_FWLOG,
  968. "FwpDroppedEventTimerRoutine: ControlTrace = %d",
  969. dwError
  970. );
  971. }
  972. HeapFree(GetProcessHeap(), 0, pProperties);
  973. }
  974. }
  975. else
  976. {
  977. //
  978. // Timer callback after trace session stopped - exit
  979. //
  980. LeaveCriticalSection(&g_FwLock);
  981. LeaveCriticalSection(&g_FwFileLock);
  982. return;
  983. }
  984. LeaveCriticalSection(&g_FwLock);
  985. }
  986. //
  987. // Record the dropped events, if there are any
  988. //
  989. if (ulKernelEvents > g_ulKernelEventsLost
  990. || g_ulDroppedEventCount > 0)
  991. {
  992. //
  993. // Get a buffer to write to.
  994. //
  995. if (NULL == g_pCurrentBuffer)
  996. {
  997. if (NULL == g_pReserveBuffer)
  998. {
  999. if (ERROR_SUCCESS != FwpAllocateBuffer(&g_pCurrentBuffer))
  1000. {
  1001. NhTrace(
  1002. TRACE_FLAG_FWLOG,
  1003. "FwpDroppedEventTimerRoutine: Unable to allocate buffer"
  1004. );
  1005. LeaveCriticalSection(&g_FwFileLock);
  1006. return;
  1007. }
  1008. }
  1009. else
  1010. {
  1011. g_pCurrentBuffer = g_pReserveBuffer;
  1012. g_pReserveBuffer = NULL;
  1013. }
  1014. }
  1015. ASSERT(NULL != g_pCurrentBuffer);
  1016. //
  1017. // Get the current time
  1018. //
  1019. GetLocalTime(&stLocalTime);
  1020. //
  1021. // Write the dropped packet event to the buffer. The actual number of
  1022. // dropped events that we're logging is:
  1023. //
  1024. // ulKernelEvents - g_ulKernelEventsLost + g_ulDroppedEventCount
  1025. //
  1026. cch =
  1027. _snprintf(
  1028. g_pCurrentBuffer->pChar,
  1029. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  1030. c_szEventsLostFormat,
  1031. stLocalTime.wYear,
  1032. stLocalTime.wMonth,
  1033. stLocalTime.wDay,
  1034. stLocalTime.wHour,
  1035. stLocalTime.wMinute,
  1036. stLocalTime.wSecond,
  1037. ulKernelEvents - g_ulKernelEventsLost + g_ulDroppedEventCount
  1038. );
  1039. if (cch > 0)
  1040. {
  1041. //
  1042. // Move the buffer pointer to the end of the data we just wrote.
  1043. // If cch were negative, then there wasn't enough room to write
  1044. // then entire entry; by not adjusting the pointer, we essentially
  1045. // drop this event.
  1046. //
  1047. g_pCurrentBuffer->pChar += cch;
  1048. //
  1049. // Adjust the dropped event counter
  1050. //
  1051. g_ulKernelEventsLost = ulKernelEvents;
  1052. g_ulDroppedEventCount = 0;
  1053. }
  1054. else
  1055. {
  1056. //
  1057. // This doesn't count as a dropped event.
  1058. //
  1059. }
  1060. //
  1061. // If there is no current IO, flush the buffer
  1062. //
  1063. if (FALSE == g_fIOPending)
  1064. {
  1065. FwpFlushCurrentBuffer();
  1066. }
  1067. }
  1068. LeaveCriticalSection(&g_FwFileLock);
  1069. } // FwpDroppedEventTimerRoutine
  1070. DWORD
  1071. FwpFlushCurrentBuffer(
  1072. VOID
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. Writes the current buffer to disk.
  1077. Arguments:
  1078. none.
  1079. Return Value:
  1080. DWORD - Win32 error code
  1081. --*/
  1082. {
  1083. DWORD dwError;
  1084. DWORD dwBytesWritten;
  1085. DWORD dwBytesToWrite;
  1086. BOOL fResult;
  1087. EnterCriticalSection(&g_FwFileLock);
  1088. ASSERT(FALSE == g_fIOPending);
  1089. ASSERT(NULL != g_pCurrentBuffer);
  1090. ASSERT(0 == g_pCurrentBuffer->Overlapped.Internal);
  1091. ASSERT(0 == g_pCurrentBuffer->Overlapped.InternalHigh);
  1092. ASSERT(0 == g_pCurrentBuffer->Overlapped.Offset);
  1093. ASSERT(0 == g_pCurrentBuffer->Overlapped.OffsetHigh);
  1094. ASSERT(0 == g_pCurrentBuffer->Overlapped.hEvent);
  1095. g_pCurrentBuffer->Overlapped.Offset = g_dwFileOffset;
  1096. dwBytesToWrite = (DWORD)(g_pCurrentBuffer->pChar - g_pCurrentBuffer->Buffer);
  1097. fResult =
  1098. WriteFile(
  1099. g_hFile,
  1100. g_pCurrentBuffer->Buffer,
  1101. dwBytesToWrite,
  1102. &dwBytesWritten,
  1103. &g_pCurrentBuffer->Overlapped
  1104. );
  1105. dwError = GetLastError();
  1106. if (FALSE != fResult || ERROR_IO_PENDING == dwError)
  1107. {
  1108. //
  1109. // The write succeeded or is pending; our completion routine
  1110. // is therefore guaranteed to be called.
  1111. //
  1112. g_fIOPending = TRUE;
  1113. g_pCurrentBuffer = g_pReserveBuffer;
  1114. g_pReserveBuffer = NULL;
  1115. }
  1116. else
  1117. {
  1118. //
  1119. // Unexpected error. Reset the buffer for future use.
  1120. //
  1121. NhTrace(
  1122. TRACE_FLAG_FWLOG,
  1123. "FwpFlushCurrentBuffer: WriteFile = %d",
  1124. dwError
  1125. );
  1126. ZeroMemory(&g_pCurrentBuffer->Overlapped, sizeof(OVERLAPPED));
  1127. g_pCurrentBuffer->pChar = g_pCurrentBuffer->Buffer;
  1128. }
  1129. LeaveCriticalSection(&g_FwFileLock);
  1130. return dwError;
  1131. } // FwpFlushCurrentBuffer
  1132. DWORD
  1133. FwpOpenLogFile(
  1134. HANDLE *phFile,
  1135. BOOLEAN *pfNewFile
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Opens the file used for logging and associates it with the thread pool's
  1140. IO completion port.
  1141. Arguments:
  1142. phFile - receives the file handle for the opened log file.
  1143. pfNewFile - receives TRUE if a new file was created; false otherwise
  1144. Return Value:
  1145. DWORD - Win32 error code
  1146. --*/
  1147. {
  1148. DWORD dwError;
  1149. DWORD dwFileSize;
  1150. ASSERT(NULL != phFile);
  1151. ASSERT(NULL != pfNewFile);
  1152. EnterCriticalSection(&g_FwLock);
  1153. ASSERT(NULL != g_pSettings);
  1154. ASSERT(NULL != g_pSettings->pszwPath);
  1155. *pfNewFile = FALSE;
  1156. dwError = ERROR_SUCCESS;
  1157. *phFile =
  1158. CreateFile(
  1159. g_pSettings->pszwPath,
  1160. GENERIC_READ | GENERIC_WRITE,
  1161. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1162. NULL,
  1163. OPEN_ALWAYS,
  1164. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1165. NULL
  1166. );
  1167. if (INVALID_HANDLE_VALUE != *phFile)
  1168. {
  1169. //
  1170. // Check if this is a new or existing file
  1171. //
  1172. if (ERROR_ALREADY_EXISTS == GetLastError())
  1173. {
  1174. //
  1175. // Check to see if existing file size is > 95% of
  1176. // our max; if so, backup now and create new file
  1177. //
  1178. dwFileSize = GetFileSize(*phFile, NULL);
  1179. if ((DWORD)-1 == dwFileSize)
  1180. {
  1181. //
  1182. // Unable to get file size. This is quite unexpected...
  1183. //
  1184. dwError = GetLastError();
  1185. CloseHandle(*phFile);
  1186. *phFile = INVALID_HANDLE_VALUE;
  1187. NhTrace(
  1188. TRACE_FLAG_FWLOG,
  1189. "FwpOpenLogFile: GetFileSize = %d",
  1190. dwError
  1191. );
  1192. }
  1193. else if (dwFileSize > 0.95 * g_pSettings->ulMaxFileSize)
  1194. {
  1195. //
  1196. // Close the current file handle
  1197. //
  1198. CloseHandle(*phFile);
  1199. //
  1200. // Rename the current log file. This call will delete any
  1201. // previous backups. If this fails, we'll just overwrite
  1202. // the current log file.
  1203. //
  1204. FwpBackupFile(g_pSettings->pszwPath);
  1205. //
  1206. // Open again
  1207. //
  1208. *pfNewFile = TRUE;
  1209. *phFile =
  1210. CreateFile(
  1211. g_pSettings->pszwPath,
  1212. GENERIC_READ | GENERIC_WRITE,
  1213. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1214. NULL,
  1215. CREATE_ALWAYS,
  1216. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1217. NULL
  1218. );
  1219. if (INVALID_HANDLE_VALUE == *phFile)
  1220. {
  1221. dwError = GetLastError();
  1222. NhTrace(
  1223. TRACE_FLAG_FWLOG,
  1224. "FwpOpenLogFile: Error %d creating %S after backup",
  1225. dwError,
  1226. g_pSettings->pszwPath
  1227. );
  1228. }
  1229. }
  1230. }
  1231. else
  1232. {
  1233. *pfNewFile = TRUE;
  1234. }
  1235. }
  1236. else
  1237. {
  1238. dwError = GetLastError();
  1239. NhTrace(
  1240. TRACE_FLAG_FWLOG,
  1241. "FwpOpenLogFile: Error %d opening %S",
  1242. dwError,
  1243. g_pSettings->pszwPath
  1244. );
  1245. }
  1246. if (INVALID_HANDLE_VALUE != *phFile)
  1247. {
  1248. //
  1249. // Associate the file handle w/ the thread pool completion port
  1250. //
  1251. if (!BindIoCompletionCallback(*phFile, FwpCompletionRoutine, 0))
  1252. {
  1253. dwError = GetLastError();
  1254. CloseHandle(*phFile);
  1255. *phFile = INVALID_HANDLE_VALUE;
  1256. }
  1257. }
  1258. LeaveCriticalSection(&g_FwLock);
  1259. return dwError;
  1260. } // FwpOpenLogFile
  1261. VOID
  1262. WINAPI
  1263. FwpPacketDroppedCallback(
  1264. PEVENT_TRACE pEvent
  1265. )
  1266. /*++
  1267. Routine Description:
  1268. This routine is called to process a dropped packet event.
  1269. Arguments:
  1270. pEvent - pointer to the event structure
  1271. Return Value:
  1272. none.
  1273. --*/
  1274. {
  1275. PMSIPNAT_PacketDroppedEvent pEventData;
  1276. FILETIME ftUtcTime;
  1277. SYSTEMTIME stLocalTime;
  1278. CHAR szSrcAddress[16];
  1279. CHAR szDstAddress[16];
  1280. int cch;
  1281. EnterCriticalSection(&g_FwFileLock);
  1282. //
  1283. // Get a buffer to write to.
  1284. //
  1285. if (NULL == g_pCurrentBuffer)
  1286. {
  1287. if (NULL == g_pReserveBuffer)
  1288. {
  1289. if (ERROR_SUCCESS != FwpAllocateBuffer(&g_pCurrentBuffer))
  1290. {
  1291. NhTrace(
  1292. TRACE_FLAG_FWLOG,
  1293. "FwpPacketDroppedCallback: Unable to allocate buffer"
  1294. );
  1295. //
  1296. // Record the dropped event
  1297. //
  1298. g_ulDroppedEventCount += 1;
  1299. LeaveCriticalSection(&g_FwFileLock);
  1300. return;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. g_pCurrentBuffer = g_pReserveBuffer;
  1306. g_pReserveBuffer = NULL;
  1307. }
  1308. }
  1309. ASSERT(NULL != g_pCurrentBuffer);
  1310. //
  1311. // Crack logging data
  1312. //
  1313. pEventData = (PMSIPNAT_PacketDroppedEvent) pEvent->MofData;
  1314. ftUtcTime.dwLowDateTime = pEvent->Header.TimeStamp.LowPart;
  1315. ftUtcTime.dwHighDateTime = pEvent->Header.TimeStamp.HighPart;
  1316. FwpConvertUtcFiletimeToLocalSystemtime(&ftUtcTime, &stLocalTime);
  1317. lstrcpyA(szSrcAddress, INET_NTOA(pEventData->SourceAddress));
  1318. lstrcpyA(szDstAddress, INET_NTOA(pEventData->DestinationAddress));
  1319. //
  1320. // Write the event data to the buffer
  1321. //
  1322. if (NAT_PROTOCOL_TCP == pEventData->Protocol)
  1323. {
  1324. CHAR szBuffer[10];
  1325. UINT i = 0;
  1326. if (pEventData->ProtocolData4 & TCP_FLAG_SYN)
  1327. {
  1328. szBuffer[i++] = 'S';
  1329. }
  1330. if (pEventData->ProtocolData4 & TCP_FLAG_FIN)
  1331. {
  1332. szBuffer[i++] = 'F';
  1333. }
  1334. if (pEventData->ProtocolData4 & TCP_FLAG_ACK)
  1335. {
  1336. szBuffer[i++] = 'A';
  1337. }
  1338. if (pEventData->ProtocolData4 & TCP_FLAG_RST)
  1339. {
  1340. szBuffer[i++] = 'R';
  1341. }
  1342. if (pEventData->ProtocolData4 & TCP_FLAG_URG)
  1343. {
  1344. szBuffer[i++] = 'U';
  1345. }
  1346. if (pEventData->ProtocolData4 & TCP_FLAG_PSH)
  1347. {
  1348. szBuffer[i++] = 'P';
  1349. }
  1350. if (0 == i)
  1351. {
  1352. //
  1353. // No flags on this packet
  1354. //
  1355. szBuffer[i++] = '-';
  1356. }
  1357. szBuffer[i] = NULL;
  1358. cch =
  1359. _snprintf(
  1360. g_pCurrentBuffer->pChar,
  1361. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  1362. c_szTcpPacketFormat,
  1363. stLocalTime.wYear,
  1364. stLocalTime.wMonth,
  1365. stLocalTime.wDay,
  1366. stLocalTime.wHour,
  1367. stLocalTime.wMinute,
  1368. stLocalTime.wSecond,
  1369. szSrcAddress,
  1370. szDstAddress,
  1371. ntohs(pEventData->SourceIdentifier),
  1372. ntohs(pEventData->DestinationIdentifier),
  1373. pEventData->PacketSize,
  1374. szBuffer,
  1375. ntohl(pEventData->ProtocolData1),
  1376. ntohl(pEventData->ProtocolData2),
  1377. ntohs((USHORT)pEventData->ProtocolData3)
  1378. );
  1379. }
  1380. else if (NAT_PROTOCOL_UDP == pEventData->Protocol)
  1381. {
  1382. cch =
  1383. _snprintf(
  1384. g_pCurrentBuffer->pChar,
  1385. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  1386. c_szUdpPacketFormat,
  1387. stLocalTime.wYear,
  1388. stLocalTime.wMonth,
  1389. stLocalTime.wDay,
  1390. stLocalTime.wHour,
  1391. stLocalTime.wMinute,
  1392. stLocalTime.wSecond,
  1393. szSrcAddress,
  1394. szDstAddress,
  1395. ntohs(pEventData->SourceIdentifier),
  1396. ntohs(pEventData->DestinationIdentifier),
  1397. pEventData->PacketSize
  1398. );
  1399. }
  1400. else if (NAT_PROTOCOL_ICMP == pEventData->Protocol)
  1401. {
  1402. cch =
  1403. _snprintf(
  1404. g_pCurrentBuffer->pChar,
  1405. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  1406. c_szIcmpPacketFormat,
  1407. stLocalTime.wYear,
  1408. stLocalTime.wMonth,
  1409. stLocalTime.wDay,
  1410. stLocalTime.wHour,
  1411. stLocalTime.wMinute,
  1412. stLocalTime.wSecond,
  1413. szSrcAddress,
  1414. szDstAddress,
  1415. pEventData->PacketSize,
  1416. pEventData->ProtocolData1,
  1417. pEventData->ProtocolData2
  1418. );
  1419. }
  1420. else
  1421. {
  1422. cch =
  1423. _snprintf(
  1424. g_pCurrentBuffer->pChar,
  1425. FW_LOG_BUFFER_REMAINING(g_pCurrentBuffer),
  1426. c_szDroppedPacketFormat,
  1427. stLocalTime.wYear,
  1428. stLocalTime.wMonth,
  1429. stLocalTime.wDay,
  1430. stLocalTime.wHour,
  1431. stLocalTime.wMinute,
  1432. stLocalTime.wSecond,
  1433. pEventData->Protocol,
  1434. szSrcAddress,
  1435. szDstAddress,
  1436. pEventData->PacketSize
  1437. );
  1438. }
  1439. if (cch > 0)
  1440. {
  1441. //
  1442. // Move the buffer pointer to the end of the data we just wrote.
  1443. // If cch were negative, then there wasn't enough room to write
  1444. // then entire entry; by not adjusting the pointer, we essentially
  1445. // drop this event.
  1446. //
  1447. g_pCurrentBuffer->pChar += cch;
  1448. }
  1449. else
  1450. {
  1451. //
  1452. // Record the dropped event
  1453. //
  1454. g_ulDroppedEventCount += 1;
  1455. }
  1456. //
  1457. // If there is no current IO, flush the buffer
  1458. //
  1459. if (FALSE == g_fIOPending)
  1460. {
  1461. FwpFlushCurrentBuffer();
  1462. }
  1463. LeaveCriticalSection(&g_FwFileLock);
  1464. } // FwpPacketDroppedCallback
  1465. DWORD
  1466. FwpLaunchTraceSession(
  1467. HNET_FW_LOGGING_SETTINGS *pSettings,
  1468. TRACEHANDLE *phSession
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. This routine is called to start a trace session.
  1473. Arguments:
  1474. pSettings - pointer to an fw logging settings structure. Only
  1475. fLogDroppedPackets and fLogConnections are examined,
  1476. and at least one of the two must be true.
  1477. phSession - on success, receives the trace handle for the session
  1478. Return Value:
  1479. DWORD -- win32 error code
  1480. --*/
  1481. {
  1482. DWORD dwError;
  1483. PEVENT_TRACE_PROPERTIES pProperties = NULL;
  1484. PROFILE("FwpLaunchTraceSession");
  1485. ASSERT(NULL != pSettings);
  1486. ASSERT(pSettings->fLogDroppedPackets || pSettings->fLogConnections);
  1487. ASSERT(NULL != phSession);
  1488. do
  1489. {
  1490. //
  1491. // Allocate the tracing properties. We need to include space for
  1492. // the name of the logging session, even though we don't have
  1493. // to copy the string into the properties ourselves
  1494. //
  1495. pProperties = FwpAllocateTraceProperties();
  1496. if (NULL == pProperties)
  1497. {
  1498. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1499. break;
  1500. }
  1501. //
  1502. // Initialize the trace properties. When events are coming at a
  1503. // low rate (which is expected), there will be at most a 13 second
  1504. // latency for event delivery. During high event rate periods, our
  1505. // memory usage for trace buffering is capped at 60k.
  1506. //
  1507. pProperties->FlushTimer = 13;
  1508. pProperties->BufferSize = 4;
  1509. pProperties->MaximumBuffers = 15;
  1510. //
  1511. // Start the trace
  1512. //
  1513. dwError = StartTrace(phSession, c_wszLogSessionName, pProperties);
  1514. if (ERROR_SUCCESS != dwError)
  1515. {
  1516. NhTrace(
  1517. TRACE_FLAG_FWLOG,
  1518. "FwpLaunchTraceSession: StartTrace = %d",
  1519. dwError
  1520. );
  1521. *phSession = NULL;
  1522. break;
  1523. }
  1524. //
  1525. // Enable the appropriate events
  1526. //
  1527. if (pSettings->fLogDroppedPackets)
  1528. {
  1529. dwError = EnableTrace(
  1530. TRUE,
  1531. 0,
  1532. 0,
  1533. &c_PacketDroppedEventGuid,
  1534. *phSession
  1535. );
  1536. if (ERROR_SUCCESS != dwError)
  1537. {
  1538. NhTrace(
  1539. TRACE_FLAG_FWLOG,
  1540. "FwpLaunchTraceSession: EnableTrace (packets) = %d",
  1541. dwError
  1542. );
  1543. //
  1544. // Stop the trace
  1545. //
  1546. ControlTrace(
  1547. *phSession,
  1548. NULL,
  1549. pProperties,
  1550. EVENT_TRACE_CONTROL_STOP
  1551. );
  1552. *phSession = NULL;
  1553. break;
  1554. }
  1555. }
  1556. if (pSettings->fLogConnections)
  1557. {
  1558. dwError = EnableTrace(
  1559. TRUE,
  1560. 0,
  1561. 0,
  1562. &c_ConnectionCreationEventGuid,
  1563. *phSession
  1564. );
  1565. if (ERROR_SUCCESS != dwError)
  1566. {
  1567. NhTrace(
  1568. TRACE_FLAG_FWLOG,
  1569. "FwpLaunchTraceSession: EnableTrace (connections) = %d",
  1570. dwError
  1571. );
  1572. //
  1573. // Stop the trace
  1574. //
  1575. ControlTrace(
  1576. *phSession,
  1577. NULL,
  1578. pProperties,
  1579. EVENT_TRACE_CONTROL_STOP
  1580. );
  1581. *phSession = NULL;
  1582. break;
  1583. }
  1584. }
  1585. } while (FALSE);
  1586. if (NULL != pProperties)
  1587. {
  1588. HeapFree(GetProcessHeap(), 0, pProperties);
  1589. }
  1590. return dwError;
  1591. } // FwpLaunchTraceSession
  1592. HRESULT
  1593. FwpLoadSettings(
  1594. HNET_FW_LOGGING_SETTINGS **ppSettings
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. This routine is called to retrieve the firewall logging settings.
  1599. Arguments:
  1600. ppSettings - receives a pointer to the settings structure on success.
  1601. The caller is responsible for calling
  1602. HNetFreeFirewallLoggingSettings on this pointer.
  1603. Return Value:
  1604. standard HRESULT
  1605. --*/
  1606. {
  1607. HRESULT hr = S_OK;
  1608. IHNetCfgMgr *pCfgMgr;
  1609. IHNetFirewallSettings *pFwSettings;
  1610. PROFILE("FwpLoadSettings");
  1611. ASSERT(NULL != ppSettings);
  1612. hr = NhGetHNetCfgMgr(&pCfgMgr);
  1613. if (SUCCEEDED(hr))
  1614. {
  1615. hr = pCfgMgr->QueryInterface(
  1616. IID_PPV_ARG(IHNetFirewallSettings, &pFwSettings)
  1617. );
  1618. pCfgMgr->Release();
  1619. if (SUCCEEDED(hr))
  1620. {
  1621. hr = pFwSettings->GetFirewallLoggingSettings(ppSettings);
  1622. pFwSettings->Release();
  1623. if (SUCCEEDED(hr))
  1624. {
  1625. //
  1626. // Make sure that the minimum file size is at least 1024 bytes.
  1627. //
  1628. if ((*ppSettings)->ulMaxFileSize < 1024)
  1629. {
  1630. (*ppSettings)->ulMaxFileSize = 1024;
  1631. }
  1632. }
  1633. else
  1634. {
  1635. NhTrace(
  1636. TRACE_FLAG_FWLOG,
  1637. "FwpLoadSettings: GetFirewallLoggingSettings = 0x%08x",
  1638. hr
  1639. );
  1640. }
  1641. }
  1642. else
  1643. {
  1644. NhTrace(
  1645. TRACE_FLAG_FWLOG,
  1646. "FwpLoadSettings: QueryInterface = 0x%08x",
  1647. hr
  1648. );
  1649. }
  1650. }
  1651. else
  1652. {
  1653. NhTrace(
  1654. TRACE_FLAG_FWLOG,
  1655. "FwpLoadSettings: NhGetHNetCfgMgr = 0x%08x",
  1656. hr
  1657. );
  1658. }
  1659. return hr;
  1660. } // FwpLoadSettings
  1661. DWORD
  1662. WINAPI
  1663. FwpTraceProcessingThreadRoutine(
  1664. LPVOID pvParam
  1665. )
  1666. /*++
  1667. Routine Description:
  1668. This routine is the entrypoint for our trace processing thread. It
  1669. does the following:
  1670. 1) Creates the file that we are logging to
  1671. 2) Sets up the trace callback routines
  1672. 3) Calls ProcessTrace. This call blocks until the trace session is
  1673. finished (i.e,, FwStopLogging is called)
  1674. Arguments:
  1675. pvParam - unused
  1676. Return Value:
  1677. DWORD - Win32 error code
  1678. --*/
  1679. {
  1680. TRACEHANDLE hTraceSession;
  1681. EVENT_TRACE_LOGFILE LogFile;
  1682. BOOLEAN fNewFile;
  1683. DWORD dwError;
  1684. BOOL fSucceeded;
  1685. ULONG ulKernelEventsLostAtShutdown;
  1686. PROFILE("FwpTraceProcessingThreadRoutine");
  1687. EnterCriticalSection(&g_FwFileLock);
  1688. ASSERT(INVALID_HANDLE_VALUE == g_hFile);
  1689. ASSERT(0 == g_dwFileOffset);
  1690. ASSERT(NULL == g_pCurrentBuffer);
  1691. ASSERT(NULL == g_pReserveBuffer);
  1692. ASSERT(FALSE == g_fIOPending);
  1693. ASSERT(NULL == g_hIOEvent);
  1694. ASSERT(0 == g_ulDroppedEventCount);
  1695. ASSERT(NULL == g_hDroppedEventTimer);
  1696. ASSERT(0 == g_ulKernelEventsLost);
  1697. do
  1698. {
  1699. //
  1700. // Create/Open the logfile.
  1701. //
  1702. dwError = FwpOpenLogFile(&g_hFile, &fNewFile);
  1703. if (ERROR_SUCCESS != dwError) break;
  1704. //
  1705. // Allocate the initial working buffer
  1706. //
  1707. dwError = FwpAllocateBuffer(&g_pCurrentBuffer);
  1708. if (ERROR_SUCCESS != dwError)
  1709. {
  1710. LeaveCriticalSection(&g_FwFileLock);
  1711. NhTrace(
  1712. TRACE_FLAG_FWLOG,
  1713. "FwpTraceProcessingRoutine: Unable to allocate buffer"
  1714. );
  1715. break;
  1716. }
  1717. if (fNewFile)
  1718. {
  1719. //
  1720. // Write the log header
  1721. //
  1722. g_dwFileOffset = 0;
  1723. dwError = FwpWriteLogHeaderToBuffer(g_pCurrentBuffer);
  1724. if (ERROR_SUCCESS == dwError)
  1725. {
  1726. FwpFlushCurrentBuffer();
  1727. }
  1728. else
  1729. {
  1730. //
  1731. // Even though we failed in writing the header, we'll still
  1732. // try to log as much as possible
  1733. //
  1734. NhTrace(
  1735. TRACE_FLAG_FWLOG,
  1736. "FwpTraceProcessinRoutine: FwpWriteLogHeaderToBuffer = %d",
  1737. dwError
  1738. );
  1739. }
  1740. }
  1741. else
  1742. {
  1743. //
  1744. // Find the end-of-file position
  1745. //
  1746. g_dwFileOffset = GetFileSize(g_hFile, NULL);
  1747. if ((DWORD)-1 == g_dwFileOffset)
  1748. {
  1749. NhTrace(
  1750. TRACE_FLAG_FWLOG,
  1751. "FwpTraceProcessingRoutine: GetFileSize = %d",
  1752. GetLastError()
  1753. );
  1754. LeaveCriticalSection(&g_FwFileLock);
  1755. break;
  1756. }
  1757. }
  1758. //
  1759. // Launch our dropped event timer. When this timer fires,
  1760. // the callback routine will check if any events have
  1761. // been dropped (both in kernel mode and user mode),
  1762. // and, if so, log that fact.
  1763. //
  1764. fSucceeded =
  1765. CreateTimerQueueTimer(
  1766. &g_hDroppedEventTimer,
  1767. NULL,
  1768. FwpDroppedEventTimerRoutine,
  1769. NULL,
  1770. 0,
  1771. 1000 * 60 * 5, // 5 minutes
  1772. 0
  1773. );
  1774. if (FALSE == fSucceeded)
  1775. {
  1776. //
  1777. // Even though we weren't able to create the timer,
  1778. // we'll still try to log as much as possible.
  1779. //
  1780. NhTrace(
  1781. TRACE_FLAG_FWLOG,
  1782. "FwpTraceProcessinRoutine: CreateTimerQueueTimer = %d",
  1783. GetLastError()
  1784. );
  1785. }
  1786. LeaveCriticalSection(&g_FwFileLock);
  1787. //
  1788. // Register our callback routines. We will attempt to continue
  1789. // even if errors occur here.
  1790. //
  1791. dwError = SetTraceCallback(
  1792. &c_PacketDroppedEventGuid,
  1793. FwpPacketDroppedCallback
  1794. );
  1795. if (ERROR_SUCCESS != dwError)
  1796. {
  1797. NhTrace(
  1798. TRACE_FLAG_FWLOG,
  1799. "FwpTraceProcessingThreadRoutine: SetTraceCallback (packets dropped) = %d",
  1800. dwError
  1801. );
  1802. }
  1803. dwError = SetTraceCallback(
  1804. &c_ConnectionCreationEventGuid,
  1805. FwpConnectionCreationCallback
  1806. );
  1807. if (ERROR_SUCCESS != dwError)
  1808. {
  1809. NhTrace(
  1810. TRACE_FLAG_FWLOG,
  1811. "FwpTraceProcessingThreadRoutine: SetTraceCallback (connection creation) = %d",
  1812. dwError
  1813. );
  1814. }
  1815. dwError = SetTraceCallback(
  1816. &c_ConnectionDeletionEventGuid,
  1817. FwpConnectionDeletionCallback
  1818. );
  1819. if (ERROR_SUCCESS != dwError)
  1820. {
  1821. NhTrace(
  1822. TRACE_FLAG_FWLOG,
  1823. "FwpTraceProcessingThreadRoutine: SetTraceCallback (connection deletion) = %d",
  1824. dwError
  1825. );
  1826. }
  1827. //
  1828. // Open the trace stream
  1829. //
  1830. ZeroMemory(&LogFile, sizeof(LogFile));
  1831. LogFile.LoggerName = c_wszLogSessionName;
  1832. LogFile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
  1833. hTraceSession = OpenTrace(&LogFile);
  1834. if ((TRACEHANDLE)INVALID_HANDLE_VALUE == hTraceSession)
  1835. {
  1836. NhTrace(
  1837. TRACE_FLAG_FWLOG,
  1838. "FwpTraceProcessingThreadRoutine: OpenTrace = %d",
  1839. GetLastError()
  1840. );
  1841. break;
  1842. }
  1843. //
  1844. // Start processing the trace stream. This call will block until
  1845. // the trace session is closed (i.e., FwStopLogging is called).
  1846. //
  1847. dwError = ProcessTrace(&hTraceSession, 1, NULL, NULL);
  1848. NhTrace(
  1849. TRACE_FLAG_FWLOG,
  1850. "FwpTraceProcessingThreadRoutine: ProcessTrace = %d",
  1851. dwError
  1852. );
  1853. dwError = CloseTrace(hTraceSession);
  1854. if (ERROR_SUCCESS != dwError)
  1855. {
  1856. NhTrace(
  1857. TRACE_FLAG_FWLOG,
  1858. "FwpTraceProcessingThreadRoutine: CloseTrace = %d",
  1859. dwError
  1860. );
  1861. }
  1862. } while (FALSE);
  1863. //
  1864. // Make sure that all dropped events are properly logged
  1865. //
  1866. EnterCriticalSection(&g_FwLock);
  1867. ulKernelEventsLostAtShutdown = g_ulKernelEventsLostAtShutdown;
  1868. LeaveCriticalSection(&g_FwLock);
  1869. //
  1870. // Since we're shutting down, we pass in the number of lost kernel
  1871. // events. This will prevent the timer routine from attempting to
  1872. // query the stopped trace session
  1873. //
  1874. FwpDroppedEventTimerRoutine((PVOID)&ulKernelEventsLostAtShutdown, FALSE);
  1875. //
  1876. // Cleanup tracing thread resources
  1877. //
  1878. FwpCleanupTraceThreadResources();
  1879. return dwError;
  1880. } // FwpTraceProcessingThreadRoutine
  1881. DWORD
  1882. FwpWriteLogHeaderToBuffer(
  1883. PFW_LOG_BUFFER pBuffer
  1884. )
  1885. /*++
  1886. Routine Description:
  1887. Writes the log file header to the passed in buffer
  1888. Arguments:
  1889. pBuffer - the buffer to write the header to.
  1890. Return Value:
  1891. DWORD - Win32 error
  1892. --*/
  1893. {
  1894. DWORD dwError = ERROR_SUCCESS;
  1895. DWORD dwHeaderSize;
  1896. ASSERT(NULL != pBuffer);
  1897. dwHeaderSize = lstrlenA(c_szLogFileHeader);
  1898. if (FW_LOG_BUFFER_REMAINING(pBuffer) < dwHeaderSize)
  1899. {
  1900. dwError = ERROR_INSUFFICIENT_BUFFER;
  1901. }
  1902. else
  1903. {
  1904. RtlCopyMemory(pBuffer->pChar, c_szLogFileHeader, dwHeaderSize);
  1905. pBuffer->pChar += dwHeaderSize;
  1906. }
  1907. return dwError;
  1908. } // FwpWriteLogHeaderToBuffer
  1909. VOID
  1910. FwStartLogging(
  1911. VOID
  1912. )
  1913. /*++
  1914. Routine Description:
  1915. This routine is called to start logging operations (depending on
  1916. the current logging settings). It is safe to call this routine when
  1917. logging has already started.
  1918. Arguments:
  1919. none.
  1920. Return Value:
  1921. none.
  1922. --*/
  1923. {
  1924. HRESULT hr = S_OK;
  1925. DWORD dwError;
  1926. PROFILE("FwStartLogging");
  1927. ASSERT(FwInitialized == FwpModuleState);
  1928. EnterCriticalSection(&g_FwLock);
  1929. g_fTracingActive = TRUE;
  1930. if (NULL == g_pSettings)
  1931. {
  1932. hr = FwpLoadSettings(&g_pSettings);
  1933. }
  1934. if (SUCCEEDED(hr))
  1935. {
  1936. if ((g_pSettings->fLogDroppedPackets || g_pSettings->fLogConnections)
  1937. && NULL == g_hSession)
  1938. {
  1939. ASSERT(NULL == g_hThread);
  1940. //
  1941. // Start the tracing session
  1942. //
  1943. dwError = FwpLaunchTraceSession(g_pSettings, &g_hSession);
  1944. if (ERROR_SUCCESS == dwError)
  1945. {
  1946. //
  1947. // Launch the trace processing thread. We're not using
  1948. // any thread-specific crt routines (e.g., strtok) so
  1949. // there's no need to call __beginthreadex
  1950. //
  1951. g_hThread = CreateThread(
  1952. NULL, // SD
  1953. 0, // stack size
  1954. FwpTraceProcessingThreadRoutine,
  1955. NULL, // thread argument
  1956. 0, // flags
  1957. NULL // thread ID
  1958. );
  1959. if (NULL == g_hThread)
  1960. {
  1961. NhTrace(
  1962. TRACE_FLAG_FWLOG,
  1963. "FwStartLogging: CreateThread = %d",
  1964. GetLastError()
  1965. );
  1966. LeaveCriticalSection(&g_FwLock);
  1967. FwStopLogging();
  1968. return;
  1969. }
  1970. }
  1971. }
  1972. }
  1973. LeaveCriticalSection(&g_FwLock);
  1974. } // FwStartLogging
  1975. VOID
  1976. FwStopLogging(
  1977. VOID
  1978. )
  1979. /*++
  1980. Routine Description:
  1981. This routine is called to stop logging operations. It is safe to call
  1982. this routine when logging is stopped.
  1983. Arguments:
  1984. none.
  1985. Return Value:
  1986. none.
  1987. Environment:
  1988. The caller must not hold g_FwFileLock or g_FwLock.
  1989. --*/
  1990. {
  1991. DWORD dwError;
  1992. PEVENT_TRACE_PROPERTIES pProperties;
  1993. PROFILE("FwStopLogging");
  1994. ASSERT(FwInitialized == FwpModuleState);
  1995. EnterCriticalSection(&g_FwLock);
  1996. g_fTracingActive = FALSE;
  1997. //
  1998. // Stop the trace session if it is currently active
  1999. //
  2000. if (NULL != g_hSession)
  2001. {
  2002. pProperties = FwpAllocateTraceProperties();
  2003. if (NULL != pProperties)
  2004. {
  2005. dwError = ControlTrace(
  2006. g_hSession,
  2007. 0,
  2008. pProperties,
  2009. EVENT_TRACE_CONTROL_STOP
  2010. );
  2011. if (ERROR_SUCCESS == dwError)
  2012. {
  2013. g_hSession = NULL;
  2014. g_ulKernelEventsLostAtShutdown = pProperties->EventsLost;
  2015. if (NULL != g_hThread)
  2016. {
  2017. HANDLE hThread;
  2018. //
  2019. // Wait for thread to exit
  2020. //
  2021. hThread = g_hThread;
  2022. LeaveCriticalSection(&g_FwLock);
  2023. dwError = WaitForSingleObject(hThread, 45 * 1000);
  2024. if (WAIT_TIMEOUT == dwError)
  2025. {
  2026. NhTrace(
  2027. TRACE_FLAG_FWLOG,
  2028. "FwStopLogging: Timeout waiting for thread"
  2029. );
  2030. //
  2031. // The logging thread still hasn't exited; kill
  2032. // it hard and make sure that all resources are
  2033. // properly freed...
  2034. //
  2035. EnterCriticalSection(&g_FwFileLock);
  2036. EnterCriticalSection(&g_FwLock);
  2037. //
  2038. // TerminateThread is a very dangerous call. However,
  2039. // since we control the thread we're about to kill,
  2040. // we can guarantee that this will be safe. In
  2041. // particular, since we hold both critical sections,
  2042. // there is no danger of them being orphaned, or of
  2043. // any of our global data being in an inconsistent
  2044. // state.
  2045. //
  2046. if (!TerminateThread(g_hThread, ERROR_TIMEOUT))
  2047. {
  2048. NhTrace(
  2049. TRACE_FLAG_FWLOG,
  2050. "FwStopLogging: TerminateThread = %d",
  2051. GetLastError()
  2052. );
  2053. }
  2054. LeaveCriticalSection(&g_FwLock);
  2055. LeaveCriticalSection(&g_FwFileLock);
  2056. //
  2057. // Cleanup thread resources. It is safe to call this
  2058. // routine multiple times.
  2059. //
  2060. FwpCleanupTraceThreadResources();
  2061. }
  2062. else if (WAIT_OBJECT_0 != dwError)
  2063. {
  2064. NhTrace(
  2065. TRACE_FLAG_FWLOG,
  2066. "FwStopLogging: wait for thread = %d/%d",
  2067. dwError,
  2068. GetLastError()
  2069. );
  2070. }
  2071. EnterCriticalSection(&g_FwLock);
  2072. if (NULL != g_hThread)
  2073. {
  2074. CloseHandle(g_hThread);
  2075. }
  2076. g_hThread = NULL;
  2077. }
  2078. NhTrace(
  2079. TRACE_FLAG_FWLOG,
  2080. "FwStopLogging: Stopped w/ %d events and %d buffers lost",
  2081. pProperties->EventsLost,
  2082. pProperties->RealTimeBuffersLost
  2083. );
  2084. g_ulKernelEventsLostAtShutdown = 0;
  2085. }
  2086. else
  2087. {
  2088. NhTrace(
  2089. TRACE_FLAG_FWLOG,
  2090. "FwStopLogging: ControlTrace = %d",
  2091. dwError
  2092. );
  2093. //
  2094. // Since the trace session has not yet been stopped,
  2095. // we leave g_hSession unchanged.
  2096. //
  2097. }
  2098. HeapFree(GetProcessHeap(), 0, pProperties);
  2099. }
  2100. }
  2101. LeaveCriticalSection(&g_FwLock);
  2102. } // FwStopLogging
  2103. VOID
  2104. FwUpdateLoggingSettings(
  2105. VOID
  2106. )
  2107. /*++
  2108. Routine Description:
  2109. This routine is called to notify the logging subsystem that the
  2110. logging settings have changed.
  2111. Arguments:
  2112. none.
  2113. Return Value:
  2114. none.
  2115. --*/
  2116. {
  2117. HRESULT hr;
  2118. HNET_FW_LOGGING_SETTINGS *pSettings;
  2119. DWORD dwError;
  2120. PROFILE("FwUpdateLoggingSettings");
  2121. ASSERT(FwInitialized == FwpModuleState);
  2122. EnterCriticalSection(&g_FwLock);
  2123. do
  2124. {
  2125. if (FALSE == g_fTracingActive)
  2126. {
  2127. //
  2128. // Since tracing is not currently active, there is no
  2129. // need to retrieve the current settings. Furthermore, free
  2130. // any stored settings that we might have so that stale
  2131. // settings are not used.
  2132. //
  2133. if (g_pSettings)
  2134. {
  2135. HNetFreeFirewallLoggingSettings(g_pSettings);
  2136. g_pSettings = NULL;
  2137. }
  2138. break;
  2139. }
  2140. //
  2141. // Obtain the current settings
  2142. //
  2143. hr = FwpLoadSettings(&pSettings);
  2144. if (FAILED(hr))
  2145. {
  2146. break;
  2147. }
  2148. if (NULL == g_pSettings)
  2149. {
  2150. //
  2151. // Since we don't have any cached settings (previous failure
  2152. // in FwpLoadSettings?) simply store what we just retrieved
  2153. // and call FwStartLogging.
  2154. //
  2155. g_pSettings = pSettings;
  2156. FwStartLogging();
  2157. break;
  2158. }
  2159. if (NULL == g_hSession)
  2160. {
  2161. //
  2162. // There is no log session at the moment. Free the old settings,
  2163. // store the new ones, and call FwStartLogging.
  2164. //
  2165. ASSERT(NULL == g_hThread);
  2166. HNetFreeFirewallLoggingSettings(g_pSettings);
  2167. g_pSettings = pSettings;
  2168. FwStartLogging();
  2169. break;
  2170. }
  2171. //
  2172. // Compare the settings to see what, if anything, has changed
  2173. //
  2174. if (wcscmp(g_pSettings->pszwPath, pSettings->pszwPath))
  2175. {
  2176. //
  2177. // Our log file has changed -- we need to stop and restart
  2178. // everything so that logging is properly moved to the
  2179. // new file.
  2180. //
  2181. LeaveCriticalSection(&g_FwLock);
  2182. FwStopLogging();
  2183. EnterCriticalSection(&g_FwLock);
  2184. if (NULL != g_pSettings)
  2185. {
  2186. HNetFreeFirewallLoggingSettings(g_pSettings);
  2187. }
  2188. g_pSettings = pSettings;
  2189. FwStartLogging();
  2190. break;
  2191. }
  2192. //
  2193. // Only possible changes are to enabled events
  2194. //
  2195. if (!!g_pSettings->fLogDroppedPackets
  2196. != !!pSettings->fLogDroppedPackets)
  2197. {
  2198. dwError = EnableTrace(
  2199. pSettings->fLogDroppedPackets,
  2200. 0,
  2201. 0,
  2202. &c_PacketDroppedEventGuid,
  2203. g_hSession
  2204. );
  2205. if (ERROR_SUCCESS != dwError)
  2206. {
  2207. NhTrace(
  2208. TRACE_FLAG_FWLOG,
  2209. "FwUpdateLoggingSettings: EnableTrace (packets) = %d",
  2210. dwError
  2211. );
  2212. }
  2213. }
  2214. if (!!g_pSettings->fLogConnections
  2215. != !!pSettings->fLogConnections)
  2216. {
  2217. dwError = EnableTrace(
  2218. pSettings->fLogConnections,
  2219. 0,
  2220. 0,
  2221. &c_ConnectionCreationEventGuid,
  2222. g_hSession
  2223. );
  2224. if (ERROR_SUCCESS != dwError)
  2225. {
  2226. NhTrace(
  2227. TRACE_FLAG_FWLOG,
  2228. "FwUpdateLoggingSettings: EnableTrace (connections) = %d",
  2229. dwError
  2230. );
  2231. }
  2232. }
  2233. //
  2234. // Free old settings and store new
  2235. //
  2236. HNetFreeFirewallLoggingSettings(g_pSettings);
  2237. g_pSettings = pSettings;
  2238. } while (FALSE);
  2239. LeaveCriticalSection(&g_FwLock);
  2240. } // FwUpdateLoggingSettings