下面就开始抓包了
在前面获取了网口之后(或者不需要或者直接设定),需要打开:
pcap_t *
pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf)
这个函数打开设备,然后返回一个pcap_t类型的指针,实际上就是获得用来捕获网络数据包的描述符
source是pcap_lookupdev返回的设备,或者我们直接设定
snaplen是对于每个数据包,捕获的最大字节数
promisc表示是否网口设置为混杂模式,0表示非混杂模式,其他值表示混杂模式
to_ms表示指定了超时的时间,单位毫秒
errbuf在函数出错的时候存放错误信息
下面的函数是只要收到一个数据包后就会立即返回
const u_char *
pcap_next(pcap_t *p, struct pcap_pkthdr *h)
参数p就是上面pcap_open_live返回的pcap_t类型的指针
参数h是用来保存收到的第一个数据包的pcap_pkthdr类型的指针,结构体如下:
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) */
};
表示捕获到的数据包的一些基本信息,时间戳和长度,这里有两个长度的确有点疑惑,同事有福的解释:
pcap_pkthdr表示的是当前包的信息,caplen表示的是当前包的data的长度,len表示包的原来长度,大多数情况下这两个长度的值是一样的,但是,当来了一个超长包,比如10000bytes,而我们在pcap_open_live中设定的snaplen只有1000, 那么caplen就是1000, len就是10000, 剩下的9000就被libpcap给截断了。这种情况下需要注意的是后续包的处理中如果使用ip头部的iplen做为偏移量来移动指针,那么可能会越界,需要做严格的长度检查。
释放网络接口
void
pcap_close(pcap_t *p)
将pcap_t的接口描述符关闭,并释放资源
因此,可以写一个,只要抓到一个包就立即返回的例子:
[lihui@master work]$ cat devices.c
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
int main(){
char ebuf[PCAP_ERRBUF_SIZE];
char *device = NULL;
int promisc = 1;
int snaplen = 65535;
int to_ms = 0;
device = pcap_lookupdev(ebuf);
if (device)
printf(“Now: %s is found!\n”, device);
else {
printf(“Error: pcap_lookupdev %s\n”, ebuf);
exit(1);
}
pcap_t* p = pcap_open_live(device, snaplen, promisc, to_ms, ebuf);
if (!p){
printf(“Error: pcap_open_live %s\n”, ebuf);
exit(1);
}
struct pcap_pkthdr pkthdr;
const u_char* pktStr = pcap_next(p, &pkthdr);
if (!pktStr){
printf(“Cannot capture pkt!\n”);
exit(1);
}
printf(“Capture packet length:%d\n”, pkthdr.len);
pcap_close(p);
return 0;
}
[lihui@master work]$ gcc devices.c -lpcap
[lihui@master work]$ ./a.out
Now: eth0 is found!
Error: pcap_open_live eth0: You don’t have permission to capture on that device (socket: Operation not permitted)
[lihui@master work]$ sudo ./a.out
Now: eth0 is found!
Capture packet length:119