📄 wanpacket.cpp
字号:
// WanPacket.cpp : Defines the entry point for the DLL application.
//
#include <tchar.h>
#include <winsock2.h>
#include <windows.h>
#include <crtdbg.h>
#include <eh.h>
#include <netmon.h>
#include "win_bpf.h"
#include "win_bpf_filter_init.h"
#include <packet32.h>
#include "wanpacket.h"
/*!
\brief Describes an opened wan (dialup, VPN...) network adapter using the NetMon API
This structure is the most important for the functioning of WanPacket.dll.
This structure should be considered opaque by users.
*/
struct WAN_ADAPTER_INT
{
HBLOB hCaptureBlob; ///< Handle to the BLOB (the network adapter in the NetMon world) used to capture
CRITICAL_SECTION CriticalSection; ///< Used to synchronize access to this structure.
PUCHAR Buffer; ///< Pointer to the ring buffer used to capture packets.
DWORD C; ///< Zero-based index of the consumer in the ring buffer. It indicates the first free byte to be read.
DWORD P; ///< Zero-based index of the producer in the ring buffer. It indicates the first free byte to be written.
DWORD Free; ///< Number of the free bytes in the ring buffer.
DWORD Size; ///< Size of the ring buffer used to capture packets.
DWORD Dropped; ///< Number of packets that the current instance had to drop, from its opening. A packet is dropped if there is no more space to store it in the ring buffer.
DWORD Accepted; ///< Number of packets that the current capture instance has accepted, from its opening. A packet is accepted if it passes the bpf filter and fits in the ring buffer. Accepted packets are the ones that reach the application.
DWORD Received; ///< Number of packets received by current instance from its opening.
DWORD MinToCopy; ///< Minimum amount of data in the ring buffer that unlocks a read.
DWORD ReadTimeout; ///< Timeout after which a read is released, also if the amount of data in the ring buffer is less than MinToCopy.
HANDLE hReadEvent; ///< Pointer to the event on which the read calls on this instance must wait.
bpf_insn *FilterCode; ///< Pointer to the filtering pseudo-code associated with current instance of capture.
DWORD Mode; ///< Working mode of the driver. See PacketSetMode() for details.
LARGE_INTEGER Nbytes; ///< Amount of bytes accepted by the filter when this instance is in statistical mode.
LARGE_INTEGER Npackets; ///< Number of packets accepted by the filter when this instance is in statistical mode.
MEM_TYPE MemEx; ///< Memory used by the TME virtual co-processor
TME_CORE Tme; ///< Data structure containing the virtualization of the TME co-processor
IRTC *pIRTC; ///< Pointer to the NetMon IRTC COM interface used to capture packets.
};
#define ALIGN_TO_WORD(x) (((x) + 3)&~(3))
BOOLEAN WanPacketAddPacketToRingBuffer(PWAN_ADAPTER pWanAdapter, LPFRAME_DESCRIPTOR lpFrameDesc, DWORD SnapToCopy, struct timeval PacketTime);
DWORD WanPacketRemovePacketsFromRingBuffer(PWAN_ADAPTER pWanAdapter, PUCHAR Buffer, DWORD BuffSize);
/*!
\brief The main dll function.
*/
BOOLEAN APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
/*!
\brief It returns the current time formatted as a timeval structure.
\return The current time formatted as a timeval structure.
*/
struct timeval WanPacketGetCurrentTime()
{
struct timeval tvReturn;
FILETIME FileTime;
GetSystemTimeAsFileTime(&FileTime);
tvReturn.tv_sec = (LONG)(((LARGE_INTEGER*)&FileTime)->QuadPart / 10000000);
tvReturn.tv_usec = (LONG)(((LARGE_INTEGER*)&FileTime)->QuadPart % 10000000 / 10);
return tvReturn;
}
/*!
\brief This is the callback used by the NetMon IRTC interface to pass the packets to the user.
\param Event. An UPDATE_EVENT structure containing the packets.
\return Not clearly defined by the NetMon IRTC MSDN documentation.
*/
DWORD WINAPI WanPacketReceiverCallback(UPDATE_EVENT Event)
{
DWORD i;
LPFRAMETABLE lpFrameTable;
LPFRAME_DESCRIPTOR lpFrameDesc;
PWAN_ADAPTER pWanAdapter;
u_int FilterResult;
struct time_conv TimeConv;
struct timeval PacketTime;
pWanAdapter = (PWAN_ADAPTER)Event.lpUserContext;
lpFrameTable = Event.lpFrameTable;
// the frame table can wrap the indices
for (i = lpFrameTable->StartIndex; i != lpFrameTable->EndIndex; (i == lpFrameTable->FrameTableLength) ? i=0: i ++ )
{
lpFrameDesc = &lpFrameTable->Frames[i];
PacketTime.tv_sec = (ULONG) (lpFrameDesc->TimeStamp / (__int64)1000000 - 11644473600);
PacketTime.tv_usec= (ULONG) (lpFrameDesc->TimeStamp % (__int64)1000000);
FORCE_TIME(&PacketTime, &TimeConv);
EnterCriticalSection( &pWanAdapter->CriticalSection );
pWanAdapter->Received ++;
FilterResult = bpf_filter(pWanAdapter->FilterCode,
lpFrameDesc->FramePointer,
lpFrameDesc->FrameLength,
lpFrameDesc->nBytesAvail,
&pWanAdapter->MemEx,
&pWanAdapter->Tme,
&TimeConv);
if ( pWanAdapter->Mode == PACKET_MODE_MON && FilterResult == 1 )
SetEvent( pWanAdapter->hReadEvent );
if (FilterResult == (u_int) -1 || FilterResult > lpFrameDesc->nBytesAvail )
FilterResult = lpFrameDesc->nBytesAvail;
if ( pWanAdapter->Mode == PACKET_MODE_STAT )
{
pWanAdapter->Npackets.QuadPart ++;
if ( lpFrameDesc->FrameLength < 60 )
pWanAdapter->Nbytes.QuadPart += 60;
else
pWanAdapter->Nbytes.QuadPart += lpFrameDesc->FrameLength;
// add preamble+SFD+FCS to the packet
// these values must be considered because are not part of the packet received from NDIS
pWanAdapter->Nbytes.QuadPart += 12;
}
if ( pWanAdapter->Mode == PACKET_MODE_CAPT && FilterResult > 0 )
{
if ( WanPacketAddPacketToRingBuffer(pWanAdapter, lpFrameDesc, FilterResult, PacketTime ) )
pWanAdapter->Accepted++;
else
pWanAdapter->Dropped++;
}
LeaveCriticalSection( &pWanAdapter->CriticalSection );
}
return NOERROR;
}
/*!
\brief Tries to open the wan (dialup, vpn...) adapter, and immediately closes it.
\return TRUE on success.
*/
BOOLEAN WanPacketTestAdapter()
{
PBLOB_TABLE pBlobTable = NULL;
HBLOB hFilterBlob = NULL;
BOOLEAN retVal;
DWORD i;
if ( CreateBlob(&hFilterBlob) != NMERR_SUCCESS )
return FALSE;
if ( SetBoolInBlob(hFilterBlob, OWNER_NPP, CATEGORY_CONFIG, TAG_INTERFACE_REALTIME_CAPTURE, TRUE) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
return FALSE;
}
if ( SetBoolInBlob(hFilterBlob, OWNER_NPP, CATEGORY_LOCATION, TAG_RAS, TRUE) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
return FALSE;
}
if ( GetNPPBlobTable(hFilterBlob, &pBlobTable) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
return FALSE;
}
DestroyBlob (hFilterBlob);
if (pBlobTable->dwNumBlobs == 1)
retVal = TRUE;
else
retVal = FALSE;
for ( i = 0 ; i < pBlobTable->dwNumBlobs ; i++ )
DestroyBlob(pBlobTable->hBlobs[i]);
GlobalFree(pBlobTable);
return retVal;
}
/*!
\brief Opens the wan (dialup, vpn...) adapter.
\return If the function succeeds, the return value is the pointer to a properly initialized WAN_ADAPTER structure,
otherwise the return value is NULL.
*/
PWAN_ADAPTER WanPacketOpenAdapter()
{
PWAN_ADAPTER pWanAdapter;
PBLOB_TABLE pBlobTable = NULL;
HBLOB hFilterBlob = NULL;
HRESULT hResult;
DWORD i;
pWanAdapter = (PWAN_ADAPTER)GlobalAlloc(GPTR, sizeof (WAN_ADAPTER));
if ( pWanAdapter == NULL )
return NULL;
if ( CreateBlob(&hFilterBlob) != NMERR_SUCCESS )
{
GlobalFree(pWanAdapter);
return NULL;
}
if ( SetBoolInBlob(hFilterBlob, OWNER_NPP, CATEGORY_CONFIG, TAG_INTERFACE_REALTIME_CAPTURE, TRUE) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
GlobalFree(pWanAdapter);
return NULL;
}
if ( SetBoolInBlob(hFilterBlob, OWNER_NPP, CATEGORY_LOCATION, TAG_RAS, TRUE) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
GlobalFree(pWanAdapter);
return NULL;
}
if ( GetNPPBlobTable(hFilterBlob, &pBlobTable) != NMERR_SUCCESS )
{
DestroyBlob( hFilterBlob);
GlobalFree(pWanAdapter);
return NULL;
}
DestroyBlob (hFilterBlob);
if ( pBlobTable->dwNumBlobs == 0 || pBlobTable->dwNumBlobs > 1)
{
///fixme.....
for ( i = 0 ; i < pBlobTable->dwNumBlobs ; i++ )
DestroyBlob(pBlobTable->hBlobs[i]);
GlobalFree(pBlobTable);
GlobalFree(pWanAdapter);
return NULL;
}
pWanAdapter->hCaptureBlob = pBlobTable->hBlobs[0];
GlobalFree(pBlobTable);
InitializeCriticalSection(&pWanAdapter->CriticalSection);
pWanAdapter->hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( pWanAdapter->hReadEvent == NULL )
goto error;
pWanAdapter->MemEx.buffer = (PUCHAR)GlobalAlloc(GPTR, DEFAULT_MEM_EX_SIZE);
if (pWanAdapter->MemEx.buffer == NULL)
goto error;
pWanAdapter->MemEx.size = DEFAULT_MEM_EX_SIZE;
pWanAdapter->Tme.active = TME_NONE_ACTIVE;
hResult = CoInitialize(NULL);
if (hResult != S_OK && hResult != S_FALSE)
goto error;
if (CreateNPPInterface(pWanAdapter->hCaptureBlob, IID_IRTC, (void**) &pWanAdapter->pIRTC) == NMERR_SUCCESS && pWanAdapter->pIRTC != NULL)
{
//create OK
if (pWanAdapter->pIRTC->Connect(pWanAdapter->hCaptureBlob, NULL, WanPacketReceiverCallback, (LPVOID)pWanAdapter , NULL) == NMERR_SUCCESS)
{
//connect OK
if (pWanAdapter->pIRTC->Start() == NMERR_SUCCESS)
{
return pWanAdapter;
}
else
{
pWanAdapter->pIRTC->Disconnect();
pWanAdapter->pIRTC->Release();
CoUninitialize();
goto error;
}
}
else
{
pWanAdapter->pIRTC->Release();
CoUninitialize();
goto error;
}
}
else
{
CoUninitialize();
goto error;
}
//awfully never reached
return NULL;
error:
if (pWanAdapter->hReadEvent != NULL)
CloseHandle(pWanAdapter->hReadEvent);
DeleteCriticalSection(&pWanAdapter->CriticalSection);
DestroyBlob(pWanAdapter->hCaptureBlob);
GlobalFree(pWanAdapter);
return NULL;
}
/*!
\brief Closes a wan (dialup, vpn...) adapter.
\param lpWanAdapter the pointer to the wan adapter to close.
WanPacketCloseAdapter closes the given adapter and frees the associated WAN_ADAPTER structure
*/
BOOLEAN WanPacketCloseAdapter(PWAN_ADAPTER pWanAdapter)
{
if (pWanAdapter->pIRTC->Stop() != NMERR_SUCCESS)
OutputDebugString("WanPacketCloseAdapter: Severe error, IRTC::Stop failed\n");
if (pWanAdapter->pIRTC->Disconnect() != NMERR_SUCCESS)
OutputDebugString("WanPacketCloseAdapter: Severe error, IRTC::Disconnect failed\n");
if (pWanAdapter->pIRTC->Release() != NMERR_SUCCESS)
OutputDebugString("WanPacketCloseAdapter: Severe error, IRTC::Release failed\n");
Sleep(0); //Just a stupid hack to make all the stuff work. I don't why it's necessary.
//uninitialize COM
CoUninitialize();
//setting a NULL filter will actually deallocate the in-use filter
WanPacketSetBpfFilter(pWanAdapter, NULL, 0);
//setting a zero-sized buffer will deallocate any in-use ring buffer
WanPacketSetBufferSize(pWanAdapter, 0);
CloseHandle(pWanAdapter->hReadEvent);
//destroy the BLOB used to capture
DestroyBlob(pWanAdapter->hCaptureBlob);
DeleteCriticalSection(&pWanAdapter->CriticalSection);
//deallocate the extended memory, if any.
if (pWanAdapter->MemEx.size > 0)
GlobalFree(pWanAdapter->MemEx.buffer);
GlobalFree(pWanAdapter);
return TRUE;
}
/*!
\brief Sets the working mode of a wan (dialup, vpn...) adapter.
\param pWanAdapter Pointer to a WAN_ADAPTER structure.
\param mode The new working mode of the adapter.
\return If the function succeeds, the return value is true.
For more information, see the documentation of PacketSetMode
*/
BOOLEAN WanPacketSetMode(PWAN_ADAPTER pWanAdapter, DWORD Mode)
{
if (Mode != PACKET_MODE_CAPT && Mode != PACKET_MODE_STAT && Mode != PACKET_MODE_MON)
return FALSE;
pWanAdapter->Mode = Mode;
return TRUE;
}
/*!
\brief Sets the bpf packet filter.
\param pWanAdapter Pointer to a WAN_ADAPTER structure.
\param FilterCode Pointer to the BPF filtering code that will be associated with this capture or monitoring
instance and that will be executed on every incoming packet.
\param Length Length, in bytes, of the BPF filter code.
\return This function returns TRUE if the filter is set successfully, FALSE if an error occurs
or if the filter program is not accepted after a safeness check. This API
performs the check in order to avoid unexpected behavior due to buggy or malicious filters, and it rejects non
conformant filters.
For more information, see the documentation of PacketSetBpf
*/
BOOLEAN WanPacketSetBpfFilter(PWAN_ADAPTER pWanAdapter, PUCHAR FilterCode, DWORD Length)
{
PUCHAR NewFilterCode = NULL;
DWORD NumberOfInstructions;
DWORD Counter;
struct bpf_insn *InitializationCode;
struct time_conv TimeConv;
if ( Length < 0)
return FALSE;
EnterCriticalSection(&pWanAdapter->CriticalSection);
if (Length > 0)
{
NumberOfInstructions = Length/sizeof(struct bpf_insn);
for(Counter = 0;
Counter < NumberOfInstructions && ((struct bpf_insn*)FilterCode)[Counter].code != BPF_SEPARATION ;
Counter++);
if ( Counter != NumberOfInstructions &&
NumberOfInstructions != Counter + 1 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -