抓包程序入门(摘抄自tcpdump文档)

来源:互联网 发布:java制造系统 编辑:程序博客网 时间:2024/05/16 10:33
         #include <pcap.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
pcap_t *handle;/* Session handle */
char *dev;/* The device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE];/* Error string */
struct bpf_program fp;/* The compiled filter */
char filter_exp[] = "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); 用以查找到当前设备默认的设备名字,errbuf保存错误信息
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s/n", errbuf);
return(2);
}
/* Find the properties for the device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s/n", dev, errbuf);
net = 0;
mask = 0;
}
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s/n", somedev, errbuf);
return(2);
}
/* Compile and apply the filter */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s/n", filter_exp, pcap_geterr(handle));
return(2);
}
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s/n", filter_exp, pcap_geterr(handle));
return(2);
}
/* 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);
}


pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)


pcap_open_live用于创建一个sniffer句柄,返回pcap_t *类型,解释一下参数,somedev是用lookupdev
返回的默认设备名,BUFSIZ是存储抓到的包的,然后是 promisc的值,为1的话表示以混杂模式进行抓包,
为0则以非混杂模式抓包;to_ms是以ms计算的timeout时间,为0表示无timeout,一直抓到缓冲区满了
为止;最后的ebuf也是用来存储错误信息用的。

我们调用pcap_compile()来编译它,其原型是这样定义的:

int pcap_compile(pcap_t *p, strUCt bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

第 一个参数是会话句柄(pcap_t
*handle在前一节的示例中)。接下来的是我们存储被编译的过滤器版本的地址的引用。再接下来的则是表达式本身,存储在规定的字符串格式里。再下边是
一个定义表达式是否被优化的整形量(0为false,1为true,标准规定)。最后,我们必须指定应用此过滤器的网络掩码。函数返回-1为失败,其他的
任何值都表明是成功的。

表达式被编译之后就可以使用了。现在进入pcap_setfilter()。仿照我们介绍pcap的格式,先来看一看pcap_setfilter()的原型:

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)






这非常直观,第一个参数是会话句柄,第二个参数是被编译表达式版本的引用(可推测出它与pcap_compile()的第二个参数相同)。

下面的代码示例可能能使你更好的理解:

#include <pcap.h>

pcap_t *handle; /* 会话的句柄 */

char dev[] = "rl0"; /* 执行嗅探的设备 */

char errbuf[PCAP_ERRBUF_SIZE]; /* 存储错误 信息的字符串 */

struct bpf_program filter; /*已经编译好的过滤表达式*/

char filter_app[] = "port 23"; /* 过滤表达式*/

bpf_u_int32 mask; /* 执行嗅探的设备的网络掩码 */

bpf_u_int32 net; /* 执行嗅探的设备的IP地址 */

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);

这个程序使嗅探器嗅探经由端口23的所有通信,使用混杂模式,设备是rl0。

你可能注意到前面的示例包含一个我们还没提到的函数:pcap_lookupnet(),向这个函数提供设备接口名,它将返回其IP和网络掩码,这是很基本的,因为我们需要知道网络掩码以便应用过滤器。此函数在此文最后的miscellaneous一节里还有描述。

据我的经验,这个过滤器在所有的操作系统下都不会工作。在我的测试环境里,我发现OpenBSD 2.9默认内核支持这种过滤器,但FreeBSD 4.3默认内核则不支持。你的情况可能会有变化。

实际的嗅探

到此为止,我们已经学习了如何定义一个设备,让它准备嗅探,还有应用过滤器使我们嗅谈到什么或者不嗅探到什么。现在到了真正去捕获一些数据包的时候了。有
两种手段捕获包。我们可以一次只捕获一个包,也可以进入一个循环,等捕获到多个包再进行处理。我们将先看看怎样去捕获单个包,然后再看看使用循环的方法。
为此,我们使用函数pcap_next()。

Pcap_next()的原型及其简单:

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

第一个参数是会话句柄,第二个参数是指向一个包括了当前数据包总体信息(被捕获时的时间,包的长度,
其被指定的部分长度)的结构体的指针(在这里只有一个片断,只作为一个示例)。Pcap_next()返回
一个u_char指针给被这个结构体描述的包。