ldap: assume GSS-SPNEGO as default
[wireshark-sm.git] / extcap / etl.c
blob78f2bf2266e6fc914c98585284a4b9b412822fe9
1 /* etl.c
3 * Copyright 2020, Odysseus Yang
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * Reads an ETL file and writes out a pcap file with LINKTYPE_ETW.
15 * https://docs.microsoft.com/en-us/windows/win32/etw/event-tracing-portal
18 #include "config.h"
19 #define WS_LOG_DOMAIN "etwdump"
21 #include "etl.h"
22 #include "wsutil/ws_getopt.h"
23 #include "wsutil/strtoi.h"
24 #include "etw_message.h"
26 #include <rpc.h>
27 #include <winevt.h>
29 #define MAX_PACKET_SIZE 0xFFFF
30 #define G_NSEC_PER_SEC 1000000000
31 #define ADD_OFFSET_TO_POINTER(buffer, offset) (((PBYTE)buffer) + offset)
32 #define ROUND_UP_COUNT(Count,Pow2) \
33 ( ((Count)+(Pow2)-1) & (~(((int)(Pow2))-1)) )
35 extern int g_include_undecidable_event;
37 //Microsoft-Windows-Wmbclass-Opn
38 const GUID mbb_provider = { 0xA42FE227, 0xA7BF, 0x4483, {0xA5, 0x02, 0x6B, 0xCD, 0xA4, 0x28, 0xCD, 0x96} };
39 // Microsoft-Windows-NDIS-PacketCapture
40 const GUID ndis_capture_provider = { 0x2ed6006e, 0x4729, 0x4609, 0xb4, 0x23, 0x3e, 0xe7, 0xbc, 0xd6, 0x78, 0xef };
42 EXTERN_C const GUID DECLSPEC_SELECTANY EventTraceGuid = { 0x68fdd900, 0x4a3e, 0x11d1, {0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3} };
43 EXTERN_C const GUID DECLSPEC_SELECTANY ImageIdGuid = { 0xb3e675d7, 0x2554, 0x4f18, { 0x83, 0xb, 0x27, 0x62, 0x73, 0x25, 0x60, 0xde } };
44 EXTERN_C const GUID DECLSPEC_SELECTANY SystemConfigExGuid = { 0x9b79ee91, 0xb5fd, 0x41c0, { 0xa2, 0x43, 0x42, 0x48, 0xe2, 0x66, 0xe9, 0xd0 } };
45 EXTERN_C const GUID DECLSPEC_SELECTANY EventMetadataGuid = { 0xbbccf6c1, 0x6cd1, 0x48c4, {0x80, 0xff, 0x83, 0x94, 0x82, 0xe3, 0x76, 0x71 } };
46 EXTERN_C const GUID DECLSPEC_SELECTANY ZeroGuid = { 0 };
48 typedef struct _WTAP_ETL_RECORD {
49 EVENT_HEADER EventHeader; // Event header
50 ETW_BUFFER_CONTEXT BufferContext; // Buffer context
51 ULONG UserDataLength;
52 ULONG MessageLength;
53 ULONG ProviderLength;
54 } WTAP_ETL_RECORD;
56 enum {
57 OPT_PROVIDER,
58 OPT_KEYWORD,
59 OPT_LEVEL,
62 static struct ws_option longopts[] = {
63 { "p", ws_required_argument, NULL, OPT_PROVIDER},
64 { "k", ws_required_argument, NULL, OPT_KEYWORD},
65 { "l", ws_required_argument, NULL, OPT_LEVEL},
66 { 0, 0, 0, 0 }
69 typedef struct _PROVIDER_FILTER {
70 GUID ProviderId;
71 ULONG64 Keyword;
72 UCHAR Level;
73 } PROVIDER_FILTER;
75 char g_err_info[FILENAME_MAX] = { 0 };
76 int g_err = ERROR_SUCCESS;
77 static wtap_dumper* g_pdh = NULL;
78 extern ULONGLONG g_num_events;
79 static PROVIDER_FILTER g_provider_filters[32] = { 0 };
80 static BOOL g_is_live_session = false;
82 static void WINAPI event_callback(PEVENT_RECORD ev);
83 void etw_dump_write_opn_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp);
84 void etw_dump_write_ndiscap_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp);
85 void etw_dump_write_general_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp);
86 void etw_dump_write_event_head_only(PEVENT_RECORD ev, ULARGE_INTEGER timestamp);
87 void wtap_etl_rec_dump(char* etl_record, ULONG total_packet_length, ULONG original_packet_length, unsigned int interface_id, BOOLEAN is_inbound, ULARGE_INTEGER timestamp, int pkt_encap, char* comment, unsigned short comment_length);
88 wtap_dumper* etw_dump_open(const char* pcapng_filename, int* err, char** err_info);
90 DWORD GetPropertyValue(WCHAR* ProviderId, EVT_PUBLISHER_METADATA_PROPERTY_ID PropertyId, PEVT_VARIANT* Value)
92 BOOL bRet;
93 DWORD err = ERROR_SUCCESS;
94 PEVT_VARIANT value = NULL;
95 DWORD bufSize = 0;
96 DWORD bufUsedOrReqd = 0;
98 EVT_HANDLE pubHandle = EvtOpenPublisherMetadata(NULL, ProviderId, NULL, GetThreadLocale(), 0);
99 if (pubHandle == NULL)
101 return GetLastError();
105 * Get required size for property
107 bRet = EvtGetPublisherMetadataProperty(
108 pubHandle,
109 PropertyId,
111 bufSize,
112 value,
113 &bufUsedOrReqd);
115 if (!bRet && ((err = GetLastError()) != ERROR_INSUFFICIENT_BUFFER))
117 return err;
119 else if (bRet) /* Didn't expect this to succeed */
121 return ERROR_INVALID_STATE;
124 value = (PEVT_VARIANT)g_malloc(bufUsedOrReqd);
125 if (!value)
127 return ERROR_INSUFFICIENT_BUFFER;
129 bufSize = bufUsedOrReqd;
132 * Get the property value
134 bRet = EvtGetPublisherMetadataProperty(
135 pubHandle,
136 PropertyId,
138 bufSize,
139 value,
140 &bufUsedOrReqd);
141 if (!bRet)
143 g_free(value);
144 return GetLastError();
147 *Value = value;
148 return ERROR_SUCCESS;
151 wtap_open_return_val etw_dump(const char* etl_filename, const char* pcapng_filename, const char* params, int* err, char** err_info)
153 EVENT_TRACE_LOGFILE log_file = { 0 };
154 WCHAR w_etl_filename[FILENAME_MAX] = { 0 };
155 wtap_open_return_val returnVal = WTAP_OPEN_MINE;
157 SUPER_EVENT_TRACE_PROPERTIES super_trace_properties = { 0 };
158 super_trace_properties.prop.Wnode.BufferSize = sizeof(SUPER_EVENT_TRACE_PROPERTIES);
159 super_trace_properties.prop.Wnode.ClientContext = 2;
160 super_trace_properties.prop.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
161 super_trace_properties.prop.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
162 super_trace_properties.prop.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
163 TRACEHANDLE traceControllerHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
164 TRACEHANDLE trace_handle = INVALID_PROCESSTRACE_HANDLE;
166 SecureZeroMemory(g_provider_filters, sizeof(g_provider_filters));
167 SecureZeroMemory(g_err_info, FILENAME_MAX);
168 g_err = ERROR_SUCCESS;
169 g_num_events = 0;
170 g_is_live_session = false;
172 if (params)
174 int opt_result = 0;
175 int option_idx = 0;
176 int provider_idx = 0;
177 char** params_array = NULL;
178 int params_array_num = 0;
179 WCHAR provider_id[FILENAME_MAX] = { 0 };
180 ULONG convert_level = 0;
182 params_array = g_strsplit(params, " ", -1);
183 while (params_array[params_array_num])
185 params_array_num++;
188 ws_optind = 0;
189 while ((opt_result = ws_getopt_long(params_array_num, params_array, ":", longopts, &option_idx)) != -1) {
190 switch (opt_result) {
191 case OPT_PROVIDER:
192 mbstowcs(provider_id, ws_optarg, FILENAME_MAX);
193 if (UuidFromString(provider_id, &g_provider_filters[provider_idx].ProviderId) == RPC_S_INVALID_STRING_UUID)
195 PEVT_VARIANT value = NULL;
197 *err = GetPropertyValue(
198 provider_id,
199 EvtPublisherMetadataPublisherGuid,
200 &value);
203 * Copy returned GUID locally
205 if (*err == ERROR_SUCCESS)
207 if (value->Type == EvtVarTypeGuid && value->GuidVal)
209 g_provider_filters[provider_idx].ProviderId = *(value->GuidVal);
211 else
213 *err = ERROR_INVALID_DATA;
216 else
218 *err_info = ws_strdup_printf("Cannot convert provider %s to a GUID, err is 0x%x", ws_optarg, *err);
219 return WTAP_OPEN_ERROR;
222 g_free(value);
225 if (IsEqualGUID(&g_provider_filters[0].ProviderId, &ZeroGuid))
227 *err = ERROR_INVALID_PARAMETER;
228 *err_info = ws_strdup_printf("Provider %s is zero, err is 0x%x", ws_optarg, *err);
229 return WTAP_OPEN_ERROR;
231 provider_idx++;
232 break;
233 case OPT_KEYWORD:
234 if (provider_idx == 0)
236 *err = ERROR_INVALID_PARAMETER;
237 *err_info = ws_strdup_printf("-k parameter must follow -p, err is 0x%x", *err);
238 return WTAP_OPEN_ERROR;
241 g_provider_filters[provider_idx - 1].Keyword = _strtoui64(ws_optarg, NULL, 0);
242 if (!g_provider_filters[provider_idx - 1].Keyword)
244 *err = ERROR_INVALID_PARAMETER;
245 *err_info = ws_strdup_printf("Keyword %s cannot be converted, err is 0x%x", ws_optarg, *err);
246 return WTAP_OPEN_ERROR;
248 break;
249 case OPT_LEVEL:
250 if (provider_idx == 0)
252 *err = ERROR_INVALID_PARAMETER;
253 *err_info = ws_strdup_printf("-l parameter must follow -p, err is 0x%x", *err);
254 return WTAP_OPEN_ERROR;
257 convert_level = strtoul(ws_optarg, NULL, 0);
258 if (convert_level > UCHAR_MAX)
260 *err = ERROR_INVALID_PARAMETER;
261 *err_info = ws_strdup_printf("Level %s is bigger than 0xff, err is 0x%x", ws_optarg, *err);
262 return WTAP_OPEN_ERROR;
264 if (!convert_level)
266 *err = ERROR_INVALID_PARAMETER;
267 *err_info = ws_strdup_printf("Level %s cannot be converted, err is 0x%x", ws_optarg, *err);
268 return WTAP_OPEN_ERROR;
271 g_provider_filters[provider_idx - 1].Level = (UCHAR)convert_level;
272 break;
275 g_strfreev(params_array);
278 /* do/while(false) is used to jump out of loop so no complex nested if/else is needed */
281 /* Read ETW from an etl file */
282 if (etl_filename)
284 mbstowcs(w_etl_filename, etl_filename, FILENAME_MAX);
286 log_file.LogFileName = w_etl_filename;
287 log_file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
288 log_file.EventRecordCallback = event_callback;
289 log_file.Context = NULL;
291 else
294 * Try the best to stop the leftover session since extcap has no way to cleanup when stop capturing. See issue
295 * https://gitlab.com/wireshark/wireshark/-/issues/17131
297 ControlTrace((TRACEHANDLE)NULL, LOGGER_NAME, &super_trace_properties.prop, EVENT_TRACE_CONTROL_STOP);
299 g_is_live_session = true;
301 log_file.LoggerName = LOGGER_NAME;
302 log_file.LogFileName = NULL;
303 log_file.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
304 log_file.EventRecordCallback = event_callback;
305 log_file.BufferCallback = NULL;
306 log_file.Context = NULL;
308 *err = StartTrace(
309 &traceControllerHandle,
310 log_file.LoggerName,
311 &super_trace_properties.prop);
312 if (*err != ERROR_SUCCESS)
314 *err_info = ws_strdup_printf("StartTrace failed with 0x%x", *err);
315 returnVal = WTAP_OPEN_ERROR;
316 break;
319 for (int i = 0; i < ARRAYSIZE(g_provider_filters); i++)
321 if (IsEqualGUID(&g_provider_filters[i].ProviderId, &ZeroGuid))
323 break;
325 *err = EnableTraceEx(
326 &g_provider_filters[i].ProviderId,
327 NULL,
328 traceControllerHandle,
329 true,
330 g_provider_filters[i].Level,
331 g_provider_filters[i].Keyword,
334 NULL);
335 if (*err != ERROR_SUCCESS)
337 *err_info = ws_strdup_printf("EnableTraceEx failed with 0x%x", *err);
338 returnVal = WTAP_OPEN_ERROR;
339 break;
344 trace_handle = OpenTrace(&log_file);
345 if (trace_handle == INVALID_PROCESSTRACE_HANDLE) {
346 *err = GetLastError();
347 *err_info = ws_strdup_printf("OpenTrace failed with 0x%x", *err);
348 returnVal = WTAP_OPEN_NOT_MINE;
349 break;
352 g_pdh = etw_dump_open(pcapng_filename, err, err_info);
353 if (g_pdh == NULL)
355 returnVal = WTAP_OPEN_ERROR;
356 break;
359 *err = ProcessTrace(&trace_handle, 1, 0, 0);
360 if (*err != ERROR_SUCCESS) {
361 returnVal = WTAP_OPEN_ERROR;
362 *err_info = ws_strdup_printf("ProcessTrace failed with 0x%x", *err);
363 break;
366 if (g_err != ERROR_SUCCESS)
368 *err = g_err;
369 *err_info = g_strdup(g_err_info);
370 returnVal = WTAP_OPEN_ERROR;
371 break;
374 if (!g_num_events) {
375 *err = ERROR_NO_DATA;
376 *err_info = ws_strdup_printf("Didn't find any etw event");
377 returnVal = WTAP_OPEN_NOT_MINE;
378 break;
380 } while (false);
382 if (trace_handle != INVALID_PROCESSTRACE_HANDLE)
384 CloseTrace(trace_handle);
386 if (g_pdh != NULL)
388 if (*err == ERROR_SUCCESS)
390 if (!wtap_dump_close(g_pdh, NULL, err, err_info))
392 returnVal = WTAP_OPEN_ERROR;
395 else
397 int err_ignore;
398 char* err_info_ignore = NULL;
399 if (!wtap_dump_close(g_pdh, NULL, &err_ignore, &err_info_ignore))
401 returnVal = WTAP_OPEN_ERROR;
402 g_free(err_info_ignore);
406 return returnVal;
409 BOOL is_event_filtered_out(PEVENT_RECORD ev)
411 if (g_is_live_session)
413 return false;
416 if (IsEqualGUID(&g_provider_filters[0].ProviderId, &ZeroGuid))
418 return false;
421 for (int i = 0; i < ARRAYSIZE(g_provider_filters); i++)
423 if (IsEqualGUID(&g_provider_filters[i].ProviderId, &ev->EventHeader.ProviderId))
425 return false;
427 if (IsEqualGUID(&g_provider_filters[i].ProviderId, &ZeroGuid))
429 break;
433 return true;
436 static void WINAPI event_callback(PEVENT_RECORD ev)
438 ULARGE_INTEGER timestamp;
439 g_num_events++;
441 if (is_event_filtered_out(ev))
443 return;
447 * 100ns since 1/1/1601 -> usec since 1/1/1970.
448 * The offset of 11644473600 seconds can be calculated with a couple of calls to SystemTimeToFileTime.
450 timestamp.QuadPart = (ev->EventHeader.TimeStamp.QuadPart / 10) - 11644473600000000ll;
452 /* Write OPN events that needs mbim sub dissector */
453 if (IsEqualGUID(&ev->EventHeader.ProviderId, &mbb_provider))
455 etw_dump_write_opn_event(ev, timestamp);
457 else if (IsEqualGUID(&ev->EventHeader.ProviderId, &ndis_capture_provider))
459 etw_dump_write_ndiscap_event(ev, timestamp);
461 /* Write any event form other providers other than above */
462 else
464 etw_dump_write_general_event(ev, timestamp);
468 wtap_dumper* etw_dump_open(const char* pcapng_filename, int* err, char** err_info)
470 wtap_dump_params params = { 0 };
471 GArray* shb_hdrs = NULL;
472 wtap_block_t shb_hdr;
473 wtapng_iface_descriptions_t* idb_info;
474 GArray* idb_datas;
475 wtap_block_t idb_data;
476 wtapng_if_descr_mandatory_t* descr_mand;
478 wtap_dumper* pdh = NULL;
480 shb_hdrs = g_array_new(false, false, sizeof(wtap_block_t));
481 shb_hdr = wtap_block_create(WTAP_BLOCK_SECTION);
482 g_array_append_val(shb_hdrs, shb_hdr);
484 /* In the future, may create multiple WTAP_BLOCK_IF_ID_AND_INFO separately for IP packet */
485 idb_info = g_new(wtapng_iface_descriptions_t, 1);
486 idb_datas = g_array_new(false, false, sizeof(wtap_block_t));
487 idb_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
488 descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(idb_data);
489 descr_mand->tsprecision = WTAP_TSPREC_USEC;
490 descr_mand->wtap_encap = WTAP_ENCAP_ETW;
491 /* Timestamp for each pcapng packet is usec units, so time_units_per_second need be set to 10^6 */
492 descr_mand->time_units_per_second = G_USEC_PER_SEC;
493 g_array_append_val(idb_datas, idb_data);
494 idb_info->interface_data = idb_datas;
496 params.encap = WTAP_ENCAP_ETW;
497 params.snaplen = 0;
498 params.tsprec = WTAP_TSPREC_USEC;
499 params.shb_hdrs = shb_hdrs;
500 params.idb_inf = idb_info;
502 pdh = wtap_dump_open(pcapng_filename, wtap_pcapng_file_type_subtype(), WTAP_UNCOMPRESSED, &params, err, err_info);
504 if (shb_hdrs)
506 wtap_block_array_free(shb_hdrs);
508 if (params.idb_inf)
510 if (params.idb_inf->interface_data)
512 wtap_block_array_free(params.idb_inf->interface_data);
514 g_free(params.idb_inf);
515 params.idb_inf = NULL;
518 return pdh;
521 ULONG wtap_etl_record_buffer_init(WTAP_ETL_RECORD** out_etl_record, PEVENT_RECORD ev, BOOLEAN include_user_data, WCHAR* message, WCHAR* provider_name)
523 ULONG total_packet_length = sizeof(WTAP_ETL_RECORD);
524 WTAP_ETL_RECORD* etl_record = NULL;
525 ULONG user_data_length = 0;
526 ULONG user_data_offset = 0;
527 ULONG message_offset = 0;
528 ULONG provider_name_offset = 0;
529 ULONG message_length = 0;
530 ULONG provider_name_length = 0;
532 if (include_user_data)
534 if (ev->UserDataLength < MAX_PACKET_SIZE)
536 user_data_length = ev->UserDataLength;
538 else
540 user_data_length = MAX_PACKET_SIZE;
542 user_data_offset = sizeof(WTAP_ETL_RECORD);
543 total_packet_length += ROUND_UP_COUNT(user_data_length, sizeof(LONG));
545 if (message && message[0] != L'\0')
547 message_offset = total_packet_length;
548 message_length = (ULONG)((wcslen(message) + 1) * sizeof(WCHAR));
549 total_packet_length += ROUND_UP_COUNT(message_length, sizeof(LONG));
551 if (provider_name && provider_name[0] != L'\0')
553 provider_name_offset = total_packet_length;
554 provider_name_length = (ULONG)((wcslen(provider_name) + 1) * sizeof(WCHAR));
555 total_packet_length += ROUND_UP_COUNT(provider_name_length, sizeof(LONG));
558 etl_record = g_malloc(total_packet_length);
559 SecureZeroMemory(etl_record, total_packet_length);
560 etl_record->EventHeader = ev->EventHeader;
561 etl_record->BufferContext = ev->BufferContext;
562 etl_record->UserDataLength = user_data_length;
563 etl_record->MessageLength = message_length;
564 etl_record->ProviderLength = provider_name_length;
566 if (user_data_offset)
568 memcpy(ADD_OFFSET_TO_POINTER(etl_record, user_data_offset), ev->UserData, user_data_length);
570 if (message_offset)
572 memcpy(ADD_OFFSET_TO_POINTER(etl_record, message_offset), message, message_length);
574 if (provider_name_offset)
576 memcpy(ADD_OFFSET_TO_POINTER(etl_record, provider_name_offset), provider_name, provider_name_length);
579 *out_etl_record = etl_record;
580 return total_packet_length;
583 void wtap_etl_add_interface(int pkt_encap, char* interface_name, unsigned short interface_name_length, char* interface_desc, unsigned short interface_desc_length)
585 wtap_block_t idb_data;
586 wtapng_if_descr_mandatory_t* descr_mand;
587 char* err_info;
588 int err;
590 idb_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO);
591 descr_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(idb_data);
592 descr_mand->wtap_encap = pkt_encap;
593 descr_mand->tsprecision = WTAP_TSPREC_USEC;
594 /* Timestamp for each pcapng packet is usec units, so time_units_per_second need be set to 10^6 */
595 descr_mand->time_units_per_second = G_USEC_PER_SEC;
596 if (interface_name_length) {
597 wtap_block_add_string_option(idb_data, OPT_IDB_NAME, interface_name, interface_name_length);
599 if (interface_desc_length) {
600 wtap_block_add_string_option(idb_data, OPT_IDB_DESCRIPTION, interface_desc, interface_desc_length);
602 if(!wtap_dump_add_idb(g_pdh, idb_data, &err, &err_info)) {
603 g_err = err;
604 sprintf_s(g_err_info, sizeof(g_err_info), "wtap_dump failed, %s", err_info);
605 g_free(err_info);
609 void wtap_etl_rec_dump(char* etl_record, ULONG total_packet_length, ULONG original_packet_length, unsigned int interface_id, BOOLEAN is_inbound, ULARGE_INTEGER timestamp, int pkt_encap, char* comment, unsigned short comment_length)
611 char* err_info;
612 int err;
613 wtap_rec rec = { 0 };
615 wtap_rec_init(&rec);
616 rec.rec_header.packet_header.caplen = total_packet_length;
617 rec.rec_header.packet_header.len = original_packet_length;
618 rec.rec_header.packet_header.pkt_encap = pkt_encap;
619 rec.rec_header.packet_header.interface_id = interface_id;
620 rec.presence_flags = WTAP_HAS_INTERFACE_ID;
621 rec.block = wtap_block_create(WTAP_BLOCK_PACKET);
622 wtap_block_add_uint32_option(rec.block, OPT_PKT_FLAGS, is_inbound ? PACK_FLAGS_DIRECTION_INBOUND : PACK_FLAGS_DIRECTION_OUTBOUND);
623 if (comment_length) {
624 wtap_block_add_string_option(rec.block, OPT_COMMENT, comment, comment_length);
626 /* Convert usec of the timestamp into nstime_t */
627 rec.ts.secs = (time_t)(timestamp.QuadPart / G_USEC_PER_SEC);
628 rec.ts.nsecs = (int)(((timestamp.QuadPart % G_USEC_PER_SEC) * G_NSEC_PER_SEC) / G_USEC_PER_SEC);
630 /* and save the packet */
631 if (!wtap_dump(g_pdh, &rec, (uint8_t*)etl_record, &err, &err_info)) {
632 g_err = err;
633 sprintf_s(g_err_info, sizeof(g_err_info), "wtap_dump failed, %s", err_info);
634 g_free(err_info);
637 /* Only flush when live session */
638 if (g_is_live_session && !wtap_dump_flush(g_pdh, &err)) {
639 g_err = err;
640 sprintf_s(g_err_info, sizeof(g_err_info), "wtap_dump failed, 0x%x", err);
642 wtap_rec_cleanup(&rec);
645 void etw_dump_write_opn_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
647 WTAP_ETL_RECORD* etl_record = NULL;
648 ULONG total_packet_length = 0;
649 BOOLEAN is_inbound = false;
650 /* 0x80000000 mask the function to host message */
651 is_inbound = ((*(INT32*)(ev->UserData)) & 0x80000000) ? true : false;
652 total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, true, NULL, NULL);
653 wtap_etl_rec_dump((char*)etl_record, total_packet_length, total_packet_length, 0, is_inbound, timestamp, WTAP_ENCAP_ETW, NULL, 0);
654 g_free(etl_record);
657 void etw_dump_write_event_head_only(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
659 WTAP_ETL_RECORD* etl_record = NULL;
660 ULONG total_packet_length = 0;
661 total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, false, NULL, NULL);
662 wtap_etl_rec_dump((char*)etl_record, total_packet_length, total_packet_length, 0, false, timestamp, WTAP_ENCAP_ETW, NULL, 0);
663 g_free(etl_record);
666 void etw_dump_write_general_event(PEVENT_RECORD ev, ULARGE_INTEGER timestamp)
668 PTRACE_EVENT_INFO pInfo = NULL;
669 PBYTE pUserData = NULL;
670 PBYTE pEndOfUserData = NULL;
671 DWORD PointerSize = 0;
672 PROPERTY_KEY_VALUE* prop_arr = NULL;
673 DWORD dwTopLevelPropertyCount = 0;
674 DWORD dwSizeofArray = 0;
675 WCHAR wszMessageBuffer[MAX_LOG_LINE_LENGTH] = { 0 };
676 WCHAR formatMessage[MAX_LOG_LINE_LENGTH] = { 0 };
678 WTAP_ETL_RECORD* etl_record = NULL;
679 ULONG total_packet_length = 0;
680 BOOLEAN is_message_dumped = false;
684 /* Skip EventTrace events */
685 if (ev->EventHeader.Flags & EVENT_HEADER_FLAG_CLASSIC_HEADER &&
686 IsEqualGUID(&ev->EventHeader.ProviderId, &EventTraceGuid))
689 * The first event in every ETL file contains the data from the file header.
690 * This is the same data as was returned in the EVENT_TRACE_LOGFILEW by
691 * OpenTrace. Since we've already seen this information, we'll skip this
692 * event.
694 break;
697 /* Skip events injected by the XPerf tracemerger - they will never be decodable */
698 if (IsEqualGUID(&ev->EventHeader.ProviderId, &ImageIdGuid) ||
699 IsEqualGUID(&ev->EventHeader.ProviderId, &SystemConfigExGuid) ||
700 IsEqualGUID(&ev->EventHeader.ProviderId, &EventMetadataGuid))
702 break;
705 if (!get_event_information(ev, &pInfo))
707 break;
710 /* Skip those events without format message since most of them need special logic to decode like NDIS-PackCapture */
711 if (pInfo->EventMessageOffset <= 0)
713 break;
716 if (EVENT_HEADER_FLAG_32_BIT_HEADER == (ev->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))
718 PointerSize = 4;
720 else
722 PointerSize = 8;
725 pUserData = (PBYTE)ev->UserData;
726 pEndOfUserData = (PBYTE)ev->UserData + ev->UserDataLength;
728 dwTopLevelPropertyCount = pInfo->TopLevelPropertyCount;
729 if (dwTopLevelPropertyCount > 0)
731 prop_arr = g_malloc(sizeof(PROPERTY_KEY_VALUE) * dwTopLevelPropertyCount);
732 dwSizeofArray = dwTopLevelPropertyCount * sizeof(PROPERTY_KEY_VALUE);
733 SecureZeroMemory(prop_arr, dwSizeofArray);
736 StringCbCopy(formatMessage, MAX_LOG_LINE_LENGTH, (LPWSTR)ADD_OFFSET_TO_POINTER(pInfo, pInfo->EventMessageOffset));
738 for (USHORT i = 0; i < dwTopLevelPropertyCount; i++)
740 pUserData = extract_properties(ev, pInfo, PointerSize, i, pUserData, pEndOfUserData, &prop_arr[i]);
741 if (NULL == pUserData)
743 break;
747 format_message(formatMessage, prop_arr, dwTopLevelPropertyCount, wszMessageBuffer, sizeof(wszMessageBuffer));
749 total_packet_length = wtap_etl_record_buffer_init(&etl_record, ev, false, wszMessageBuffer, (WCHAR*)ADD_OFFSET_TO_POINTER(pInfo, pInfo->ProviderNameOffset));
750 wtap_etl_rec_dump((char*)etl_record, total_packet_length, total_packet_length, 0, false, timestamp, WTAP_ENCAP_ETW, NULL, 0);
751 g_free(etl_record);
753 is_message_dumped = true;
754 } while (false);
756 if (NULL != prop_arr)
758 g_free(prop_arr);
759 prop_arr = NULL;
761 if (NULL != pInfo)
763 g_free(pInfo);
764 pInfo = NULL;
767 if (!is_message_dumped && g_include_undecidable_event)
769 etw_dump_write_event_head_only(ev, timestamp);
774 * Editor modelines - https://www.wireshark.org/tools/modelines.html
776 * Local variables:
777 * c-basic-offset: 4
778 * tab-width: 8
779 * indent-tabs-mode: nil
780 * End:
782 * vi: set shiftwidth=4 tabstop=8 expandtab:
783 * :indentSize=4:tabSize=8:noTabs=true: