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 @@
Consoletrue
- tdh.lib;%(AdditionalDependencies)
+ tdh.lib;ws2_32.lib;%(AdditionalDependencies)
@@ -119,7 +119,7 @@
Consoletrue
- tdh.lib;%(AdditionalDependencies)
+ tdh.lib;ws2_32.lib;%(AdditionalDependencies)
@@ -140,7 +140,7 @@
truetruetrue
- tdh.lib;%(AdditionalDependencies)
+ tdh.lib;ws2_32.lib;%(AdditionalDependencies)
@@ -161,7 +161,7 @@
truetruetrue
- 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();