This article introduces a simple network Sniffer implemented by using C language and network data packet analysis and development tools. Currently, many Sniff tools are available, such as Netxray and Sniffer pro in Windows. It is very convenient to capture packets in Windows. It is common in UNIX environments such as Sniffit, Snoop, Tcpdump, and Dsniff. This section describes a simple network Sniffer implemented using C language and network data packets and analysis development tools libpcap and winpcap.
Network sniffer program diagram
First, process 1 is provided.
Figure 1 Flowchart
Network sniffer program implementation
Programming in c environment, the source code is as follows:
/* Jun 2nd, 2002 * Project for graduation qualification By lobby Team 19 */ # Include <stdio. h> # Include <conio. h> // The path must be added. The header file packet32.h must be included. # Include "... Includepacket32.h" # Include "... Includentddndis. h" # Define Max_Num_Adapter 10 // Prototypes prototype // Send packets Void PrintPackets (LPPACKET lpPacket ); // Device List Char AdapterList [Max_Num_Adapter] [1024]; // Start the main program Int main () { // Define a pointer to an ADAPTER structure device pointer LPADAPTER lpAdapter = 0; // Define a pointer to a PACKET structure package pointer LPPACKET lpPacket; Int I; DWORD dwErrorCode; DWORD dwVersion; DWORD dwWindowsMajorVersion; // Unicode strings (WinNT) WCHAR AdapterName [8192]; // list of network adapter devices WCHAR * temp, * temp1; // ASCII strings (Win9x) Char AdapterNamea [8192]; // list of network adapter devices Char * tempa, * temp1a; Int AdapterNum = 0, Open; ULONG AdapterLength; Char buffer [256000]; // buffer that holds data from the drive Struct bpf_stat stat; // Obtain the local Nic name AdapterLength = 4096; Printf ("Packet. dll test application. Library version: % sn", PacketGetVersion ()); Printf ("Adapters installed: n "); I = 0; |
The following code is used to obtain the network adapter name in different versions: The NIC names in Win9x and WinNT are implemented using ASCII and UNICODE, respectively, Therefore, you must first obtain the Local Operating System Version:
DwVersion = GetVersion (); DwWindowsMajorVersion = (DWORD) (LOBYTE (LOWORD (dwVersion ))); |
The Packet. dll function used here is PacketGetAdapterNamesPTSTR pStr, PULONG BufferSize, usually the first function that communicates with the driver and is called, It will be installed in the Local System of the returned user The name of the network adapter is placed in Buffer pStr; BufferSize is the length of the buffer:
If (! (DwVersion> = 0x80000000 & dwWindowsMajorVersion> = 4 )) { // Windows NT // Unable to find the device list If (PacketGetAdapterNames (AdapterName, & AdapterLength) = FALSE ){ Printf ("Unable to retrieve the list of the adapters! N "); Return-1; } // Find the device list Temp = AdapterName; Temp1 = AdapterName; While (* temp! = '') | (* (Temp-1 )! = '')) { If (* temp = '') { Memcpy (AdapterList [I], temp1, (temp-temp1) * 2 ); Temp1 = temp + 1; I ++; } Temp ++; } // Display the list of adapters AdapterNum = I; For (I = 0; I <AdapterNum; I ++) Wprintf (L "n % d-% sn", I + 1, AdapterList [I]); Printf ("n "); } Else // otherwise, it is windows 9x. The method for obtaining the adapter name is the same as that in WinNT { If (PacketGetAdapterNames (AdapterNamea, & AdapterLength) = FALSE ){ Printf ("Unable to retrieve the list of the adapters! N "); Return-1; } Tempa = AdapterNamea; Temp1a = AdapterNamea; While (* tempa! = '') | (* (Tempa-1 )! = '')) { If (* tempa = '') { Memcpy (AdapterList [I], temp1a, tempa-temp1a ); Temp1a = tempa + 1; I ++; } Tempa ++; } AdapterNum = I; For (I = 0; I <AdapterNum; I ++) Printf ("n % d-% sn", I + 1, AdapterList [I]); Printf ("n "); } |
The following code allows the user to select the network adapter Number of the listener:
// Select a device Do { Printf ("Select the number of the adapter to open :"); Scanf ("% d", & Open ); If (Open> AdapterNum) Printf ("nThe number must be smaller than % d", AdapterNum ); } While (Open> AdapterNum );
|
Then, open the selected device. Here, you can set it to "hybrid" mode, It can also be opened in "direct" mode. The Code is as follows:
// Open the device LpAdapter = PacketOpenAdapter (AdapterList [Open-1]); // When the device cannot be opened, the following error message is displayed: If (! LpAdapter | (lpAdapter-> hFile = INVALID_HANDLE_VALUE )) { DwErrorCode = GetLastError (); Printf ("Unable to open the adapter, Error Code: % lxn", dwErrorCode ); Return-1; } |
Set the NIC to "mixed" mode. The Code is as follows: The PacketSetHwFilterLPADAPTER AdapterObject and ULONG Filter functions are used here ), It sets a hardware filter on the incoming package. If the operation is successful, TRUE is returned. AdapterObject is the network card of the filter. Device pointer; the constant Filter of the Filter is defined in the header file ntddndis. h, including: · NDIS-PACKET-TYPE-PROMISCUOUS: sets the hybrid mode. Each incoming package will be accepted by the NIC; · NDIS-PACKET-TYPE-DIRECTED: only packets DIRECTED to the host NIC are accepted; · NDIS-PACKET-TYPE-BROADCAST: Only BROADCAST packets are accepted; · NDIS-PACKET-TYPE-MULTICAST: only receives multicast packets from the group where the host is located; · NDIS-PACKET-TYPE-ALL-MULTICAS: accept each multicast package.
// Set the network adapter in promiscuous mode // If the mixed mode fails to be set, an error is prompted: If (PacketSetHwFilter (lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS) = FALSE ){ Printf ("Warning: unable to set promiscuous mode! N "); } |
Then set the buffer of K in the driver: The function PacketSetBuffLPADAPTER AdapterObject, int dim) is used here ), It is used to set the buffer of the driver of the adapter to which the AdapterObject points. If it succeeds, TRUE is returned. Dim is the size of the new buffer, When it is set, the data in the old buffer zone will be discarded, and the stored package will also be lost. Note: whether the size of the drive buffer is set properly affects the performance of the packet capture process, The setting should ensure fast operation without packet loss. Here we set 512000 bytes.
// Set a 512 K buffer in the driver // When the buffer cannot be set, an error is prompted: If (PacketSetBuff (lpAdapter, 512000) = FALSE ){ Printf ("Unable to set the kernel buffer! N "); Return-1; }
|
PacketSetReadTimeoutLPADAPTER AdapterObject, int timeout) The function is used to set the read operation timeout value bound to the specified network adapter with AdapterObject. The timeout is measured in milliseconds, 0 indicates no timeout, When no package exists, read will not be returned.
// Set a 1 second read timeout // Set 1 second read operation timeout If (PacketSetReadTimeout (lpAdapter, 1000) = FALSE ){ Printf ("Warning: unable to set the read tiemout! N "); } |
|
Next, locate the device. The Code is as follows:
The PacketAllocatePacketVoid function is used here. a packet structure is allocated in the memory and a pointer to it is returned. However, the Buffer field of this structure is not set yet, therefore, you should call the PacketInitPacket function to initialize it.
// Allocate and initialize a packet structure that will be used // Receive the packets. // When positioning fails, an error is prompted: If (lpPacket = PacketAllocatePacket () = NULL ){ Printf ("nError: failed to allocate the LPPACKET structure ."); Return (-1 ); } |
Then, you can initialize the device and start to accept the network package:
Use the PacketInitPacketLPPACKET lpPacket, PVOID Buffer, UINT Length) function to initialize the PACKET structure. LpPacket is the pointer to be initialized. Buffer is the pointer to the Buffer that points to the data that contains the package allocated by the user. Length is the Buffer Length.
Note: The buffer zone associated with the PACKET structure stores packages intercepted by the packet capture driver. The number of packages is limited by the buffer size, the maximum buffer size is the amount of data that the application can read from the drive once. Therefore, setting a large buffer area can reduce the number of system calls and improve the interception efficiency. The value is 256 kb.
PacketInitPacket (lpPacket, (char *) buffer, 256000 ); |
Next, the main loop of packet capture:
The PacketReceivePacketLPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync) function is used to intercept a collection of packages. The parameter includes an ADAPTER structure pointer pointing to the NIC used to specify the PACKET capture, a pointer pointing to the PACKET structure used to hold the PACKET, and a flag indicating synchronous or asynchronous operations. During synchronous operations, the function locks the program. When asynchronous operations are performed, the function does not lock the program. You must call the PacketWaitPacket process to check whether the program is completed correctly. Generally, the synchronization mode is used.
// Until you have a keyboard: While (! Kbhit ()) { // Capture the packets capture package // When a packet fails to be captured, an error is prompted: If (PacketReceivePacket (lpAdapter, lpPacket, TRUE) = FALSE ){ Printf ("Error: PacketReceivePacket failed "); Return (-1 ); } // Print the data in the package and call the custom function PrintPackets) PrintPackets (lpPacket ); } |
Finally, print the statistical data. The Code is as follows:
The PacketGetStatsLPADAPTER AdapterObject function, struct bpf_star * s, is used to obtain the internal variable values of the two drivers: the number of packages received by the specified Nic starting from the PacketOpenAdapter call; and the number of packets received by the NIC but discarded by the kernel. These two values are copied to the bpf_stat structure provided by the application by the driver.
// Print the capture statistics // Obtain the statistical value // When the status cannot be read from the kernel, an error is prompted: If (PacketGetStats (lpAdapter, & stat) = FALSE ){ Printf ("Warning: unable to get stats from the kernel! N "); } // Print "XX packet capture; XX packet discard ": Else Printf ("nn % d packets received. n % d Packets lost", stat. bs_recv, stat. bs_drop );
|
The PacketFreePacket (LPPACKET lpPacket) function is used to release the structure pointed to by lpPacket:
// Release space PacketFreePacket (lpPacket ); Use the PacketCloseAdapter (LPADAPTER lpAdapter) function to release the lpAdapter structure of the ADAPTER and disable the NIC pointer: // Close the adapter and exit // Disable the device and exit PacketCloseAdapter (lpAdapter ); Return (0 ); } // The main program ends |
The code of the custom function PrintPackets used to print the datagram is not described in detail here.
Conclusion
The compilation of network sniffer aims to make everyone aware of the importance of network management, pay attention to network information security issues, and encrypt and decrypt information.