From 5580702462b1e6d89b60a59f7fa529888ca50288 Mon Sep 17 00:00:00 2001 From: Jedihy Date: Fri, 4 Sep 2020 13:26:47 -0700 Subject: [PATCH] Automatically infer original fragment length for truncated fragments (Raw/Ethernet) (#28) * infer original length * update readme * fix LSO packets * fix comment * cr feedback * fix comment * fix comments --- README.md | 2 ++ src/etl2pcapng.vcxproj | 8 ++--- src/main.c | 67 ++++++++++++++++++++++++++++++++++-------- src/pcapng.h | 3 +- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 448fb22..a0e5627 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ msbuild -t:rebuild -p:configuration=release -p:platform=x64 # History +1.4.0 - Automatically infer original fragment length if captured fragments were truncated. + 1.3.0 - Add a comment to each packet containing the process id (PID). 1.2.0 - Write direction info of each packet (epb_flags) diff --git a/src/etl2pcapng.vcxproj b/src/etl2pcapng.vcxproj index 3302436..dd80bed 100644 --- a/src/etl2pcapng.vcxproj +++ b/src/etl2pcapng.vcxproj @@ -102,7 +102,7 @@ Console true - tdh.lib;%(AdditionalDependencies) + tdh.lib;ws2_32.lib;%(AdditionalDependencies) @@ -119,7 +119,7 @@ Console true - tdh.lib;%(AdditionalDependencies) + tdh.lib;ws2_32.lib;%(AdditionalDependencies) @@ -140,7 +140,7 @@ true true true - tdh.lib;%(AdditionalDependencies) + tdh.lib;ws2_32.lib;%(AdditionalDependencies) @@ -161,7 +161,7 @@ true true true - tdh.lib;%(AdditionalDependencies) + tdh.lib;ws2_32.lib;%(AdditionalDependencies) diff --git a/src/main.c b/src/main.c index 8a5e11b..cab55a7 100644 --- a/src/main.c +++ b/src/main.c @@ -12,8 +12,11 @@ in Windows that produces packet capture events) to pcapng format Issues: -ndiscap supports packet truncation and so does pcapng, but ndiscap doesn't - currently log metadata about truncation in its events (other than marking - them with a keyword), so we pretend there is no truncation for now. + currently log metadata about truncation in its events, so we try to infer + the original fragment length from IP headers and it currently works for + RAW and Eithernet frames. For LSO v2 packets since length field is not + filled, we can't infer the original length for them and we use the + truncated length as their original length. */ @@ -25,6 +28,8 @@ in Windows that produces packet capture events) to pcapng format #include #include #include +#include +#include #include #define USAGE \ @@ -226,6 +231,12 @@ void WINAPI EventCallback(PEVENT_RECORD ev) unsigned long FragLength; PROPERTY_DATA_DESCRIPTOR Desc; ULARGE_INTEGER TimeStamp; + short Type; + unsigned long TotalFragmentLength; + unsigned long InferredOriginalFragmentLength; + PETHERNET_HEADER EthHdr; + PIPV4_HEADER Ipv4Hdr; + PIPV6_HEADER Ipv6Hdr; if (!IsEqualGUID(&ev->EventHeader.ProviderId, &NdisCapId) || (ev->EventHeader.EventDescriptor.Id != tidPacketFragment && @@ -244,15 +255,16 @@ void WINAPI EventCallback(PEVENT_RECORD ev) Iface = GetInterface(LowerIfIndex); + if (!!(ev->EventHeader.EventDescriptor.Keyword & KW_MEDIA_NATIVE_802_11)) { + Type = PCAPNG_LINKTYPE_IEEE802_11; + } else if (!!(ev->EventHeader.EventDescriptor.Keyword & KW_MEDIA_WIRELESS_WAN)) { + Type = PCAPNG_LINKTYPE_RAW; + } else { + Type = PCAPNG_LINKTYPE_ETHERNET; + } + if (!Pass2) { - short Type; - if (!!(ev->EventHeader.EventDescriptor.Keyword & KW_MEDIA_NATIVE_802_11)) { - Type = PCAPNG_LINKTYPE_IEEE802_11; - } else if (!!(ev->EventHeader.EventDescriptor.Keyword & KW_MEDIA_WIRELESS_WAN)) { - Type = PCAPNG_LINKTYPE_RAW; - } else { - Type = PCAPNG_LINKTYPE_ETHERNET; - } + // Record the IfIndex if it's a new one. if (Iface == NULL) { unsigned long MiniportIfIndex; @@ -289,7 +301,7 @@ void WINAPI EventCallback(PEVENT_RECORD ev) } if (MetadataLength != sizeof(PacketMetadata)) { - printf("Unknown Metadata length. Expected %u, got %u\n", sizeof(DOT11_EXTSTA_RECV_CONTEXT), MetadataLength); + printf("Unknown Metadata length. Expected %llu, got %u\n", sizeof(DOT11_EXTSTA_RECV_CONTEXT), MetadataLength); return; } @@ -399,10 +411,41 @@ void WINAPI EventCallback(PEVENT_RECORD ev) } } + TotalFragmentLength = AuxFragBufOffset + FragLength; + + // Parse the packet to see if it's truncated. If so, try to recover the original length. + if (Type == PCAPNG_LINKTYPE_ETHERNET) { + if (TotalFragmentLength >= sizeof(ETHERNET_HEADER)) { + EthHdr = (PETHERNET_HEADER)AuxFragBuf; + if (ntohs(EthHdr->Type) == ETHERNET_TYPE_IPV4 && + TotalFragmentLength >= sizeof(IPV4_HEADER) + sizeof(ETHERNET_HEADER)) { + Ipv4Hdr = (PIPV4_HEADER)(EthHdr + 1); + InferredOriginalFragmentLength = ntohs(Ipv4Hdr->TotalLength) + sizeof(ETHERNET_HEADER); + } else if (ntohs(EthHdr->Type) == ETHERNET_TYPE_IPV6 && + TotalFragmentLength >= sizeof(IPV6_HEADER) + sizeof(ETHERNET_HEADER)) { + Ipv6Hdr = (PIPV6_HEADER)(EthHdr + 1); + InferredOriginalFragmentLength = ntohs(Ipv6Hdr->PayloadLength) + sizeof(IPV6_HEADER) + sizeof(ETHERNET_HEADER); + } + } + } else if (Type == PCAPNG_LINKTYPE_RAW) { + // Raw frames begins with an IPv4/6 header. + if (TotalFragmentLength >= sizeof(IPV4_HEADER)) { + Ipv4Hdr = (PIPV4_HEADER)AuxFragBuf; + if (Ipv4Hdr->Version == 4) { + InferredOriginalFragmentLength = ntohs(Ipv4Hdr->TotalLength) + sizeof(ETHERNET_HEADER); + } else if (Ipv4Hdr->Version == 6) { + Ipv6Hdr = (PIPV6_HEADER)(AuxFragBuf); + InferredOriginalFragmentLength = ntohs(Ipv6Hdr->PayloadLength) + sizeof(IPV6_HEADER) + sizeof(ETHERNET_HEADER); + } + } + } + PcapNgWriteEnhancedPacket( OutFile, AuxFragBuf, - AuxFragBufOffset + FragLength, + TotalFragmentLength, + // For LSO v2 packets, inferred original fragment length is ignored since length field in IP header is not filled. + InferredOriginalFragmentLength <= TotalFragmentLength ? TotalFragmentLength : InferredOriginalFragmentLength, Iface->PcapNgIfIndex, !!(ev->EventHeader.EventDescriptor.Keyword & KW_SEND), TimeStamp.HighPart, diff --git a/src/pcapng.h b/src/pcapng.h index ac12ae6..03bcff9 100644 --- a/src/pcapng.h +++ b/src/pcapng.h @@ -194,6 +194,7 @@ PcapNgWriteEnhancedPacket( HANDLE File, char* FragBuf, unsigned long FragLength, + unsigned long OrigFragLength, long InterfaceId, long IsSend, long TimeStampHigh, // usec (unless if_tsresol is used) @@ -230,7 +231,7 @@ PcapNgWriteEnhancedPacket( Body.InterfaceId = InterfaceId; Body.TimeStampHigh = TimeStampHigh; Body.TimeStampLow = TimeStampLow; - Body.PacketLength = FragLength; // actual length + Body.PacketLength = OrigFragLength; // original length Body.CapturedLength = FragLength; // truncated length if (!WriteFile(File, &Body, sizeof(Body), NULL, NULL)) { Err = GetLastError();