博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
libpcap的安装问题
阅读量:6659 次
发布时间:2019-06-25

本文共 4856 字,大约阅读时间需要 16 分钟。

hot3.png

由于最近要做的项目要用到mOS,装mOS之前要用到libpcap。

为了开发需要,我决定使用最新libpcap源码包安装。在Unix环境下安装libpcap库,需要

c编译器,flex,bison等,安装Ubuntu系统时,没有这些包。安装flex需要m4编译环境,否则会提示“GNU M4 is required”错误。
1. 安装系统依赖包
sudo apt-get install gcc libc6-dev

221445_vhlb_614348.png

sudo apt-get install m4 

221541_gX2O_614348.png

sudo apt-get install flex bison
221701_IAll_614348.png
2. 下载libpcap源码并安装
从官网http://www.tcpdump.org/下载最新的libpcap版本
cd /usr/local/src
wget http://www.tcpdump.org/release/libpcap-1.5.3.tar.gz

tar zxvf libpcap-1.5.3.tar.gz
cd libpcap-1.5.3
./configure
make
sudo make install
3. 安装开发需要用到的依赖库
sudo apt-get install libpcap-dev
4. 测试libpcap的小程序,命名为pcap_demo.c,以检验环境是否配置正确
#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 80"; /* 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);
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", dev, 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);
}
开始编译:
    gcc -g pcap_demo.c -o pcap_demo -lpcap  
开始执行
    ./pcap_demo
5. 注意的问题

5.1. 注意使用root用户来执行,或者对普通用户使用sudo来提升权限

    sudo pcap_demo

5.2. 对一些PCAP API函数要有全面地理解,并时刻更新文档,比如pcap_loop这个函数,下面是官网的man page地址

http://www.tcpdump.org/manpages/pcap.3pcap.html

5.3. 对一些函数的理解:

    pcap_loop和pcap_dispatch的区别,前者不会超时返回,而是会尽量去读取更多的包,直至发生一个错误才返回。正常返回的值是0,否则就是负值。我目前需要连续不断地抓包,所以应该使用pcap_loop。pcap_dispatch内部会调用pcap_loop。pcap_loop中的第四个参数在某些应用中很有用,但是在通常情况下被设为NULL。这种定义很有用,比如假如你想给pcap_loop的回调函数再额外传递一些参数,你可以使用u_char类型的指针(字符串),传人到回调函数中再做具体地处理。pcap_dispatch只会处理它收到的第一批包。

从pcap_loop返回后,我们应该显式调用pcap_close来关闭pcap以便释放资源。为了表示连续不间断的抓包,在pcap_loop中要尽量使用-1而不是0.关于其中回调函数的说明,里面有3个参数。第一个参数user是pcap_loop中最后一个参数,它表示某个不太重要的信息,可以忽略,第二个参数是包头信息,含有包的时间戳和长度,第三个参数是包的数据,从链路层头开始,它在该回调函数中并不会被释放,但是当该回调返回时不包装这些数据再合法,所以要再次使用它们,请事先复制出来。

下面再深入研究一下pcap_loop这个回调函数的定义:
首先注意函数的返回值是void类型,这完全符合逻辑,因为pcap_loop根本不知道如何处理回调函数的返回值,就是给他传出返回值也没有意义。然后就是回调函数的第一个参数对应pcap_loop中的最后一个参数,不管你给pcap_loop的最后一个参数传递什么值,当回调函数被调用时,它都会作为第一个参数传递给回调函数,第二个参数是pcap头,它包含一些信息:抓包时间,包多大,等等,这个结构在pcap.h中定义,如下:
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_next()函数。pcap_next()表示只抓取一个数据包,它的第一个参数是session handle,第二个参数是包头,返回值是包数据。函数原型如下:
u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
另一种循环抓包的方法,就是使用pcap_loop和回调函数,代码样例参见我整理出的两个例子。
5.4. 网卡设备的设置有两种方法,第一种方法是用户直接指定网卡名称(必须要真实可用),从命令行参数传递进去,比如
#include <stdio.h>
#include <pcap.h>
int main(int argc, char *argv[])
{
char *dev = argv[1];
printf("Device: %s\n", dev);
return(0);
}
另一种方法,是让pcap自己去探测网卡设备,如果出错,会给出出错信息,但是这种方法很多情况下不靠谱,对此的改进是,让pcap探测出所有的网卡设备,让用户区选择使用那个网络设备抓包,参见下面的代码
#include <stdio.h>
#include <pcap.h>
int main(int argc, char *argv[])
{
char *dev, errbuf[PCAP_ERRBUF_SIZE];
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
return(2);
}
printf("Device: %s\n", dev);
return(0);
}
5.5.对我们抓到的数据包,它的结构,大体分为Ethernet header,IP header,TCP header等等,分别对应14,20,20个字节,IP header至少20个字节,TCP头也至少20个字节。
data=recv_data[42:]这样做的原因是,recv_data 抓到的都是raw packet, tcp/ip是分了5层,一个udp包,会带有14Bytes的Ethenet_II Frame的头,然后是20个字节的ip包头,而udp包头有8个字节,所以偏移量42之后的才是udp的实际内容。tcp包的包头大小为20Bytes,所以其实际内容在偏移量54之后。
5.6.对数据包的解包和组包,需要用到Ethernet header,IP header,TCP header,UDP header等常用数据结构的定义,我们并不需要重新定义这些头,直接引用相关的头文件定义就可以了。
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h> 
5.6.对我们目前的程序,通常需要从命令行传人如下参数信息:
wlan0             待抓包的网卡名称
tcp port 80    过滤表达式
10000 or -1   抓包模式,是抓指定个数的包(这里是10000个包),还是无限抓包下去
当然,对这些参数,你也可以写死在程序里。

转载于:https://my.oschina.net/wangsifangyuan/blog/994033

你可能感兴趣的文章
SpringMVC跨域接收JSON
查看>>
小议高清视频会议普及
查看>>
vcc编译器的报错
查看>>
2014总结
查看>>
简单的I2C协议理解
查看>>
session写入到memcache
查看>>
Hadoop (CDH4发行版)集群部署 (部署脚本,namenode高可用,hadoop管理)
查看>>
手机运维
查看>>
安装PHP7,Apach2.4
查看>>
如何安装win8的最好方法和优缺点
查看>>
Predicting Running Time of Grid Tasks based on CPU Load Predictions
查看>>
蜜月圣地之二
查看>>
win7 64位导入证书时,窗口变成未响应解决办法
查看>>
看PHP未来5年的发展
查看>>
Mac OSX操作系统安装和配置Zend Server 6教程(1)
查看>>
手动编译httpd
查看>>
SQLSERVER存储过程基本语法
查看>>
RSA知识整理
查看>>
14.12.2类的特殊成员2
查看>>
Windows下重新安装mysql
查看>>