Use PCAP to write your own SNIFFER program

zhaozj2021-02-16  52

Programming with Pcaptim Carstenstimcarst At Yahoo Dot Comthe Latest Version of this Document Can Be Found At http://broker.dhs.org/pcap.html

Original: http://www.tcpdump.org/pcap.htm

Translation: dangdanding@163.com

This article readers: The basic knowledge of the basic C language is needed, otherwise you can read this article unless you just want to know the basic theoretical knowledge of PCAP programming. Of course, you don't have to be a master of network programming, because this article only needs to understand people with rich network programming (the meaning is not interested or unintentional to this aspect) It doesn't matter). All code examples in this article are tested under the default kernel version BSD4.3 (I also tested under Redhat 6.2 with kernel-2.2.14-5).

Get Started: The Format of A PCAP Application

Let us first understand the common design of a PCAP application. The process of code is as follows:

1. First of all, decide to use the network interface to SNIFF. Under Linux, it may be Eth0 in BSD may be XL1, etc. We either define this device in a string (char *), or use the user to specify the device interface name used to Sniff directly in the command line.

2, initialize the PCAP. This is a place to specify a network interface used to Sniff. Of course we can swNIFF on multiple interface devices. Through the handle, we can distinguish these different SNIFF device interfaces. Just like we open a file used to read or write, we must name our Sniffer Session to distinguish these different session.

3, usually we only want SNIFF-specific network communication (such as a TCP packet, all TCP packets that send 23 ports). Usually we develop a rule set that defines a specific network communication, and compiles its (Apply to) PCAP engine. This is the most important step of writing PCAP applications, and must be closely associated. The rules are saved in a string, and the format that is converted to the PCAP engine can be identified by compiling. In fact, the so-called compilation is just that the specific function calls a specific function in our own program, does not involve any external application. Then we can tell the PCAP engine app compiled rules as our SNIFF rule (Filter).

4. Finally, we notify the PCAP engine to enter the main process: PCAP accepts and handles the numerical data packets that match the specified rules. Whenever a new packet is captured, the PCAP calls the custom callback function for the corresponding processing. You can do anything we want to do in the callback function: anatomical capture packets and print to the user console, or save it to the file, of course, you can not do anything (if you don't do anything, why should we write these Code? If ... then ..., huh, many people have begun to vomit and fainted)

5, end SNIFF and close the PCAP session handle.

In fact, it is a very simple process for programming with PCAP, a total of 5 steps, and will make you feel confused. Detailed implementation is as follows.

Setting the Device

This is an extremely simple operation (original: this is terribly Simple). There are two ways to set the network interface for SNIFF.

1. The user specifies the set of network interfaces in the command line:

#include #include int main (int Argc, char * argv []) {char * dev = argv [1]; printf ("device:% s / n", dev); Return (0);} The user passes the listening interface through the command line parameters.

Translation: The command line parameters must be judged in the actual project development:

IF (argc <2) {

Printf ("USAGE:% s

Exit (1);

}

2. Set the online interface of the listener through the PCAP engine:

#include #include int main () {char * dev, errbuf [pcap_errbuf_size]; dev = pcap_lookupdev (Errbuf); Printf ("Device:% S / N", DEV); Return (0);

In this case, the PCAP engine sets themselves to the interface used to listen. But what ERRBUF string is used? Most PCAP functions allow us to pass such a string as its parameters. This string parameter is used to set an error message after the PCAP function call failed. In the above example, if the PCAP_LOOKUP function call fails, the error message will be saved in Errbuf.

Translation: The resulting code is as follows:

IF (NULL == (dev = pcap_lookupdev (errbuf))) {

FPRINTF (stderr, "pcap_lookupdev () error:% s / n", errbuf);

EXIT (-1);

}

Printf ("Device:% S / N", DEV);

Opening the Device for Sniffe

The task for creating a Sniff session is very simple. We created a SNIFF session using PCAP_OPEN_LIVE (). Function prototype:

PCAP_T * PCAP_OPEN_LIVE (Char * Device, Int Snaplen, Int Promisc, int to_ms, char * ebuf)

Device: The listening device interface we have developed in the previous section;

Snaplen: Develop the maximum number of network packets captured by PCAP;

Promisc:> 0 Specifies the Device Interface to work in a mixed mode ("Promiscous mode);

TO_MS: Develop a specific time (MS) after reading timeout; 0 means encountering an error exit, -1 designation never timeout;

EBUF: Develop a string for storing error information

PCAP_T: The return value is a PCAP session used to listen.

Sample code:

#include ... pcap_t * handle; handle = pcap_open_live (Somedev, Bufsiz, 1, 0, Errbuf);

The above code opens the device specified by SOMEDEV and reads (capture) buffs bytes, and we set the interface to work in a mixed mode, which has been listening to any error occurred, and saved the error message in the string specified by Errbuf.

About mixed mode vs. Nonmix mode: usually listening only to data packets directly to the host in non-mixed mode: sending, or passing the packets from or through host routes will be captured by PCAP; mixed mode, all send The packets on the physical link will be captured. In a shared network environment, this will result in the data stream of the entire network being listened. The mixed monitor mode is detected: can be detected by testing strong reliability, whether there is a host in the network is listening in a mixed mode, and the mixed mode of operation is only valid in the non-cross-switching network, and in a high load network environment. In the mixed mode will consume a lot of system resources. Filter Traffic

Usually we are only interested in specific network communication. For example, we only intend to listen to the Telnet service (Port 23) to capture username and password information. It is known to be interested in FTP (Port 21) or DNS (UDP Port 53). You can set data stream filtering rules (Filter) through PCAP_COMPILE () and PCAP_SETFILTER.

Function prototype:

INT PCAP_COMPILE (PCAP_T * P, Struct BPF_PROGRAM * FP, CHAR * STR, INT OPTIMIZE, BPF_U_INT32 NETMASK)

p: means a PCAP session handle;

FP: Store rules after compilation;

STR: Filter Rules in Rule Expression Format, Filter in TCPDump;

Optimize: Develop Optimization Options: 0 False, 1 True;

Netmask: Monitor the network mask of the interface;

Return Value: -1 Indicates that the operation failed, and other values ​​were successful.

INT PCAP_SETFILTER (PCAP_T * P, Struct BPF_Program * FP)

p: means a session handle of PCAP;

FP: Indicates the compiled filtering rules;

Return Value: -1 Indicates that the operation failed, and other values ​​were successful.

Sample code:

#include ... pcap_t * handle; / * session handle * / char dev [] = "rl0"; / * device to sniff on * / char errbuf [PCAP_ERRBUF_SIZE]; / * error string * / struct bpf_program filter; / * The compiled filter expression * / char filter_app [] = "port 23"; / * The filter expression * / bpf_u_int32 mask; / * The netmask of our sniffing device * / bpf_u_int32 net; / * The IP of our sniffing device * / pcap_lookupnet (dev, & net, & mask, errbuf); handle = pcap_open_live (dev, BUFSIZ, 1, 0, errbuf); pcap_compile (handle, & filter, filter_app, 0, net); pcap_setfilter (handle, & filter); The above code device RL0 monitors all data packets sent or derived from the port 23 in the mixed mode. The PCAP_LOOKUPNET () function returns the IP address of the given interface and subnet mask.

The actual sniffing

Now let's get ready to capture the packet: There are two ways to capture the packet. Either capture a data packet that meets the condition, or enter a loop process to capture the specified number of packets and exit. First, you will find out that using PCAP_NEXT () captures a single packet at a time.

Function prototype:

U_CHAR * PCAP_NEXT (PCAP_T * P, Struct PCAP_PKTHDR * H)

P: PCAP session handle;

H: Pointer to the PCAP_PKTHDR interface, saved the universal information of the captured packet in this structure. Including: Time information, length of the packet, and the length of the header portion (the structure definition is defined later).

Return Value: Returns the U_CHAR * type pointer to the actual packet.

Code example:

#include #include int main () {pcap_t * handle; / * session handle * / char * dev; / * The device to sniff on * / char erbef [pcap_errbuf_size]; / * Error string * / struct bpf_program filter; / * The compiled filter * / char filter_app [] = "port 23"; / * The filter expression * / bpf_u_int32 mask; / * Our netmask * / bpf_u_int32 net; / * Our IP * / struct pcap_pkthdr header; / * The header that pcap gives us * / const u_char * packet; / * The actual packet * / / * Define the device * / dev = pcap_lookupdev (errbuf); / * Find the properties for the device * / PCAP_LOOKUPNET (dev, & net, & mask, errbuf); / * Open the session in promiscuous mode * / handle = pcap_open_live (dev, bufsiz, 1, 0, errbuf); / * Compile and Apply the filter * / PC AP_Compile (Handle, & Filter, Filter_App, 0, Net); PCAP_SETFILTER (Handle, & Filter); / * Grab A packet * / packet = pcap_next (handle, & header); / * Print Its length * / printf ("Jacked a packet with Length of [% d] / n ", header.len); / * and close the session * / pcap_close (handle); Return (0);} Play all the interfaces returned from PCAP_LOOKUPDEV () in mixed mode Monitor status. PCAP captures a packet of port 23 and prints the length of the package. Then call PCAP_Close () to close the PCAP session.

Of course we can use more complex and more powerful features PCAP_LOOP and PCAP_DISPATCH. Usually few Sniffer uses PCAP_NEXT, they usually use PCAP_LOOP or PCAP_DISPATCH. In order to facilitate the understanding of these two functions, you need to know the concept of the backup function.

The callback function is not a new concept, and the concept of callback functions is used in many APIs. You can define your own callback function by PCAP_LOOP or PCAP_DISPATCH. In fact, PCAP_LOOP and PCAP_DISPATCH are very similar. When PCAP captures a data package that meets the rules, two functions will call our own handlers to perform our own processing. Function prototype:

INT PCAP_LOOP (PCAP_T * P, INT CNT, PCAP_HANDLER CALLBACK, U_CHAR * USER)

P: PCAP session handle;

CNT: Defines the number of packets captured by SNIFF;

Callback: Customized callback function handle;

User: Parameters passing to the callback function, if there is no parameter, it can be set to NULL;

The usage of function PCAP_DISPATCH and PCAP_LOOP is almost the same. The unique difference between the two is handling the timeout mode (in PCAP_OPEN_LIVE () set, the timeout parameters set in PCAP_OPEN_LIVE () will work here: PCAP_LOOP will ignore the timeout parameters and PCAP_DISPATCH is in the development time A read timeout error will occur when it is. Check the help of PCAP get more information.

The prototype of the callback function:

Void got_packet (u_char * args, const struct pcap_pkthdr * header, const u_char * packet);

ARGS: The last parameter corresponding to PCAP_LOOP;

Header: Pointing the pointer to the PCAP packet header;

Packet: Pointer to Packet Packet captured by PCAP, the string of the Packet pointer points to the entire data package;

Return Value: The callback function cannot return any value.

When defining a callback function, you need to strictly follow the prototype definition, otherwise the PCAP_LOOP will not correctly call the callback function.

The definition of the PCAP_PKTHDR structure is as follows:

Struct PCAP_PKTHDR {STRUCT TIMEVAL TS; / * TIME Stamp * / BPF_U_INT32 CAPLEN; / * Length of portion present * / bpf_u_int32 Len; / * Length this packet (off wire) * /

}

How to use (handle) Packet pointer variables? The structure referred to by a Packet pointer contains a lot of properties, which is not a real string, but a collection of multiple structures (such as: a TCP / IP packet includes Ethernet head, IP header, TCP head and data A valid data load in the package). First, you need to define these structures:

/ * Ethernet header * /

...

转载请注明原文地址:https://www.9cbs.com/read-21828.html

New Post(0)