1, Foreword
Through the previous study, we are familiar with capturing packets from the network card. Now we will learn how to process packets. WinPcap provides us with many API s to save packets flowing through the network to a heap file and read the contents of the heap. The format of this file is very simple, but it contains the binary content of the captured datagram. This file format is also the standard of many network tools, such as WinDump, Ethereal, Snort, etc.
2, Code explanation
Save packets to file: write packets in LIBPCAP format, capture packets from the specified interface and store them in a specified file.
#include "mainwindow.h" #include <QApplication> #include <QDebug> #define HAVE_REMOTE #include "pcap.h" #ifndef WIN32 #include <sys/socket.h> #include <netinet/in.h> #else #include <winsock2.h> #include <ws2tcpip.h> #endif //Callback function prototype void packet_handler(u_char* dumpfile, const struct pcap_pkthdr* header, const u_char* pkt_data); int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t* adhandle; //Define file handle char errbuf[PCAP_ERRBUF_SIZE]; pcap_dumper_t *dumpfile; //Check whether the command line parameter has a file name if(argc != 2) { qDebug()<<"usage: %s filename"<<argv[0]; } //Get the list of native adapters if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs, errbuf) == -1) { qDebug() << "Error in pcap_findalldevs_ex: " <<errbuf; exit(1); } //Print adapter list for(d = alldevs; d; d = d->next) { //Device name qDebug()<<"Name: "<<d->name; ++i; //Device description if (d->description) { qDebug()<<"Description: "<<d->description; }else { qDebug()<<"No description available"; } qDebug()<<"===================================================================="; } if(i==0) { qDebug()<<"No interfaces found! Make sure WinPcap is installed."; return -1; } qDebug()<<QString("Enter the interface number (1-%1): ").arg(i); //scanf("%d",&inum); inum = 5; qDebug()<<"inum: "<<inum; if(inum < 1 || inum > i){ qDebug()<<"Interface number out of range."; //Release adapter list pcap_freealldevs(alldevs); return -1; } //Jump to the selected adapter for(d=alldevs,i=0; i<inum-1; d=d->next,i++); //Open adapter if((adhandle = pcap_open(d->name, //Device name 65536, //65535 packet certificate can capture all the contents of each packet on different data link layers PCAP_OPENFLAG_PROMISCUOUS, //promiscuous mode 1000, //Read timeout NULL, //Remote machine authentication errbuf //Error buffer pool )) == NULL) { qDebug()<<"Unable to open the adapter."<<QString("%1 is not support by WinPcap").arg(d->name); //Release adapter list pcap_freealldevs(alldevs); return -1; } //Open file dumpfile = pcap_dump_open(adhandle,argv[1]); if(dumpfile == NULL) { qDebug()<<stderr<<"Error opening output file"; } qDebug()<<QString("Listening on %1...").arg(d->description); //Release adapter list pcap_freealldevs(alldevs); //Loop to capture data and call packet_ The handler function stores data in a heap file pcap_loop(adhandle,0,packet_handler,(unsigned char *)dumpfile); return a.exec(); } //The callback function will be called by libpcap when each packet is received void packet_handler(u_char* dumpfile, const struct pcap_pkthdr* header, const u_char* pkt_data) { pcap_dump(dumpfile,header,pkt_data); }
The structure of the program is very similar to that of the previous example. The difference is that once the network card is opened, the program calls pcap_dump_open to open a file. This call associates the file with a network card. packet_handler() calls pcap internally_ Dump() to store the captured datagram in a file, pcap_ Parameters of dump and packer_handler(), so it is convenient to use.
Read data content from file (pcap_loop): open a heap file and print the contents of each package in it
#include "mainwindow.h" #include <QApplication> #include <QDebug> #define HAVE_REMOTE #include "pcap.h" #ifndef WIN32 #include <sys/socket.h> #include <netinet/in.h> #else #include <winsock2.h> #include <ws2tcpip.h> #endif #define LINE_LEN 16 //Callback function prototype void dispatcher_handler(u_char* temp1, const struct pcap_pkthdr* header, const u_char* pkt_data); int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); pcap_t* fp; //Define file handle char errbuf[PCAP_ERRBUF_SIZE]; //Check whether the command line parameter has a file name if(argc != 2) { qDebug()<<"usage: %s filename"<<argv[0]; } //Open a heap file that stores data if((fp = pcap_open_offline(argv[1],errbuf)) == NULL) { qDebug()<<stderr<<"Error opening dump file"; } //Read data until EOF flag is encountered pcap_loop(fp,0,dispatcher_handler,NULL); return a.exec(); } //The callback function will be called by libpcap when each packet is received void dispatcher_handler(u_char* temp1, const struct pcap_pkthdr* header, const u_char* pkt_data) { u_int i = 0; //Print timestamp and len of pkt qDebug()<<"header->ts.tv_sec: "<<header->ts.tv_sec; qDebug()<<"header->ts.tv_usec: "<<header->ts.tv_usec; qDebug()<<"header->len: "<<header->len; //Print newspaper for(int i=1; (i<header->caplen+1); ++i) { qDebug()<<"pkt_data[i-1]: "<<pkt_data[i-1]; } }
Read data content from file (pcap_next_ex): open a heap file and print the contents of each package in it
#include "mainwindow.h" #include <QApplication> #include <QDebug> #define HAVE_REMOTE #include "pcap.h" #ifndef WIN32 #include <sys/socket.h> #include <netinet/in.h> #else #include <winsock2.h> #include <ws2tcpip.h> #endif #define LINE_LEN 16 int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); pcap_t* fp; //Define file handle char errbuf[PCAP_ERRBUF_SIZE]; struct pcap_pkthdr* header; const u_char* pkt_data; u_int i = 0; int res; //Check whether the command line parameter has a file name if(argc != 2) { qDebug()<<"usage: %s filename"<<argv[0]; } //Open a heap file that stores data if((fp = pcap_open_offline(argv[1],errbuf)) == NULL) { qDebug()<<stderr<<"Error opening dump file"; } //Read data until EOF flag is encountered while((res = pcap_next_ex(fp,&header,&pkt_data)) >= 0) { //Print timestamp and len of pkt qDebug()<<"header->ts.tv_sec: "<<header->ts.tv_sec; qDebug()<<"header->ts.tv_usec: "<<header->ts.tv_usec; qDebug()<<"header->len: "<<header->len; //Print newspaper for(int i=1; (i<header->caplen+1); ++i) { qDebug()<<"pkt_data[i-1]: "<<pkt_data[i-1]; } } if(res == -1) { qDebug()<<"Error reading the packets: "<<pcap_geterr(fp); } return a.exec(); }
The latest version of WinPcap provides a further way to store packets to disk, that is, using pcap_live_dump() function, which requires three parameters:
- A file name;
- A maximum length allowed for the file;
- The maximum number of packages allowed by the file;
For these parameters, 0 means there is no maximum limit
You can call pcap at_ live_ A filter is set before dump() to define which datagrams need to be stored
pcap_live_dump() is non blocking, so it will return immediately: the stored procedure of data will proceed asynchronously until the file reaches the specified maximum length or the maximum number of datagrams.
Applications can use pcap_ live_ dump_ End() to check whether the data is stored. If the maximum length parameter and the number of datagrams you specify are 0, the operation will be blocked forever.
pcap_live_dump() and pcap_ The difference of dump () is the problem of performance from the maximum limit. pcap_live_dump() uses WinPcap NPF driver to write data to the file from the kernel level, so as to minimize the memory copy.
Obviously, these features cannot be realized under other operating systems, pcap_live_dump() is unique to WinPcap and can only be applied to Win32 environment.