上篇文章中针对libpcap进行了理论总结,以及部分函数和结构的介绍,这里就整个数据包抓包由浅到深进行分析。
获取网络接口名字和掩码信息
#include
#include
#include
//in_addr头文件
int main(int argc,char **argv)
{
char error[PCAP_ERRBUF_SIZE];//#define PCAP_ERRBUF_SIZE 256
struct in_addr ip;
struct in_addr mask;
char *interface;
bpf_u_int32 net_ip;
bpf_u_int32 net_mask;
interface=pcap_lookupdev(error);//获取网络设备指针
if(interface==NULL)
{
printf("pcap_lookupdev error\n");
return -1;
}
printf("Network interface:%s\n",interface);
int ret=pcap_lookupnet(interface,&net_ip,&net_mask,error);//获取网络接口地址和掩码
if(ret<0)
{
printf("pcap_lookupnet error\n");
return -1;
}
ip.s_addr=net_ip;
mask.s_addr=net_mask;
printf("Interface ip:%s\n",inet_ntoa(ip));//地址输出
printf("Interface mask:%s\n",inet_ntoa(mask));//掩码输出
//获取所有接口
// typedef struct pcap_if pcap_if_t;
/*
struct pcap_if {
struct pcap_if *next;
char *name;
char *description;
struct pcap_addr *addresses;
bpf_u_int32 flags;
};
*/
pcap_if_t *p;
ret=pcap_findalldevs(&p,error);
if(ret<0)
{
printf("pcap_findalldevs error\n");
return -1;
}
while(p!=NULL)
{
printf("name:%s",p->name);
printf("\tdescription:%s\n",p->description);
p=p->next;
}
return 0;
}
执行结果:
注:代码中使用了pcap_findalldevs函数获取主机内所有可用的网络接口链表。可以看出显示中列出了4个USB接口。这是由于USB为传输协议,并不是存储协议,USB接口主要用于数据传输的,所以可以抓取到USB接口。
在获取了网络接口之后开始抓取一个数据包
#include
#include
#include
#include
int main()
{
char error[PCAP_ERRBUF_SIZE];
struct pcap_pkthdr head;
pcap_t *pcaph;//libpcap句柄
struct bpf_program bpf_filter;//过滤规则
char bpf_filter_string[]="src host 192.168.61.118";
const u_char *packet_content;//数据包内容
bpf_u_int32 mask;
bpf_u_int32 ip;
char *interface;
int ret;
interface=pcap_lookupdev(error);//返回可用设备指针
assert(interface!=NULL);
printf("interface:%s",interface);
ret=pcap_lookupnet(interface,&ip,&mask,error);//获取网络地址和掩码信息
assert(ret>=0);
pcaph=pcap_open_live(interface,1500,1,0,error);//打开网络接口
printf("%s\n",error);
assert(pcaph!=NULL);
pcap_compile(pcaph,&bpf_filter,bpf_filter_string,0,mask);//编译过滤规则
pcap_setfilter(pcaph,&bpf_filter);
packet_content=pcap_next(pcaph,&head);
printf("capture a packet from:%s\n",interface);
printf("The packet length is :%d\n",head.len);
pcap_close(pcaph);
return 0;
}
执行结果:
注意:这里可以打印error字符串输出出错的原因,该程序中后期核心转储是因为适用权限的问题,适用本代码需要有root执行权限。该段代码可以作为数据包捕获的雏形,后期整个数据包捕获都是这样的架构。
抓取多个数据包
#include
#include
#include
/*注意回调函数的定义
typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes);
*/
void packet_callback(u_char *argument,const struct pcap_pkthdr *pcap_header,const u_char *packet_content)
{
static int num=1;
printf("The %d packet is captured\n",num);
num++;
}
int main()
{
pcap_t *pcaph;
char error[PCAP_ERRBUF_SIZE];
char *interface;
struct bpf_program bpf_filter;
char bpf_filter_string[]="src host 192.168.61.118";
bpf_u_int32 mask;
bpf_u_int32 ip;
interface=pcap_lookupdev(error);
pcap_lookupnet(interface,&ip,&mask,error);
pcaph=pcap_open_live(interface,BUFSIZ,1,0,error);
pcap_compile(pcaph,&bpf_filter,bpf_filter_string,0,mask);
pcap_setfilter(pcaph,&bpf_filter);
pcap_loop(pcaph,5,packet_callback,NULL);//循环接收5个数据包
pcap_close(pcaph);
return 0;
}
运行代码:
与上一个内容类似,该段代码需要要root权限下执行,否则将会报错核心转储。另外规则的制定需要参考上一篇博文的理论基础部分。后期的分析将会深入到TCP/IP各个层去,这里面涉及各层的协议。抓取和分析,这里作为一个专题讲述。(先运行代码在主机(192.168.61.117),再使用主机(192.168.61.118)ping(192.168.61.117))