Skip to content

Commit

Permalink
Automatically infer original fragment length for truncated fragments …
Browse files Browse the repository at this point in the history
…(Raw/Ethernet) (#28)

* infer original length

* update readme

* fix LSO packets

* fix comment

* cr feedback

* fix comment

* fix comments
  • Loading branch information
csujedihy authored Sep 4, 2020
1 parent e33c208 commit 5580702
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions src/etl2pcapng.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>tdh.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>tdh.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
Expand All @@ -119,7 +119,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>tdh.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>tdh.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
Expand All @@ -140,7 +140,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>tdh.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>tdh.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Expand All @@ -161,7 +161,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>tdh.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>tdh.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Expand Down
67 changes: 55 additions & 12 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/

Expand All @@ -25,6 +28,8 @@ in Windows that produces packet capture events) to pcapng format
#include <evntcons.h>
#include <tdh.h>
#include <strsafe.h>
#include <winsock2.h>
#include <netiodef.h>
#include <pcapng.h>

#define USAGE \
Expand Down Expand Up @@ -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 &&
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/pcapng.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 5580702

Please sign in to comment.