捕获数据包操作
/*pcap_test.c
编译方式:gcc pcap_test.c -o pcap_test -lpcap -lpthread
*/
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <pthread.h>
#define SNAP_LEN 65535
pcap_t *handle;
pcap_dumper_t* out_pcap;
/*
函数名称:void pcap_dump(u_char *user, struct pcap_pkthdr *h,u_char *sp)
函数功能:向调用pcap_dump_open()函数打开的文件输出一个数据包。该函数可作为pcap_dispatch()函数的回调函数。
*/
void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
int * id = (int *)arg;
pcap_dump((u_char*)out_pcap, pkthdr, packet);//写入文件
printf("id: %d\n", ++(*id));
printf("Packet length: %d\n", pkthdr->len);
printf("Number of bytes: %d\n", pkthdr->caplen);
printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
int i;
for(i=0; i<pkthdr->len; ++i)
{
printf(" %02x", packet[i]);
if( (i + 1) % 16 == 0 )
{
printf("\n");
}
}
printf("\n\n");
}
/*
函数名称:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user)
函数功能:功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。
而如果为pcap_open_live()函数指定了一个非零值的超时设置,然后调用pcap_dispatch()函数,则当超时发生时pcap_dispatch()函数会返回。
cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。
函数名称:pcap_callback(u_char* argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
函数功能:数据包处理函数, argument为用户输入参数, packet_header 为数据包的头信息, packet_content参数为数据包内容
*/
void *thr_fn1(void *arg)
{
int id = 0;
//抓取100个tcp数据包
pcap_loop(handle, 100, getPacket, (u_char*)&id);
}
int main(int argc, char **argv)
{
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
int i=0,num;
//dev = pcap_lookupdev(errbuf);//查找网络设备,返回可被pcap_open_live()函数调用的网络设备名指针
pcap_if_t *alldev, *p;
char *dev = NULL;
char filter_exp[] = "tcp";
pthread_t t1;
if(pcap_findalldevs(&alldev,errbuf)==-1) //得到所有网卡接口
{
printf("find all devices is error\n");
return 0;
}
for(p = alldev; p; p = p->next)
{
printf("%d:%s\n",++i,p->name);//网卡名称
if(p->description)
{
printf("%s\n",p->description);//网卡描述
}
if(p->flags)
{
printf("Loopback Interface\n");//flags为1是环回口
}
}
printf("please input which interface you want to use\n");
scanf("%d", &num);
if(num < 1 || num > i)
{
printf("interface is unavillible\n");
return 0;
}
p = alldev;
i = 1;
while(p && i != num)
{
p = p->next;
i++;
}
if(!p)
{
printf("not find\n");
return 0;
}
dev = p->name;
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num);
printf("Filter expression: %s\n", filter_exp);
/*pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
功能:打开网络设备,并且返回用于捕获网络数据包的数据包捕获描述字
device:网卡名称
snaplen:为pcap捕捉的最大字节数
promisc:当promisc设为true时将置指定接口为混杂模式
to_ms:是读取时的超时值,单位是毫秒(假如为0则一直嗅探直到错误发生,为-1则不确定
ebuf:入任何错误信息的字符串
*/
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* pcap_datalink(pcap_t *)
功能:检查MAC层,以确保我们处理的是以太网
DLT_EN10MB:以太网
DLT_IEEE802: IEEE802.5令牌环网
...等*/
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
/*函数名称:int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask)
函数功能:将str参数指定的字符串编译到过滤程序中。
参数说明:fp是一个bpf_program结构的指针,在pcap_compile()函数中被赋值。optimize参数控制结果代码的优化。netmask参数指定本地网络的网络掩码。
*/
if (pcap_compile(handle, &fp, filter_exp, 0, 24) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/*
函数名称:int pcap_setfilter(pcap_t p, struct bpf_program fp)
函数功能:指定一个过滤程序。
参数说明:fp参数是bpf_program结构指针,通常取自pcap_compile()函数调用。
返回值:出错时返回-1;成功时返回0
*/
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/*
函数名称:pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)
函数功能:打开用于保存捕获数据包的文件,用于写入。
参数说明:fname 参数为”-“时表示标准输出。出错时返回NULL。
p参数为调用pcap_open_offline()或pcap_open_live()函数后返回的 pcap结构指针。
fname参数指定打开的文件名。如果返回NULL,则可调用pcap_geterr()函数获取错误消 息。
*/
out_pcap = pcap_dump_open(handle,"dump.pcap");
if(!out_pcap)
{
fprintf(stderr, "Couldn't pcap_dump_open dump.pcap: %s\n", pcap_geterr(handle));
exit(EXIT_FAILURE);
}
pthread_create(&t1, NULL, thr_fn1, NULL);
pthread_join(t1, NULL);
pcap_dump_flush(out_pcap);
pcap_dump_close(out_pcap);
pcap_freecode(&fp);
pcap_close(handle);
return 0;
}
输出:
查看数据包:
libpcap读取数据包文件分析
/*pcap_read.c
编译方式:gcc pcap_read.c -o pcap_read -lpcap
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pcap.h>
void pcap_loop_callback(u_char* arg, const struct pcap_pkthdr * pkthdr,const u_char * packet)
{
int * id = (int *)arg;
printf("id: %d\n", ++(*id));
printf("Packet length: %d\n", pkthdr->len);
printf("Number of bytes: %d\n", pkthdr->caplen);
printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
int i;
for(i=0; i<pkthdr->len; ++i)
{
printf(" %02x", packet[i]);
if( (i + 1) % 16 == 0 )
{
printf("\n");
}
}
printf("\n\n");
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("please input pcapfile\n");
return -1;
}
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
char *pcap_name = argv[1];
printf("dissect file %s\n", pcap_name);
if ((handle = pcap_open_offline_with_tstamp_precision(pcap_name, PCAP_TSTAMP_PRECISION_NANO, errbuf)) == NULL) //打开文件
{
printf("%s\n", errbuf);
return -1;
}
int id = 0;
pcap_loop(handle, 101, pcap_loop_callback, (u_char *)&id);
pcap_close(handle);
return 0;
}