Skip to content

Commit

Permalink
Allow setting timestamp mode per-adapter-handle. See nmap/nmap#1775
Browse files Browse the repository at this point in the history
Any of the supported timestamp modes can be set via
PacketSetTimestampMode(), which uses the new BIOCSTIMESTAMPMODE
IoControl code. The TimestampMode Registry setting is still observed as
the default for new capture handles. Changing the timestamp mode will
empty the kernel's capture buffer to avoid conflict between timestamps
in captured packets.
  • Loading branch information
bonsaiviking committed Mar 16, 2020
1 parent 44908e2 commit 58bed96
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 74 deletions.
1 change: 1 addition & 0 deletions Common/Packet32.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ extern "C"
BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject, int timeout);
BOOLEAN PacketSetBpf(LPADAPTER AdapterObject, struct bpf_program* fp);
BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior);
BOOLEAN PacketSetTimestampMode(LPADAPTER AdapterObject, ULONG mode);
INT PacketSetSnapLen(LPADAPTER AdapterObject, int snaplen);
BOOLEAN PacketGetStats(LPADAPTER AdapterObject, struct bpf_stat* s);
BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject, struct bpf_stat* s);
Expand Down
1 change: 1 addition & 0 deletions packetWin7/Dll/Packet.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ EXPORTS
PacketSetDumpLimits
PacketIsDumpEnded
PacketSetLoopbackBehavior
PacketSetTimestampMode
PacketGetAirPcapHandle
35 changes: 35 additions & 0 deletions packetWin7/Dll/Packet32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3961,6 +3961,41 @@ BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavio
return result;
}

/*!
\brief Sets the timestamp mode of an adapter handle.
\param AdapterObject Pointer to an _ADAPTER structure.
\param mode The new timestamp mode from the TIMESTAMPMODE_* definitions
\return TRUE if the function succeeds, FALSE otherwise.
*/
BOOLEAN PacketSetTimestampMode(LPADAPTER AdapterObject, ULONG mode)
{
DWORD BytesReturned;
BOOLEAN result;

TRACE_ENTER();

if (AdapterObject->Flags != INFO_FLAG_NDIS_ADAPTER)
{
TRACE_PRINT("PacketSetTimestampMode: not allowed on non-NPF adapters");

TRACE_EXIT();
return FALSE;
}


result = (BOOLEAN)DeviceIoControl(AdapterObject->hFile,
BIOCSTIMESTAMPMODE,
&mode,
sizeof(ULONG),
NULL,
0,
&BytesReturned,
NULL);

TRACE_EXIT();
return result;
}

/*!
\brief Sets the snap len on the adapters that allow it.
\param AdapterObject Pointer to an _ADAPTER structure.
Expand Down
30 changes: 2 additions & 28 deletions packetWin7/npf/npf/Openclos.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,6 @@ static
VOID
NPF_ReleaseFilterModuleResources(PNPCAP_FILTER_MODULE pFiltMod);

/// Global start time. Used as an absolute reference for timestamp conversion.
struct time_conv G_Start_Time =
{
0, {0, 0},
};

ULONG g_NumOpenedInstances = 0;
ULONG g_NumLoopbackInstances = 0;

extern SINGLE_LIST_ENTRY g_arrFiltMod; //Adapter filter module list head, each list item is a group head.
Expand Down Expand Up @@ -373,12 +366,10 @@ NPF_OpenAdapter_End:;
// complete the open
//
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Open = %p\n", Open);
localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances);

// Get the absolute value of the system boot time.
// This is used for timestamp conversion.
TIME_SYNCHRONIZE(&G_Start_Time);
TIME_SYNCHRONIZE(&Open->start, Open->TimestampMode);

NPF_AddToGroupOpenArray(Open, pFiltMod);

Expand Down Expand Up @@ -1038,21 +1029,6 @@ NPF_Cleanup(

// IrpSp->FileObject->FsContext = NULL;

//
// Decrease the counter of open instances
//
localNumOpenInstances = InterlockedDecrement(&g_NumOpenedInstances);
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenInstances);

if (localNumOpenInstances == 0)
{
//
// Force a synchronization at the next NPF_Open().
// This hopefully avoids the synchronization issues caused by hibernation or standby.
//
TIME_DESYNCHRONIZE(&G_Start_Time);
}

Status = STATUS_SUCCESS;

//
Expand Down Expand Up @@ -1458,6 +1434,7 @@ NPF_CreateOpenObject()
// Initialize the open instance
//
//Open->BindContext = NULL;
Open->TimestampMode = g_TimestampMode;
Open->bpfprogram = NULL; //reset the filter
Open->mode = MODE_CAPT;
Open->Nbytes.QuadPart = 0;
Expand Down Expand Up @@ -1968,9 +1945,6 @@ NPF_Restart(

TRACE_ENTER();

TIME_DESYNCHRONIZE(&G_Start_Time);
TIME_SYNCHRONIZE(&G_Start_Time);

if (RestartParameters == NULL)
{
// Can't validate, but probably fine. Also, I don't think this is possible.
Expand Down
27 changes: 26 additions & 1 deletion packetWin7/npf/npf/Packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ ULONG g_AdminOnlyMode = 0;
ULONG g_DltNullMode = 0;
ULONG g_Dot11SupportMode = 0;
ULONG g_VlanSupportMode = 0;
ULONG g_TimestampMode = 0;
ULONG g_TimestampMode = DEFAULT_TIMESTAMPMODE;

ULONG g_NCpu;

Expand Down Expand Up @@ -318,6 +318,9 @@ DriverEntry(
// Get the TimestampMode option. The meanings of its values is described in time_calls.h.
// If the registry key doesn't exist, we view it as TimestampMode=0, so the default "QueryPerformanceCounter" timestamp gathering method.
g_TimestampMode = NPF_GetRegistryOption_Integer(&parametersPath, &g_TimestampRegValueName);
if (!NPF_TimestampModeSupported(g_TimestampMode)) {
g_TimestampMode = DEFAULT_TIMESTAMPMODE;
}

#ifdef HAVE_WFP_LOOPBACK_SUPPORT
g_LoopbackSupportMode = NPF_GetRegistryOption_Integer(&parametersPath, &g_LoopbackSupportRegValueName);
Expand Down Expand Up @@ -1966,6 +1969,28 @@ NPF_IoControl(

break;

case BIOCSTIMESTAMPMODE:
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
SET_FAILURE_BUFFER_SMALL();
break;
}

dim = *((PULONG)Irp->AssociatedIrp.SystemBuffer);

// verify that the provided mode is supported
if (!NPF_TimestampModeSupported(dim))
{
SET_FAILURE_INVALID_REQUEST();
break;
}

/* Reset buffer, since contents could have differing timestamps */
NPF_ResetBufferContents(Open);
Open->TimestampMode = dim;

SET_RESULT_SUCCESS(0);
break;

default:
TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Unknown IOCTL code");
Expand Down
3 changes: 2 additions & 1 deletion packetWin7/npf/npf/Packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ typedef struct _OPEN_INSTANCE

OPEN_STATE OpenStatus;
NDIS_SPIN_LOCK OpenInUseLock;
ULONG TimestampMode;
struct timeval start; // Time synchronization of QPC with last boot

}
OPEN_INSTANCE, *POPEN_INSTANCE;
Expand Down Expand Up @@ -439,7 +441,6 @@ struct PacketHeader
};

extern ULONG g_NCpu;
extern struct time_conv G_Start_Time; // from openclos.c

#define TRANSMIT_PACKETS 256 ///< Maximum number of packets in the transmit packet pool. This value is an upper bound to the number
///< of packets that can be transmitted at the same time or with a single call to NdisSendPackets.
Expand Down
4 changes: 2 additions & 2 deletions packetWin7/npf/npf/Read.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ NPF_Read(

//fill the bpf header for this packet
header = (struct bpf_hdr *)CurrBuff;
GET_TIME(&header->bh_tstamp, &G_Start_Time);
GET_TIME(&header->bh_tstamp, &Open->start, Open->TimestampMode);

#ifdef NPCAP_KDUMP
if (Open->mode & MODE_DUMP)
Expand Down Expand Up @@ -942,7 +942,7 @@ NPF_TapExForEachOpen(

Header = (struct PacketHeader *)(LocalData->Buffer + LocalData->P);
LocalData->Accepted++;
GET_TIME(&Header->header.bh_tstamp, &G_Start_Time);
GET_TIME(&Header->header.bh_tstamp, &Open->start, Open->TimestampMode);
Header->SN = InterlockedIncrement(&Open->WriterSN) - 1;

// DbgPrint("MDL %d\n", BufferLength);
Expand Down
6 changes: 6 additions & 0 deletions packetWin7/npf/npf/ioctls.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,12 @@
#define W_BIOCSETEVENTHANDLE 7920
#define BIOCSETEVENTHANDLE CTL_CODE(FILE_DEVICE_TRANSPORT, 0xa11, METHOD_BUFFERED, FILE_READ_DATA)

/*
\brief IOCTL code: set the timestamp mode.
This IOCTL sets the timestamp mode (DWORD) to one of the supported modes from time_calls.h
*/
#define BIOCSTIMESTAMPMODE CTL_CODE(FILE_DEVICE_TRANSPORT, 0xa12, METHOD_BUFFERED, FILE_READ_DATA)
/**
* @}
*/
Expand Down
68 changes: 26 additions & 42 deletions packetWin7/npf/npf/time_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@
#define TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE 4
#define /* DEPRECATED */ TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP 99

__inline BOOLEAN NPF_TimestampModeSupported(ULONG mode)
{
return mode == TIMESTAMPMODE_SINGLE_SYNCHRONIZATION
|| mode == TIMESTAMPMODE_QUERYSYSTEMTIME
|| mode == TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE;
}

extern ULONG g_TimestampMode;

/* Defined in Packet.c/h
Expand All @@ -116,21 +123,8 @@ struct timeval

#endif /*WIN_NT_DRIVER*/

struct time_conv
{
ULONGLONG reference;
struct timeval start;
};

#ifdef WIN_NT_DRIVER

__inline void TIME_DESYNCHRONIZE(struct time_conv* data)
{
data->reference = 0;
// data->start.tv_sec = 0;
// data->start.tv_usec = 0;
}

#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600

/* KeQueryPerformanceCounter TimeStamps */
Expand Down Expand Up @@ -167,24 +161,16 @@ __inline void SynchronizeOnCpu(struct timeval* start)

#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600

__inline VOID TIME_SYNCHRONIZE(struct time_conv* data)
__inline VOID TIME_SYNCHRONIZE(struct timeval* start, ULONG TimestampMode)
{

if (data->reference != 0)
return;


switch (g_TimestampMode)
switch (TimestampMode)
{
case TIMESTAMPMODE_QUERYSYSTEMTIME:
case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE:
//do nothing
data->reference = 1;
case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION:
SynchronizeOnCpu(start);
break;
default:
//it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
SynchronizeOnCpu(&data->start);
data->reference = 1;
//do nothing
break;
}
return;
Expand All @@ -193,7 +179,7 @@ __inline VOID TIME_SYNCHRONIZE(struct time_conv* data)

#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600

__inline void GetTimeKQPC(struct timeval* dst, struct time_conv* data)
__inline void GetTimeKQPC(struct timeval* dst, struct timeval* start)
{
LARGE_INTEGER PTime, TimeFreq;
LONG tmp;
Expand All @@ -202,8 +188,8 @@ __inline void GetTimeKQPC(struct timeval* dst, struct time_conv* data)
tmp = (LONG)(PTime.QuadPart / TimeFreq.QuadPart);

//it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
dst->tv_sec = data->start.tv_sec + tmp;
dst->tv_usec = data->start.tv_usec + (LONG)((PTime.QuadPart % TimeFreq.QuadPart) * 1000000 / TimeFreq.QuadPart);
dst->tv_sec = start->tv_sec + tmp;
dst->tv_usec = start->tv_usec + (LONG)((PTime.QuadPart % TimeFreq.QuadPart) * 1000000 / TimeFreq.QuadPart);

if (dst->tv_usec >= 1000000)
{
Expand All @@ -212,21 +198,19 @@ __inline void GetTimeKQPC(struct timeval* dst, struct time_conv* data)
}
}

__inline void GetTimeQST(struct timeval* dst, struct time_conv* data)
__inline void GetTimeQST(struct timeval* dst)
{
LARGE_INTEGER SystemTime;
UNREFERENCED_PARAMETER(data);

KeQuerySystemTime(&SystemTime);

dst->tv_sec = (LONG)(SystemTime.QuadPart / 10000000 - 11644473600);
dst->tv_usec = (LONG)((SystemTime.QuadPart % 10000000) / 10);
}

__inline void GetTimeQST_precise(struct timeval* dst, struct time_conv* data)
__inline void GetTimeQST_precise(struct timeval* dst)
{
LARGE_INTEGER SystemTime;
UNREFERENCED_PARAMETER(data);

My_KeQuerySystemTimePrecise(&SystemTime);

Expand All @@ -238,33 +222,33 @@ __inline void GetTimeQST_precise(struct timeval* dst, struct time_conv* data)
#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600


__inline void GET_TIME(struct timeval* dst, struct time_conv* data)
__inline void GET_TIME(struct timeval* dst, struct timeval* start, ULONG TimestampMode)
{
switch (g_TimestampMode)
switch (TimestampMode)
{
case TIMESTAMPMODE_QUERYSYSTEMTIME:
GetTimeQST(dst, data);
GetTimeQST(dst);
break;
case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE:
GetTimeQST_precise(dst, data);
GetTimeQST_precise(dst);
break;
default:
GetTimeKQPC(dst, data);
GetTimeKQPC(dst, start);
break;
}
}


#else /*WIN_NT_DRIVER*/

__inline void FORCE_TIME(struct timeval* src, struct time_conv* dest)
__inline void FORCE_TIME(struct timeval* src, struct timeval* dest)
{
dest->start = *src;
*dest = *src;
}

__inline void GET_TIME(struct timeval* dst, struct time_conv* data)
__inline void GET_TIME(struct timeval* dst, struct timeval* data)
{
*dst = data->start;
*dst = *data;
}

#endif /*WIN_NT_DRIVER*/
Expand Down

0 comments on commit 58bed96

Please sign in to comment.