#include <packet32.h>
#include <windows.h>
-#include <windowsx.h>
+//#include <windowsx.h>
#include <ntddndis.h>
+#include "trace.h"
+
+
+/****** KERNEL Macro APIs ******************************************************/
+
+#define GetInstanceModule(hInst) (HMODULE)(hInst)
+#define GlobalPtrHandle(lp) ((HGLOBAL)GlobalHandle(lp))
+#define GlobalLockPtr(lp) ((BOOL)GlobalLock(GlobalPtrHandle(lp)))
+#define GlobalUnlockPtr(lp) GlobalUnlock(GlobalPtrHandle(lp))
+#define GlobalAllocPtr(flags, cb) (GlobalLock(GlobalAlloc((flags), (cb))))
+#define GlobalReAllocPtr(lp, cbNew, flags) (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags))))
+#define GlobalFreePtr(lp) (GlobalUnlockPtr(lp), (BOOL)(ULONG_PTR)GlobalFree(GlobalPtrHandle(lp)))
+
+#undef GMEM_MOVEABLE
+#define GMEM_MOVEABLE 0
+
+
/// Title of error windows
TCHAR szWindowTitle[] = TEXT("PACKET.DLL");
-#if _DBG
+#if DBG
#define ODS(_x) OutputDebugString(TEXT(_x))
-#define ODSEx(_x, _y)
+//#define ODSEx(_x, _y)
+#define ODSEx TRACE
#else
#ifdef _DEBUG_TO_FILE
#include <stdio.h>
-// Macro to print a debug string. The behavior differs depending on the debug level
+/*!
+ \brief Macro to print a debug string. The behavior differs depending on the debug level
+*/
#define ODS(_x) { \
FILE *f; \
f = fopen("winpcap_debug.txt", "a"); \
fprintf(f, "%s", _x); \
fclose(f); \
}
-// Macro to print debug data with the printf convention. The behavior differs depending on */
+/*!
+ \brief Macro to print debug data with the printf convention. The behavior differs depending on
+ the debug level
+*/
#define ODSEx(_x, _y) { \
FILE *f; \
f = fopen("winpcap_debug.txt", "a"); \
LPCTSTR NPFServiceName = TEXT("NPF");
LPCTSTR NPFServiceDesc = TEXT("Netgroup Packet Filter");
LPCTSTR NPFDriverName = TEXT("\\npf.sys");
-LPCTSTR NPFRegistryLocation = TEXT("SYSTEM\\CurrentControlSet\\Services\\NPF");
+LPCTSTR NPFRegistryLocation = TEXT("SYSTEM\\ControlSet001\\Services\\NPF");
//---------------------------------------------------------------------------
+/*!
+ \brief The main dll function.
+*/
+
BOOL APIENTRY DllMain (HANDLE DllHandle,DWORD Reason,LPVOID lpReserved)
{
BOOLEAN Status=TRUE;
#ifdef _DEBUG_TO_FILE
// dump a bunch of registry keys useful for debug to file
- PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
+ PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
"adapters.reg");
- PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip",
+ PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip",
"tcpip.reg");
- PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\NPF",
+ PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\NPF",
"npf.reg");
- PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services",
+ PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services",
"services.reg");
#endif
break;
return Status;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Converts an ASCII string to UNICODE. Uses the MultiByteToWideChar() system function.
+ \param string The string to convert.
+ \return The converted string.
+*/
WCHAR* SChar2WChar(char* string)
{
return TmpStr;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Sets the maximum possible lookahead buffer for the driver's Packet_tap() function.
+ \param AdapterObject Handle to the service control manager.
+ \return If the function succeeds, the return value is nonzero.
+
+ The lookahead buffer is the portion of packet that Packet_tap() can access from the NIC driver's memory
+ without performing a copy. This function tries to increase the size of that buffer.
+*/
BOOLEAN PacketSetMaxLookaheadsize (LPADAPTER AdapterObject)
{
return Status;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Retrieves the event associated in the driver with a capture instance and stores it in an
+ _ADAPTER structure.
+ \param AdapterObject Handle to the service control manager.
+ \return If the function succeeds, the return value is nonzero.
+
+ This function is used by PacketOpenAdapter() to retrieve the read event from the driver by means of an ioctl
+ call and set it in the _ADAPTER structure pointed by AdapterObject.
+*/
BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject)
{
DWORD BytesReturned;
- TCHAR EventName[39];
+ WCHAR EventName[39];
// this tells the terminal service to retrieve the event from the global namespace
wcsncpy(EventName,L"Global\\",sizeof(L"Global\\"));
EventName[20]=0; // terminate the string
// open the shared event
- AdapterObject->ReadEvent=CreateEvent(NULL,
+ AdapterObject->ReadEvent=CreateEventW(NULL,
TRUE,
FALSE,
EventName);
CloseHandle(AdapterObject->ReadEvent);
// open the shared event
- AdapterObject->ReadEvent=CreateEvent(NULL,
+ AdapterObject->ReadEvent=CreateEventW(NULL,
TRUE,
FALSE,
EventName+7);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Installs the NPF device driver.
+ \param ascmHandle Handle to the service control manager.
+ \param ascmHandle A pointer to a handle that will receive the pointer to the driver's service.
+ \param driverPath The full path of the .sys file to load.
+ \return If the function succeeds, the return value is nonzero.
+
+ This function installs the driver's service in the system using the CreateService function.
+*/
-BOOL PacketInstallDriver(SC_HANDLE ascmHandle,SC_HANDLE *srvHandle,TCHAR *driverPath)
+BOOL PacketInstallDriver(SC_HANDLE ascmHandle, SC_HANDLE* srvHandle, TCHAR* driverPath)
{
BOOL result = FALSE;
ULONG err;
- ODS("installdriver\n")
+ ODS("installdriver\n");
if (GetFileAttributes(driverPath) != 0xffffffff) {
*srvHandle = CreateService(ascmHandle,
//npf.sys already existed
result = TRUE;
}
- }
- else {
+ } else {
//Created service for npf.sys
result = TRUE;
}
}
- if (result == TRUE)
- if (*srvHandle != NULL)
+ if (result == TRUE) {
+ if (*srvHandle != NULL) {
CloseServiceHandle(*srvHandle);
+ }
+ }
- if(result == FALSE){
+ if (result == FALSE){
err = GetLastError();
- if(err != 2)
+ if (err != 2) {
ODSEx("PacketInstallDriver failed, Error=%d\n",err);
+ }
}
return result;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Convert a Unicode dotted-quad to a 32-bit IP address.
+ \param cp A string containing the address.
+ \return the converted 32-bit numeric address.
+
+ Doesn't check to make sure the address is valid.
+*/
+
ULONG inet_addrU(const WCHAR *cp)
{
return val;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Dumps a registry key to disk in text format. Uses regedit.
+ \param KeyName Name of the ket to dump. All its subkeys will be saved recursively.
+ \param FileName Name of the file that will contain the dump.
+ \return If the function succeeds, the return value is nonzero.
+
+ For debugging purposes, we use this function to obtain some registry keys from the user's machine.
+*/
#ifdef _DEBUG_TO_FILE
// PUBLIC API
//---------------------------------------------------------------------------
+/** @ingroup packetapi
+ * @{
+ */
+
+/** @defgroup packet32 Packet.dll exported functions and variables
+ * @{
+ */
+
/// Current packet.dll Version. It can be retrieved directly or through the PacketGetVersion() function.
char PacketLibraryVersion[] = "2.3";
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Returns a string with the dll version.
+ \return A char pointer to the version of the library.
+*/
PCHAR PacketGetVersion(){
return PacketLibraryVersion;
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Returns information about the MAC type of an adapter.
+ \param AdapterObject The adapter on which information is needed.
+ \param type Pointer to a NetType structure that will be filled by the function.
+ \return If the function succeeds, the return value is nonzero, otherwise the return value is zero.
+
+ This function return the link layer technology and the speed (in bps) of an opened adapter.
+ The LinkType field of the type parameter can have one of the following values:
+
+ - NdisMedium802_3: Ethernet (802.3)
+ - NdisMediumWan: WAN
+ - NdisMedium802_5: Token Ring (802.5)
+ - NdisMediumFddi: FDDI
+ - NdisMediumAtm: ATM
+ - NdisMediumArcnet878_2: ARCNET (878.2)
+*/
BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type)
{
BOOLEAN Status;
return Status;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Stops and unloads the WinPcap device driver.
+ \return If the function succeeds, the return value is nonzero, otherwise it is zero.
+ This function can be used to unload the driver from memory when the application no more needs it.
+ Note that the driver is physically stopped and unloaded only when all the files on its devices
+ are closed, i.e. when all the applications that use WinPcap close all their adapters.
+*/
BOOL PacketStopDriver()
{
SC_HANDLE scmHandle;
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Opens an adapter.
+ \param AdapterName A string containing the name of the device to open.
+ Use the PacketGetAdapterNames() function to retrieve the list of available devices.
+ \return If the function succeeds, the return value is the pointer to a properly initialized ADAPTER object,
+ otherwise the return value is NULL.
+
+ This function tries to load and start the packet driver at the first invocation. In this way,
+ the management of the driver is transparent to the application, that simply needs to open an adapter to start
+ WinPcap.
+
+ \note the Windows 95 version of the NPF driver works with the ASCII string format, while the Windows NT
+ version works with UNICODE. Therefore, AdapterName \b should be an ASCII string in Windows 95, and a UNICODE
+ string in Windows NT. This difference is not a problem if the string pointed by AdapterName was obtained
+ through the PacketGetAdapterNames function, because it returns the names of the adapters in the proper format.
+ Problems can arise in Windows NT when the string is obtained from ANSI C functions like scanf, because they
+ use the ASCII format. Since this could be a relevant problem during the porting of command-line applications
+ from UNIX, we included in the Windows NT version of PacketOpenAdapter the ability to detect ASCII strings and
+ convert them to UNICODE before sending them to the device driver. Therefore PacketOpenAdapter in Windows NT
+ accepts both the ASCII and the UNICODE format. If a ASCII string is received, it is converted to UNICODE
+ by PACKET.DLL before being passed to the driver.
+*/
LPADAPTER PacketOpenAdapter(LPTSTR AdapterName)
{
LPADAPTER lpAdapter;
HKEY PathKey;
SERVICE_STATUS SStat;
BOOLEAN QuerySStat;
+ WCHAR SymbolicLink[128];
- ODSEx("PacketOpenAdapter: trying to open the adapter=%S\n",AdapterName)
+ ODSEx("PacketOpenAdapter: trying to open the adapter=%S\n",AdapterName);
scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-
if(scmHandle == NULL){
error = GetLastError();
ODSEx("OpenSCManager failed! Error=%d\n", error);
- }
- else{
+ } else {
*driverPath = 0;
GetCurrentDirectory(512, driverPath);
- wsprintf(driverPath + wcslen(driverPath),
- NPFDriverName);
+ wsprintf(driverPath + wcslen(driverPath), NPFDriverName);
// check if the NPF registry key is already present
// this means that the driver is already installed and that we don't need to call PacketInstallDriver
if(KeyRes != ERROR_SUCCESS){
Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath);
- }
- else{
+ } else {
Result = TRUE;
RegCloseKey(PathKey);
}
QuerySStat = QueryServiceStatus(srvHandle, &SStat);
ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState);
- if(!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){
+ if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){
ODS("Calling startservice\n");
if (StartService(srvHandle, 0, NULL)==0){
error = GetLastError();
- if(error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){
+ if (error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){
SetLastError(error);
if (scmHandle != NULL) CloseServiceHandle(scmHandle);
error = GetLastError();
}
}
}
- }
- else{
+ } else {
error = GetLastError();
ODSEx("OpenService failed! Error=%d", error);
}
- }
- else{
- if( GetSystemDirectory(WinPath, sizeof(WinPath)/sizeof(TCHAR)) == 0) return FALSE;
- wsprintf(driverPath,
- TEXT("%s\\drivers%s"),
- WinPath,NPFDriverName);
+ } else {
+ if (GetSystemDirectory(WinPath, sizeof(WinPath)/sizeof(TCHAR)) == 0) {
+ return FALSE;
+ }
+ wsprintf(driverPath, TEXT("%s\\drivers%s"), WinPath, NPFDriverName);
- if(KeyRes != ERROR_SUCCESS)
+ if (KeyRes != ERROR_SUCCESS) {
Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath);
- else
+ } else {
Result = TRUE;
-
+ }
if (Result) {
-
srvHandle = OpenService(scmHandle,NPFServiceName,SERVICE_START);
- if (srvHandle != NULL){
-
+ if (srvHandle != NULL) {
QuerySStat = QueryServiceStatus(srvHandle, &SStat);
ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState);
-
- if(!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){
-
+ if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING) {
ODS("Calling startservice\n");
-
- if (StartService(srvHandle, 0, NULL)==0){
+ if (StartService(srvHandle, 0, NULL) == 0) {
error = GetLastError();
- if(error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){
+ if (error != ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS) {
SetLastError(error);
if (scmHandle != NULL) CloseServiceHandle(scmHandle);
ODSEx("PacketOpenAdapter: StartService failed, Error=%d\n",error);
}
}
}
- }
- else{
+ } else {
error = GetLastError();
ODSEx("OpenService failed! Error=%d", error);
}
}
}
}
-
if (scmHandle != NULL) CloseServiceHandle(scmHandle);
- AdapterNameA=(char*)AdapterName;
- if(AdapterNameA[1]!=0){ //ASCII
- AdapterNameU=SChar2WChar(AdapterNameA);
- AdapterName=AdapterNameU;
- } else { //Unicode
- AdapterNameU=NULL;
+ AdapterNameA = (char*)AdapterName;
+ if (AdapterNameA[1] != 0) { // ASCII
+ AdapterNameU = SChar2WChar(AdapterNameA);
+ AdapterName = AdapterNameU;
+ } else { // Unicode
+ AdapterNameU = NULL;
}
- lpAdapter=(LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER));
- if (lpAdapter==NULL)
- {
+ lpAdapter = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER));
+ if (lpAdapter == NULL) {
ODS("PacketOpenAdapter: GlobalAlloc Failed\n");
- error=GetLastError();
+ error = GetLastError();
if (AdapterNameU != NULL) free(AdapterNameU);
//set the error to the one on which we failed
SetLastError(error);
ODS("PacketOpenAdapter: Failed to allocate the adapter structure\n");
return NULL;
}
- lpAdapter->NumWrites=1;
+ lpAdapter->NumWrites = 1;
- wsprintf(lpAdapter->SymbolicLink,TEXT("\\\\.\\%s%s"),DOSNAMEPREFIX,&AdapterName[8]);
+ wsprintf(SymbolicLink,TEXT("\\\\.\\%s%s"), DOSNAMEPREFIX, &AdapterName[8]);
+ // Copy only the bytes that fit in the adapter structure.
+ // Note that lpAdapter->SymbolicLink is present for backward compatibility but will
+ // never be used by the apps
+ memcpy(lpAdapter->SymbolicLink, (PCHAR)SymbolicLink, MAX_LINK_NAME_LENGTH);
+
//try if it is possible to open the adapter immediately
- lpAdapter->hFile=CreateFile(lpAdapter->SymbolicLink,GENERIC_WRITE | GENERIC_READ,
- 0,NULL,OPEN_EXISTING,0,0);
+ lpAdapter->hFile = CreateFile(SymbolicLink,GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
if (lpAdapter->hFile != INVALID_HANDLE_VALUE) {
-
- if(PacketSetReadEvt(lpAdapter)==FALSE){
- error=GetLastError();
+ ODSEx("PacketOpenAdapter: CreateFile(%S) successfull\n", SymbolicLink);
+ if (PacketSetReadEvt(lpAdapter) == FALSE) {
+ error = GetLastError();
ODS("PacketOpenAdapter: Unable to open the read event\n");
if (AdapterNameU != NULL)
free(AdapterNameU);
}
//this is probably the first request on the packet driver.
//We must create the dos device and set the access rights on it
- else{
- Result=DefineDosDevice(DDD_RAW_TARGET_PATH,&lpAdapter->SymbolicLink[4],AdapterName);
- if (Result)
- {
+ else {
+ Result = DefineDosDevice(DDD_RAW_TARGET_PATH,
+ &SymbolicLink[4],
+ AdapterName);
+ if (Result) {
- lpAdapter->hFile=CreateFile(lpAdapter->SymbolicLink,GENERIC_WRITE | GENERIC_READ,
- 0,NULL,OPEN_EXISTING,0,0);
- if (lpAdapter->hFile != INVALID_HANDLE_VALUE)
- {
-
- if(PacketSetReadEvt(lpAdapter)==FALSE){
- error=GetLastError();
+ ODSEx("PacketOpenAdapter: calling CreateFile(%S)\n", SymbolicLink);
+
+ lpAdapter->hFile = CreateFile(
+ SymbolicLink,
+ GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
+ if (lpAdapter->hFile != INVALID_HANDLE_VALUE) {
+ if (PacketSetReadEvt(lpAdapter) == FALSE) {
+ error = GetLastError();
ODS("PacketOpenAdapter: Unable to open the read event\n");
if (AdapterNameU != NULL)
free(AdapterNameU);
ODSEx("PacketOpenAdapter: PacketSetReadEvt failed, Error=1,%d\n",error);
return NULL;
}
-
PacketSetMaxLookaheadsize(lpAdapter);
if (AdapterNameU != NULL)
free(AdapterNameU);
return lpAdapter;
+ } else {
+ ODS("PacketOpenAdapter: CreateFile failed\n");
}
+ } else {
+ ODSEx("PacketOpenAdapter: DefineDosDevice(%S) failed\n", &SymbolicLink[4]);
}
}
-
- error=GetLastError();
+ error = GetLastError();
if (AdapterNameU != NULL)
free(AdapterNameU);
GlobalFreePtr(lpAdapter);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Closes an adapter.
+ \param lpAdapter the pointer to the adapter to close.
+ PacketCloseAdapter closes the given adapter and frees the associated ADAPTER structure
+*/
VOID PacketCloseAdapter(LPADAPTER lpAdapter)
{
CloseHandle(lpAdapter->hFile);
GlobalFreePtr(lpAdapter);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Allocates a _PACKET structure.
+ \return On succeess, the return value is the pointer to a _PACKET structure otherwise the
+ return value is NULL.
+
+ The structure returned will be passed to the PacketReceivePacket() function to receive the
+ packets from the driver.
+ \warning The Buffer field of the _PACKET structure is not set by this function.
+ The buffer \b must be allocated by the application, and associated to the PACKET structure
+ with a call to PacketInitPacket.
+*/
LPPACKET PacketAllocatePacket(void)
{
- LPPACKET lpPacket;
- lpPacket=(LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET));
- if (lpPacket==NULL)
- {
+ LPPACKET lpPacket;
+ lpPacket = (LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET));
+ if (lpPacket == NULL) {
ODS("PacketAllocatePacket: GlobalAlloc Failed\n");
return NULL;
}
return lpPacket;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Frees a _PACKET structure.
+ \param lpPacket The structure to free.
+
+ \warning the user-allocated buffer associated with the _PACKET structure is not deallocated
+ by this function and \b must be explicitly deallocated by the programmer.
+*/
VOID PacketFreePacket(LPPACKET lpPacket)
{
GlobalFreePtr(lpPacket);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Initializes a _PACKET structure.
+ \param lpPacket The structure to initialize.
+ \param Buffer A pointer to a user-allocated buffer that will contain the captured data.
+ \param Length the length of the buffer. This is the maximum buffer size that will be
+ transferred from the driver to the application using a single read.
+
+ \note the size of the buffer associated with the PACKET structure is a parameter that can sensibly
+ influence the performance of the capture process, since this buffer will contain the packets received
+ from the the driver. The driver is able to return several packets using a single read call
+ (see the PacketReceivePacket() function for details), and the number of packets transferable to the
+ application in a call is limited only by the size of the buffer associated with the PACKET structure
+ passed to PacketReceivePacket(). Therefore setting a big buffer with PacketInitPacket can noticeably
+ decrease the number of system calls, reducing the impcat of the capture process on the processor.
+*/
VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length)
{
lpPacket->bIoComplete = FALSE;
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Read data (packets or statistics) from the NPF driver.
+ \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter from which
+ the data is received.
+ \param lpPacket Pointer to a PACKET structure that will contain the data.
+ \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with
+ older applications.
+ \return If the function succeeds, the return value is nonzero.
+
+ The data received with this function can be a group of packets or a static on the network traffic,
+ depending on the working mode of the driver. The working mode can be set with the PacketSetMode()
+ function. Give a look at that function if you are interested in the format used to return statistics
+ values, here only the normal capture mode will be described.
+
+ The number of packets received with this function is variable. It depends on the number of packets
+ currently stored in the driver\92s buffer, on the size of these packets and on the size of the buffer
+ associated to the lpPacket parameter. The following figure shows the format used by the driver to pass
+ packets to the application.
+
+ \image html encoding.gif "method used to encode the packets"
+
+ Packets are stored in the buffer associated with the lpPacket _PACKET structure. The Length field of
+ that structure is updated with the amount of data copied in the buffer. Each packet has a header
+ consisting in a bpf_hdr structure that defines its length and contains its timestamp. A padding field
+ is used to word-align the data in the buffer (to speed up the access to the packets). The bh_datalen
+ and bh_hdrlen fields of the bpf_hdr structures should be used to extract the packets from the buffer.
+
+ Examples can be seen either in the TestApp sample application (see the \ref packetsamps page) provided
+ in the developer's pack, or in the pcap_read() function of wpcap.
+*/
BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
{
BOOLEAN res;
res = ReadFile(AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->ulBytesReceived,NULL);
return res;
}
-/*
-ReadFile(
- HANDLE hFile,
- LPVOID lpBuffer,
- DWORD nNumberOfBytesToRead,
- LPDWORD lpNumberOfBytesRead,
- LPOVERLAPPED lpOverlapped
- );
- */
-//---------------------------------------------------------------------------
+/*!
+ \brief Sends one (or more) copies of a packet to the network.
+ \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will
+ send the packets.
+ \param lpPacket Pointer to a PACKET structure with the packet to send.
+ \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with
+ older applications.
+ \return If the function succeeds, the return value is nonzero.
+
+ This function is used to send a raw packet to the network. 'Raw packet' means that the programmer
+ will have to include the protocol headers, since the packet is sent to the network 'as is'.
+ The CRC needs not to be calculated and put at the end of the packet, because it will be transparently
+ added by the network interface.
+
+ The behavior of this function is influenced by the PacketSetNumWrites() function. With PacketSetNumWrites(),
+ it is possible to change the number of times a single write must be repeated. The default is 1,
+ i.e. every call to PacketSendPacket() will correspond to one packet sent to the network. If this number is
+ greater than 1, for example 1000, every raw packet written by the application will be sent 1000 times on
+ the network. This feature mitigates the overhead of the context switches and therefore can be used to generate
+ high speed traffic. It is particularly useful for tools that test networks, routers, and servers and need
+ to obtain high network loads.
+ The optimized sending process is still limited to one packet at a time: for the moment it cannot be used
+ to send a buffer with multiple packets.
+
+ \note The ability to write multiple packets is currently present only in the Windows NTx version of the
+ packet driver. In Windows 95/98/ME it is emulated at user level in packet.dll. This means that an application
+ that uses the multiple write method will run in Windows 9x as well, but its performance will be very low
+ compared to the one of WindowsNTx.
+*/
BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
{
DWORD BytesTransfered;
return WriteFile(AdapterObject->hFile,lpPacket->Buffer,lpPacket->Length,&BytesTransfered,NULL);
}
-//---------------------------------------------------------------------------
+
+/*!
+ \brief Sends a buffer of packets to the network.
+ \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will
+ send the packets.
+ \param PacketBuff Pointer to buffer with the packets to send.
+ \param Size Size of the buffer pointed by the PacketBuff argument.
+ \param Sync if TRUE, the packets are sent respecting the timestamps. If FALSE, the packets are sent as
+ fast as possible
+ \return The amount of bytes actually sent. If the return value is smaller than the Size parameter, an
+ error occurred during the send. The error can be caused by a driver/adapter problem or by an
+ inconsistent/bogus packet buffer.
+
+ This function is used to send a buffer of raw packets to the network. The buffer can contain an arbitrary
+ number of raw packets, each of which preceded by a dump_bpf_hdr structure. The dump_bpf_hdr is the same used
+ by WinPcap and libpcap to store the packets in a file, therefore sending a capture file is straightforward.
+ 'Raw packets' means that the sending application will have to include the protocol headers, since every packet
+ is sent to the network 'as is'. The CRC of the packets needs not to be calculated, because it will be
+ transparently added by the network interface.
+
+ \note Using this function if more efficient than issuing a series of PacketSendPacket(), because the packets are
+ buffered in the kernel driver, so the number of context switches is reduced.
+
+ \note When Sync is set to TRUE, the packets are synchronized in the kerenl with a high precision timestamp.
+ This requires a remarkable amount of CPU, but allows to send the packets with a precision of some microseconds
+ (depending on the precision of the performance counter of the machine). Such a precision cannot be reached
+ sending the packets separately with PacketSendPacket().
+*/
+INT PacketSendPackets(LPADAPTER AdapterObject, PVOID PacketBuff, ULONG Size, BOOLEAN Sync)
+{
+ BOOLEAN Res;
+ DWORD BytesTransfered, TotBytesTransfered=0;
+ struct timeval BufStartTime;
+ LARGE_INTEGER StartTicks, CurTicks, TargetTicks, TimeFreq;
+
+
+ ODS("PacketSendPackets");
+
+ // Obtain starting timestamp of the buffer
+ BufStartTime.tv_sec = ((struct timeval*)(PacketBuff))->tv_sec;
+ BufStartTime.tv_usec = ((struct timeval*)(PacketBuff))->tv_usec;
+
+ // Retrieve the reference time counters
+ QueryPerformanceCounter(&StartTicks);
+ QueryPerformanceFrequency(&TimeFreq);
+
+ CurTicks.QuadPart = StartTicks.QuadPart;
+
+ do{
+ // Send the data to the driver
+ Res = DeviceIoControl(AdapterObject->hFile,
+ (Sync)?pBIOCSENDPACKETSSYNC:pBIOCSENDPACKETSNOSYNC,
+ (PCHAR)PacketBuff + TotBytesTransfered,
+ Size - TotBytesTransfered,
+ NULL,
+ 0,
+ &BytesTransfered,
+ NULL);
+
+ TotBytesTransfered += BytesTransfered;
+
+ // calculate the time interval to wait before sending the next packet
+ TargetTicks.QuadPart = StartTicks.QuadPart +
+ (LONGLONG)
+ ((((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_sec - BufStartTime.tv_sec) * 1000000 +
+ (((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_usec - BufStartTime.tv_usec)) *
+ (TimeFreq.QuadPart) / 1000000;
+
+ // Exit from the loop on termination or error
+ if(TotBytesTransfered >= Size || Res != TRUE)
+ break;
+
+ // Wait until the time interval has elapsed
+ while( CurTicks.QuadPart <= TargetTicks.QuadPart )
+ QueryPerformanceCounter(&CurTicks);
+
+ }
+ while(TRUE);
+
+ return TotBytesTransfered;
+}
+
+/*!
+ \brief Defines the minimum amount of data that will be received in a read.
+ \param AdapterObject Pointer to an _ADAPTER structure
+ \param nbytes the minimum amount of data in the kernel buffer that will cause the driver to
+ release a read on this adapter.
+ \return If the function succeeds, the return value is nonzero.
+
+ In presence of a large value for nbytes, the kernel waits for the arrival of several packets before
+ copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage,
+ i.e. better performance, which is a good setting for applications like sniffers. Vice versa, a small value
+ means that the kernel will copy the packets as soon as the application is ready to receive them. This is
+ suggested for real time applications (like, for example, a bridge) that need the better responsiveness from
+ the kernel.
+
+ \b note: this function has effect only in Windows NTx. The driver for Windows 9x doesn't offer
+ this possibility, therefore PacketSetMinToCopy is implemented under these systems only for compatibility.
+*/
BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes)
{
return DeviceIoControl(AdapterObject->hFile,pBIOCSMINTOCOPY,&nbytes,4,NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Sets the working mode of an adapter.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param mode The new working mode of the adapter.
+ \return If the function succeeds, the return value is nonzero.
+
+ The device driver of WinPcap has 4 working modes:
+ - Capture mode (mode = PACKET_MODE_CAPT): normal capture mode. The packets transiting on the wire are copied
+ to the application when PacketReceivePacket() is called. This is the default working mode of an adapter.
+ - Statistical mode (mode = PACKET_MODE_STAT): programmable statistical mode. PacketReceivePacket() returns, at
+ precise intervals, statics values on the network traffic. The interval between the statistic samples is
+ by default 1 second but it can be set to any other value (with a 1 ms precision) with the
+ PacketSetReadTimeout() function. The data returned by PacketReceivePacket() when the adapter is in statistical
+ mode is shown in the following figure:<p>
+ \image html stats.gif "data structure returned by statistical mode"
+ Two 64-bit counters are provided: the number of packets and the amount of bytes that satisfy a filter
+ previously set with PacketSetBPF(). If no filter has been set, all the packets are counted. The counters are
+ encapsulated in a bpf_hdr structure, so that they will be parsed correctly by wpcap. Statistical mode has a
+ very low impact on system performance compared to capture mode.
+ - Dump mode (mode = PACKET_MODE_DUMP): the packets are dumped to disk by the driver, in libpcap format. This
+ method is much faster than saving the packets after having captured them. No data is returned
+ by PacketReceivePacket(). If the application sets a filter with PacketSetBPF(), only the packets that satisfy
+ this filter are dumped to disk.
+ - Statitical Dump mode (mode = PACKET_MODE_STAT_DUMP): the packets are dumped to disk by the driver, in libpcap
+ format, like in dump mode. PacketReceivePacket() returns, at precise intervals, statics values on the
+ network traffic and on the amount of data saved to file, in a way similar to statistical mode.
+ The data returned by PacketReceivePacket() when the adapter is in statistical dump mode is shown in
+ the following figure:<p>
+ \image html dump.gif "data structure returned by statistical dump mode"
+ Three 64-bit counters are provided: the number of packets accepted, the amount of bytes accepted and the
+ effective amount of data (including headers) dumped to file. If no filter has been set, all the packets are
+ dumped to disk. The counters are encapsulated in a bpf_hdr structure, so that they will be parsed correctly
+ by wpcap.
+ Look at the NetMeter example in the
+ WinPcap developer's pack to see how to use statistics mode.
+*/
BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode)
{
DWORD BytesReturned;
return DeviceIoControl(AdapterObject->hFile,pBIOCSMODE,&mode,4,NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Sets the name of the file that will receive the packet when the adapter is in dump mode.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param name the file name, in ASCII or UNICODE.
+ \param len the length of the buffer containing the name, in bytes.
+ \return If the function succeeds, the return value is nonzero.
+
+ This function defines the file name that the driver will open to store the packets on disk when
+ it works in dump mode. The adapter must be in dump mode, i.e. PacketSetMode() should have been
+ called previously with mode = PACKET_MODE_DUMP. otherwise this function will fail.
+ If PacketSetDumpName was already invoked on the adapter pointed by AdapterObject, the driver
+ closes the old file and opens the new one.
+*/
+
+BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len)
+{
+ DWORD BytesReturned;
+ WCHAR *FileName;
+ BOOLEAN res;
+ WCHAR NameWithPath[1024];
+ int TStrLen;
+ WCHAR *NamePos;
+
+ if(((PUCHAR)name)[1]!=0 && len>1){ //ASCII
+ FileName=SChar2WChar(name);
+ len*=2;
+ }
+ else { //Unicode
+ FileName=name;
+ }
+
+ TStrLen=GetFullPathName(FileName,1024,NameWithPath,&NamePos);
+
+ len=TStrLen*2+2; //add the terminating null character
+ // Try to catch malformed strings
+ if(len>2048){
+ if(((PUCHAR)name)[1]!=0 && len>1) free(FileName);
+ return FALSE;
+ }
+
+ res = DeviceIoControl(AdapterObject->hFile,pBIOCSETDUMPFILENAME,NameWithPath,len,NULL,0,&BytesReturned,NULL);
+ free(FileName);
+ return res;
+}
+
+/*!
+ \brief Set the dump mode limits.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param maxfilesize The maximum dimension of the dump file, in bytes. 0 means no limit.
+ \param maxnpacks The maximum number of packets contained in the dump file. 0 means no limit.
+ \return If the function succeeds, the return value is nonzero.
+
+ This function sets the limits after which the NPF driver stops to save the packets to file when an adapter
+ is in dump mode. This allows to limit the dump file to a precise number of bytes or packets, avoiding that
+ very long dumps fill the disk space. If both maxfilesize and maxnpacks are set, the dump is stopped when
+ the first of the two is reached.
+
+ \note When a limit is reached, the dump is stopped, but the file remains opened. In order to flush
+ correctly the data and access the file consistently, you need to close the adapter with PacketCloseAdapter().
+*/
+BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks)
+{
+ DWORD BytesReturned;
+ UINT valbuff[2];
+
+ valbuff[0] = maxfilesize;
+ valbuff[1] = maxnpacks;
+
+ return DeviceIoControl(AdapterObject->hFile,
+ pBIOCSETDUMPLIMITS,
+ valbuff,
+ sizeof valbuff,
+ NULL,
+ 0,
+ &BytesReturned,
+ NULL);
+}
+
+/*!
+ \brief Returns the status of the kernel dump process, i.e. tells if one of the limits defined with PacketSetDumpLimits() was reached.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param sync if TRUE, the function blocks until the dump is finished, otherwise it returns immediately.
+ \return TRUE if the dump is ended, FALSE otherwise.
+
+ PacketIsDumpEnded() informs the user about the limits that were set with a previous call to
+ PacketSetDumpLimits().
+
+ \warning If no calls to PacketSetDumpLimits() were performed or if the dump process has no limits
+ (i.e. if the arguments of the last call to PacketSetDumpLimits() were both 0), setting sync to TRUE will
+ block the application on this call forever.
+*/
+BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync)
+{
+ DWORD BytesReturned;
+ int IsDumpEnded;
+ BOOLEAN res;
+
+ if(sync)
+ WaitForSingleObject(AdapterObject->ReadEvent, INFINITE);
+
+ res = DeviceIoControl(AdapterObject->hFile,
+ pBIOCISDUMPENDED,
+ NULL,
+ 0,
+ &IsDumpEnded,
+ 4,
+ &BytesReturned,
+ NULL);
+
+ if(res == FALSE) return TRUE; // If the IOCTL returns an error we consider the dump finished
+
+ return (BOOLEAN)IsDumpEnded;
+}
+
+/*!
+ \brief Returns the notification event associated with the read calls on an adapter.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \return The handle of the event that the driver signals when some data is available in the kernel buffer.
+
+ The event returned by this function is signaled by the driver if:
+ - The adapter pointed by AdapterObject is in capture mode and an amount of data greater or equal
+ than the one set with the PacketSetMinToCopy() function is received from the network.
+ - the adapter pointed by AdapterObject is in capture mode, no data has been received from the network
+ but the the timeout set with the PacketSetReadTimeout() function has elapsed.
+ - the adapter pointed by AdapterObject is in statics mode and the the timeout set with the
+ PacketSetReadTimeout() function has elapsed. This means that a new statistic sample is available.
+
+ In every case, a call to PacketReceivePacket() will return immediately.
+ The event can be passed to standard Win32 functions (like WaitForSingleObject or WaitForMultipleObjects)
+ to wait until the driver's buffer contains some data. It is particularly useful in GUI applications that
+ need to wait concurrently on several events.
+
+*/
HANDLE PacketGetReadEvent(LPADAPTER AdapterObject)
{
return AdapterObject->ReadEvent;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Sets the number of times a single packet written with PacketSendPacket() will be repeated on the network.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param nwrites Number of copies of a packet that will be physically sent by the interface.
+ \return If the function succeeds, the return value is nonzero.
+ See PacketSendPacket() for details.
+*/
BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)
{
DWORD BytesReturned;
return DeviceIoControl(AdapterObject->hFile,pBIOCSWRITEREP,&nwrites,4,NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Sets the timeout after which a read on an adapter returns.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param timeout indicates the timeout, in milliseconds, after which a call to PacketReceivePacket() on
+ the adapter pointed by AdapterObject will be released, also if no packets have been captured by the driver.
+ Setting timeout to 0 means no timeout, i.e. PacketReceivePacket() never returns if no packet arrives.
+ A timeout of -1 causes PacketReceivePacket() to always return immediately.
+ \return If the function succeeds, the return value is nonzero.
+
+ \note This function works also if the adapter is working in statistics mode, and can be used to set the
+ time interval between two statistic reports.
+*/
BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)
{
DWORD BytesReturned;
return DeviceIoControl(AdapterObject->hFile,pBIOCSRTIMEOUT,&DriverTimeOut,4,NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Sets the size of the kernel-level buffer associated with a capture.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param dim New size of the buffer, in \b kilobytes.
+ \return The function returns TRUE if successfully completed, FALSE if there is not enough memory to
+ allocate the new buffer.
+
+ When a new dimension is set, the data in the old buffer is discarded and the packets stored in it are
+ lost.
+
+ Note: the dimension of the kernel buffer affects heavily the performances of the capture process.
+ An adequate buffer in the driver is able to keep the packets while the application is busy, compensating
+ the delays of the application and avoiding the loss of packets during bursts or high network activity.
+ The buffer size is set to 0 when an instance of the driver is opened: the programmer should remember to
+ set it to a proper value. As an example, wpcap sets the buffer size to 1MB at the beginning of a capture.
+*/
BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim)
{
DWORD BytesReturned;
return DeviceIoControl(AdapterObject->hFile,pBIOCSETBUFFERSIZE,&dim,4,NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Sets a kernel-level packet filter.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param fp Pointer to a filtering program that will be associated with this capture or monitoring
+ instance and that will be executed on every incoming packet.
+ \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 by the driver. The driver performs
+ the check in order to avoid system crashes due to buggy or malicious filters, and it rejects non
+ conformat filters.
+
+ This function associates a new BPF filter to the adapter AdapterObject. The filter, pointed by fp, is a
+ set of bpf_insn instructions.
+
+ A filter can be automatically created by using the pcap_compile() function of wpcap. This function
+ converts a human readable text expression with the syntax of WinDump (see the manual of WinDump at
+ http://netgroup.polito.it/windump for details) into a BPF program. If your program doesn't link wpcap, but
+ you need to know the code of a particular filter, you can launch WinDump with the -d or -dd or -ddd
+ flags to obtain the pseudocode.
+
+*/
BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp)
{
DWORD BytesReturned;
return DeviceIoControl(AdapterObject->hFile,pBIOCSETF,(char*)fp->bf_insns,fp->bf_len*sizeof(struct bpf_insn),NULL,0,&BytesReturned,NULL);
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Returns a couple of statistic values about the current capture session.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param s Pointer to a user provided bpf_stat structure that will be filled by the function.
+ \return If the function succeeds, the return value is nonzero.
+
+ With this function, the programmer can know the value of two internal variables of the driver:
+ - the number of packets that have been received by the adapter AdapterObject, starting at the
+ time in which it was opened with PacketOpenAdapter.
+ - the number of packets that have been dropped by the driver. A packet is dropped when the kernel
+ buffer associated with the adapter is full.
+*/
BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s)
{
+ BOOLEAN Res;
DWORD BytesReturned;
- return DeviceIoControl(AdapterObject->hFile,pBIOCGSTATS,NULL,0,s,sizeof(struct bpf_stat),&BytesReturned,NULL);
+ struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications
+
+ Res = DeviceIoControl(AdapterObject->hFile,
+ pBIOCGSTATS,
+ NULL,
+ 0,
+ &tmpstat,
+ sizeof(struct bpf_stat),
+ &BytesReturned,
+ NULL);
+
+ // Copy only the first two values retrieved from the driver
+ s->bs_recv = tmpstat.bs_recv;
+ s->bs_drop = tmpstat.bs_drop;
+
+ return Res;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Returns statistic values about the current capture session. Enhanced version of PacketGetStats().
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param s Pointer to a user provided bpf_stat structure that will be filled by the function.
+ \return If the function succeeds, the return value is nonzero.
+
+ With this function, the programmer can retireve the sname values provided by PacketGetStats(), plus:
+
+ - the number of drops by interface (not yet supported, always 0).
+ - the number of packets that reached the application, i.e that were accepted by the kernel filter and
+ that fitted in the kernel buffer.
+*/
+BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s)
+{
+ BOOLEAN Res;
+ DWORD BytesReturned;
+ struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications
+
+ Res = DeviceIoControl(AdapterObject->hFile,
+ pBIOCGSTATS,
+ NULL,
+ 0,
+ &tmpstat,
+ sizeof(struct bpf_stat),
+ &BytesReturned,
+ NULL);
+
+ s->bs_recv = tmpstat.bs_recv;
+ s->bs_drop = tmpstat.bs_drop;
+ s->ps_ifdrop = tmpstat.ps_ifdrop;
+ s->bs_capt = tmpstat.bs_capt;
+
+ return Res;
+}
+/*!
+ \brief Performs a query/set operation on an internal variable of the network card driver.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param Set Determines if the operation is a set (Set=TRUE) or a query (Set=FALSE).
+ \param OidData A pointer to a _PACKET_OID_DATA structure that contains or receives the data.
+ \return If the function succeeds, the return value is nonzero.
+
+ \note not all the network adapters implement all the query/set functions. There is a set of mandatory
+ OID functions that is granted to be present on all the adapters, and a set of facultative functions, not
+ provided by all the cards (see the Microsoft DDKs to see which functions are mandatory). If you use a
+ facultative function, be careful to enclose it in an if statement to check the result.
+*/
BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData)
{
DWORD BytesReturned;
return Result;
}
-//---------------------------------------------------------------------------
-
+/*!
+ \brief Sets a hardware filter on the incoming packets.
+ \param AdapterObject Pointer to an _ADAPTER structure.
+ \param Filter The identifier of the filter.
+ \return If the function succeeds, the return value is nonzero.
+
+ The filter defined with this filter is evaluated by the network card, at a level that is under the NPF
+ device driver. Here is a list of the most useful hardware filters (A complete list can be found in ntddndis.h):
+
+ - NDIS_PACKET_TYPE_PROMISCUOUS: sets promiscuous mode. Every incoming packet is accepted by the adapter.
+ - NDIS_PACKET_TYPE_DIRECTED: only packets directed to the workstation's adapter are accepted.
+ - NDIS_PACKET_TYPE_BROADCAST: only broadcast packets are accepted.
+ - NDIS_PACKET_TYPE_MULTICAST: only multicast packets belonging to groups of which this adapter is a member are accepted.
+ - NDIS_PACKET_TYPE_ALL_MULTICAST: every multicast packet is accepted.
+ - NDIS_PACKET_TYPE_ALL_LOCAL: all local packets, i.e. NDIS_PACKET_TYPE_DIRECTED + NDIS_PACKET_TYPE_BROADCAST + NDIS_PACKET_TYPE_MULTICAST
+*/
BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter)
{
BOOLEAN Status;
return Status;
}
-//---------------------------------------------------------------------------
-
-BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize)
+/*!
+ \brief Retrieve the list of available network adapters and their description.
+ \param pStr User allocated string that will be filled with the names of the adapters.
+ \param BufferSize Length of the buffer pointed by pStr.
+ \return If the function succeeds, the return value is nonzero.
+
+ Usually, this is the first function that should be used to communicate with the driver.
+ It returns the names of the adapters installed on the system <B>and supported by WinPcap</B>.
+ After the names of the adapters, pStr contains a string that describes each of them.
+
+ \b Warning:
+ the result of this function is obtained querying the registry, therefore the format
+ of the result in Windows NTx is different from the one in Windows 9x. Windows 9x uses the ASCII
+ encoding method to store a string, while Windows NTx uses UNICODE. After a call to PacketGetAdapterNames
+ in Windows 95x, pStr contains, in succession:
+ - a variable number of ASCII strings, each with the names of an adapter, separated by a "\0"
+ - a double "\0"
+ - a number of ASCII strings, each with the description of an adapter, separated by a "\0". The number
+ of descriptions is the same of the one of names. The fisrt description corresponds to the first name, and
+ so on.
+ - a double "\0".
+
+ In Windows NTx, pStr contains: the names of the adapters, in UNICODE format, separated by a single UNICODE "\0" (i.e. 2 ASCII "\0"), a double UNICODE "\0", followed by the descriptions of the adapters, in ASCII format, separated by a single ASCII "\0" . The string is terminated by a double ASCII "\0".
+ - a variable number of UNICODE strings, each with the names of an adapter, separated by a UNICODE "\0"
+ - a double UNICODE "\0"
+ - a number of ASCII strings, each with the description of an adapter, separated by an ASCII "\0".
+ - a double ASCII "\0".
+*/
+
+BOOLEAN PacketGetAdapterNames(PTSTR pStr, PULONG BufferSize)
{
- HKEY LinkageKey,AdapKey;
- DWORD RegKeySize=0;
+ HKEY LinkageKey, AdapKey;
+ DWORD RegKeySize = 0;
LONG Status;
ULONG Result;
PTSTR BpStr;
- char *TTpStr,*DpStr,*DescBuf;
+ char *TTpStr;
+ char *DpStr;
+ char *DescBuf;
LPADAPTER adapter;
- PPACKET_OID_DATA OidData;
- int i=0,k,rewind;
+ PPACKET_OID_DATA OidData;
+ int i = 0, k, rewind;
DWORD dim;
TCHAR AdapName[256];
ODSEx("PacketGetAdapterNames: BufferSize=%d\n",*BufferSize);
- OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,512);
+ OidData = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 512);
if (OidData == NULL) {
ODS("PacketGetAdapterNames: GlobalAlloc Failed\n");
return FALSE;
}
- Status=RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"),
- 0,
- KEY_READ,
- &AdapKey);
+ Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"),
+ 0, KEY_READ, &AdapKey);
// Get the size to allocate for the original device names
- while((Result=RegEnumKey(AdapKey,i,AdapName,sizeof(AdapName)/2))==ERROR_SUCCESS)
- {
- Status=RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey);
- Status=RegOpenKeyEx(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey);
- Status=RegQueryValueEx(LinkageKey,L"Export",NULL,NULL,NULL,&dim);
+ while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) {
+ Status = RegOpenKeyEx(AdapKey, AdapName,0, KEY_READ, &LinkageKey);
+ Status = RegOpenKeyExW(LinkageKey, L"Linkage",0, KEY_READ, &LinkageKey);
+ Status = RegQueryValueExW(LinkageKey, L"Export", NULL, NULL, NULL, &dim);
i++;
- if(Status!=ERROR_SUCCESS) continue;
- RegKeySize+=dim;
+ if (Status!=ERROR_SUCCESS) continue;
+ RegKeySize += dim;
}
// Allocate the memory for the original device names
ODSEx("Need %d bytes for the names\n", RegKeySize+2);
- BpStr=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,RegKeySize+2);
+ BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize+2);
if (BpStr == NULL || RegKeySize > *BufferSize) {
ODS("PacketGetAdapterNames: GlobalAlloc Failed\n");
GlobalFreePtr(OidData);
return FALSE;
}
-
- k=0;
- i=0;
+ k = 0;
+ i = 0;
ODS("PacketGetAdapterNames: Cycling through the adapters:\n");
// Copy the names to the buffer
- while((Result=RegEnumKey(AdapKey,i,AdapName,sizeof(AdapName)/2))==ERROR_SUCCESS)
- {
+ while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) {
WCHAR UpperBindStr[64];
i++;
ODSEx(" %d) ", i);
- Status=RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey);
- Status=RegOpenKeyEx(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey);
+ Status = RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey);
+ Status = RegOpenKeyExW(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey);
dim=sizeof(UpperBindStr);
- Status=RegQueryValueEx(LinkageKey,L"UpperBind",NULL,NULL,(PUCHAR)UpperBindStr,&dim);
+ Status=RegQueryValueExW(LinkageKey,L"UpperBind",NULL,NULL,(PUCHAR)UpperBindStr,&dim);
ODSEx("UpperBind=%S ", UpperBindStr);
}
dim=RegKeySize-k;
- Status=RegQueryValueEx(LinkageKey,L"Export",NULL,NULL,(LPBYTE)BpStr+k,&dim);
+ Status=RegQueryValueExW(LinkageKey,L"Export",NULL,NULL,(LPBYTE)BpStr+k,&dim);
if(Status!=ERROR_SUCCESS){
ODS("Name = SKIPPED (error reading the key)\n");
continue;
// Create the device name
rewind=k;
memcpy(pStr+k,BpStr+i,16);
- memcpy(pStr+k+8,TEXT("Packet_"),14);
+ memcpy(pStr+k+8,TEXT("NPF_"),8);
i+=8;
- k+=15;
+ k+=12;
while(BpStr[i-1]!=0){
pStr[k++]=BpStr[i++];
}
PacketCloseAdapter(adapter);
}
- *DpStr=0;
+ *DpStr = 0;
- pStr[k++]=0;
- pStr[k]=0;
+ pStr[k++] = 0;
+ pStr[k] = 0;
- if((ULONG)(DpStr-DescBuf+k) < *BufferSize)
- memcpy(pStr+k,DescBuf,DpStr-DescBuf);
- else{
+ if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) {
+ memcpy(pStr + k, DescBuf, DpStr - DescBuf);
+ } else {
GlobalFreePtr(OidData);
- GlobalFreePtr (BpStr);
- GlobalFreePtr (DescBuf);
+ GlobalFreePtr(BpStr);
+ GlobalFreePtr(DescBuf);
ODS("\nPacketGetAdapterNames: ended with failure\n");
return FALSE;
}
GlobalFreePtr(OidData);
- GlobalFreePtr (BpStr);
- GlobalFreePtr (DescBuf);
+ GlobalFreePtr(BpStr);
+ GlobalFreePtr(DescBuf);
ODS("\nPacketGetAdapterNames: ended correctly\n");
return TRUE;
}
else{
- DWORD RegType;
-
- ODS("Adapters not found under SYSTEM\\CurrentControlSet\\Control\\Class. Using the TCP/IP bindings.\n");
+ DWORD RegType;
- GlobalFreePtr (BpStr);
+ ODS("Adapters not found under SYSTEM\\ControlSet001\\Control\\Class. Using the TCP/IP bindings.\n");
- Status=RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"),0,KEY_READ,&LinkageKey);
- if (Status == ERROR_SUCCESS)
- {
+ GlobalFreePtr(BpStr);
+ Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage"),
+ 0, KEY_READ, &LinkageKey);
+ if (Status == ERROR_SUCCESS) {
// Retrieve the length of the key
- Status=RegQueryValueEx(LinkageKey,TEXT("bind"),NULL,&RegType,NULL,&RegKeySize);
+ Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, NULL, &RegKeySize);
// Allocate the buffer
- BpStr=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,RegKeySize+2);
+ BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize + 2);
if (BpStr == NULL || RegKeySize > *BufferSize) {
GlobalFreePtr(OidData);
return FALSE;
}
- Status=RegQueryValueEx(LinkageKey,TEXT("bind"),NULL,&RegType,(LPBYTE)BpStr,&RegKeySize);
+ Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, (LPBYTE)BpStr, &RegKeySize);
RegCloseKey(LinkageKey);
+ } else {
+ //ODS("SYSTEM\\ControlSet001\\Control\\Class - RegKey not found.\n");
+ ODS("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage - RegKey not found.\n");
}
-
- if (Status==ERROR_SUCCESS){
-
- DescBuf=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096);
+ if (Status == ERROR_SUCCESS) {
+ DescBuf = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096);
if (DescBuf == NULL) {
- GlobalFreePtr (BpStr);
+ GlobalFreePtr(BpStr);
GlobalFreePtr(OidData);
return FALSE;
}
- DpStr=DescBuf;
-
- for(i=0,k=0;BpStr[i]!=0 || BpStr[i+1]!=0;){
-
- if(k+wcslen(BpStr+i)+30 > *BufferSize){
+ DpStr = DescBuf;
+ for (i = 0, k = 0; BpStr[i] != 0 || BpStr[i+1] != 0; ) {
+ if (k + wcslen(BpStr + i) + 30 > *BufferSize) {
// Input buffer too small
GlobalFreePtr(OidData);
- GlobalFreePtr (BpStr);
- GlobalFreePtr (DescBuf);
+ GlobalFreePtr(BpStr);
+ GlobalFreePtr(DescBuf);
return FALSE;
}
-
+
+ ODS("\tCreating a device name - started.\n");
+
// Create the device name
- rewind=k;
- memcpy(pStr+k,BpStr+i,16);
- memcpy(pStr+k+8,TEXT("Packet_"),14);
- i+=8;
- k+=15;
- while(BpStr[i-1]!=0){
- pStr[k++]=BpStr[i++];
+ rewind = k;
+ memcpy(pStr + k,BpStr + i,16);
+ memcpy(pStr + k + 8, TEXT("NPF_"), 8);
+ i += 8;
+ k += 12;
+ while (BpStr[i - 1] != 0) {
+ pStr[k++] = BpStr[i++];
}
-
// Open the adapter
- adapter=PacketOpenAdapter(pStr+rewind);
- if(adapter==NULL){
- k=rewind;
+ adapter = PacketOpenAdapter(pStr+rewind);
+ if (adapter == NULL) {
+ k = rewind;
continue;
}
-
// Retrieve the description
OidData->Oid = OID_GEN_VENDOR_DESCRIPTION;
OidData->Length = 256;
- Status = PacketRequest(adapter,FALSE,OidData);
- if(Status==0 || ((char*)OidData->Data)[0]==0){
- k=rewind;
+ Status = PacketRequest(adapter, FALSE, OidData);
+ if (Status == 0 || ((char*)OidData->Data)[0] == 0) {
+ k = rewind;
+ ODS("\tCreating a device name - Retrieve the description.\n");
continue;
}
// Copy the description
- TTpStr=(char*)(OidData->Data);
- while(*TTpStr!=0){
- *DpStr++=*TTpStr++;
+ TTpStr = (char*)(OidData->Data);
+ while (*TTpStr != 0){
+ *DpStr++ = *TTpStr++;
}
- *DpStr++=*TTpStr++;
-
+ *DpStr++ = *TTpStr++;
// Close the adapter
PacketCloseAdapter(adapter);
-
+
+ ODS("\tCreating a device name - completed.\n");
}
- *DpStr=0;
+ *DpStr = 0;
- pStr[k++]=0;
- pStr[k]=0;
+ pStr[k++] = 0;
+ pStr[k] = 0;
- if((ULONG)(DpStr-DescBuf+k) < *BufferSize)
- memcpy(pStr+k,DescBuf,DpStr-DescBuf);
- else{
+ if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) {
+ memcpy(pStr + k, DescBuf, DpStr-DescBuf);
+ } else {
GlobalFreePtr(OidData);
- GlobalFreePtr (BpStr);
- GlobalFreePtr (DescBuf);
+ GlobalFreePtr(BpStr);
+ GlobalFreePtr(DescBuf);
return FALSE;
}
GlobalFreePtr(OidData);
- GlobalFreePtr (BpStr);
- GlobalFreePtr (DescBuf);
+ GlobalFreePtr(BpStr);
+ GlobalFreePtr(DescBuf);
+ ODS("PacketGetAdapterNames() returning TRUE\n");
return TRUE;
- }
- else{
+ } else {
MessageBox(NULL,TEXT("Can not find TCP/IP bindings.\nIn order to run the packet capture driver you must install TCP/IP."),szWindowTitle,MB_OK);
- ODS("Cannot find the TCP/IP bindings");
+ ODS("Cannot find the TCP/IP bindings\n");
return FALSE;
}
}
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Returns comprehensive information the addresses of an adapter.
+ \param AdapterName String that contain _ADAPTER structure.
+ \param buffer A user allocated array of npf_if_addr that will be filled by the function.
+ \param NEntries Size of the array (in npf_if_addr).
+ \return If the function succeeds, the return value is nonzero.
+
+ This function grabs from the registry information like the IP addresses, the netmasks
+ and the broadcast addresses of an interface. The buffer passed by the user is filled with
+ npf_if_addr structures, each of which contains the data for a single address. If the buffer
+ is full, the reaming addresses are dropeed, therefore set its dimension to sizeof(npf_if_addr)
+ if you want only the first address.
+*/
BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntries)
{
} else { //Unicode
AdapterNameU = NULL;
}
- ifname = wcsrchr(AdapterName, '\\');
+ ifname = wcsrchr(AdapterName, '\\');
if (ifname == NULL)
ifname = AdapterName;
else
ifname++;
- if (wcsncmp(ifname, L"Packet_", 7) == 0)
- ifname += 7;
+ if (wcsncmp(ifname, L"NPF_", 4) == 0)
+ ifname += 4;
- if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"), 0, KEY_READ, &UnderTcpKey) == ERROR_SUCCESS)
+ if( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"),
+ 0, KEY_READ, &UnderTcpKey) == ERROR_SUCCESS)
{
- status = RegOpenKeyEx(UnderTcpKey,ifname,0,KEY_READ,&TcpIpKey);
+ status = RegOpenKeyExW(UnderTcpKey,ifname,0,KEY_READ,&TcpIpKey);
if (status != ERROR_SUCCESS) {
RegCloseKey(UnderTcpKey);
goto fail;
{
// Query the registry key with the interface's adresses
- status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet"),0,KEY_READ,&SystemKey);
+ status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\ControlSet001\\Services"),
+ 0,KEY_READ,&SystemKey);
if (status != ERROR_SUCCESS)
goto fail;
- status = RegOpenKeyEx(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
+ status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
if (status != ERROR_SUCCESS) {
RegCloseKey(SystemKey);
goto fail;
return FALSE;
}
-//---------------------------------------------------------------------------
+/*!
+ \brief Returns the IP address and the netmask of an adapter.
+ \param AdapterName String that contain _ADAPTER structure.
+ \param netp Pointer to a variable that will receive the IP address of the adapter.
+ \param maskp Pointer to a variable that will receive the netmask of the adapter.
+ \return If the function succeeds, the return value is nonzero.
+
+ \note this function is obsolete and is maintained for backward compatibility. Use PacketGetNetInfoEx() instead.
+*/
BOOLEAN PacketGetNetInfo(LPTSTR AdapterName, PULONG netp, PULONG maskp)
{
ifname = AdapterName;
else
ifname++;
- if (wcsncmp(ifname, L"Packet_", 7) == 0)
- ifname += 7;
- status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services"),0,KEY_READ,&SystemKey);
+ if (wcsncmp(ifname, L"NPF_", 4) == 0)
+ ifname += 4;
+ status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\ControlSet001\\Services"),
+ 0,KEY_READ,&SystemKey);
if (status != ERROR_SUCCESS)
goto fail;
- status = RegOpenKeyEx(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
+ status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
if (status != ERROR_SUCCESS) {
RegCloseKey(SystemKey);
goto fail;
free(AdapterNameU);
return FALSE;
}
+
+/* @} */