一个简单的抓ARP包程序分析

##########################################################################
2014-02-10
参考网上找到的实例编译一个简单的抓取arp包并从中提取显示源、目的mac、ip地址的代码时遇到出错
源代码如下(这部分直接复的就不排版了,将就看一下):

#include <pcap.h> 
#include <stdlib.h>
#include <string.h>
//ARP Header, (assuming Ethernet+ipv4)
#define ARP_REQUEST 1
#define ARP_REPLY 2
typedef struct arphdr{
u_int16_t htype; //hardware type
u_int16_t ptype; //protocol type
u_char hlen;   //hardware address length
u_char plen;   //protocol address length
u_int16_t oper;  //operation code
u_char sha[6];    //sender hardware address
u_char spa[4];    //sender ip address
u_char tha[6];    //target hardware address
u_char tpa[4];    //target ip address
}arphdr_t;
#define MAXBYTES2CAPTURE 2048
int main(int argc, char *argv[])
{
int i=0;
bpf_u_int32 netaddr=0, mask=0;
struct bpf_program filter;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *descr = NULL;
struct pcap_pkthdr pkthdr;
const unsigned char *packet = NULL;
arphdr_t *arpheader = NULL;
memset(errbuf, 0, PCAP_ERRBUF_SIZE);
if (argc != 2){
printf("Usage: arpsniffer <interface> \n");
exit(1);
} 
descr = pcap_open_live(argv[1], MAXBYTES2CAPTURE, 0,
512, errbuf); 
pcap_lookupnet(argv[1], &netaddr, &mask, errbuf);
pcap_compile(descr, &filter, "arp", 1, mask);
pcap_setfilter(descr, &filter);
while (1){
packet = pcap_next(descr, &pkthdr);
arpheader = (struct arphdr *)(packet + 14)
printf("\n\nReceived Packet Size: %d bytes\n",pkthdr->len);
printf("Hardware type: %s\n", (ntohs(arpheader->htype) == 1)?"Ethernet" : "Unknown");
printf("Protocol type: %s\n", (ntohs(arpheader->ptype) == 0x0800) ? "Ethernet" : "Unknown");
printf("Operation: %s\n", (ntohs(arpheader->oper) == ARP_REQUEST) ?"ARP Request" : "ARP Reply");
if (ntohs(arpheader->htype) == 1 && ntohs(arpheader->ptype) == 0x0800)
{
printf("Sender MAC: ");
for (i=0; i<6; i++)printf("%02x:", arpheader->sha[i]);
printf("\nSender IP: ");
for (i=0; i<4; i++)printf("%d.", arpheader ->spa[i]);
printf("\nTarget MAC: ");
for (i=0; i<6; i++)printf("%02x:", arpheader->tha[i]);
printf("\nTarget IP: ");
for (i=0; i<4; i++)printf("%d.", arpheader ->tpa[i]);
printf("\n");
}
}
return 0;
}


 

第一次编译不通过,由错误信息可以找到,pkthdr应该是一个对象而不是指针,因此上面
printf("\n\nReceived Packet Size: %d bytes\n",pkthdr->len);
一行应该改为:
printf("\n\nReceived Packet Size: %d bytes\n",pkthdr.len);

第二次编译通过,不过在运行时显示
Segmentation fault (core dumped)
经调试,packet在调用了packet_next()函数后得到的返回值是NULL。
这次的问题出在了pcap_open_live()函数的参数to_ms中,由于被设成了512,而通过man pacp_next可以看到pcap_next() reads the next packet (by calling pcap_dispatch() with the cnt of 1),可以看出pcap_next()函数实际上是调用了pcap_dispatch()函数,并令其cnt参数为1,但是在pcap_dispatch()函数中需要有回调函数的函数指针作为参数,个人认为是在pcap_next()里又再定义了一个作为处理包的回调函数,没翻过代码,纯属猜测,而pcap_dispatch()函数是受到超时值限制的,因此当512ms过去后仍没有抓到arp包,pcap_dispatch()函数就返回,其定义并传入回调函数中的pcap_pkthdr结构体也无法得到填充,而用户定义的通过pcap_next()函数传入的pcap_pkthdr结构体也自然没有得到初始化,此时再对其成员进行引用,就会出现段错误了。
解决方法是将to_ms参数值设置为0,这样就会一直阻塞直到抓到arp包。

最后,其实第二次调试时还犯了一个错误,直接定义了一个pcap_pkthdr结构体的指针并把它传给了pcap_next()函数,理论上是没错的,但是实际上我定义的这个指针并没有分配到实际的内存,到真正抓到包要对其成员赋值时,就又出现段错误了,两个错误混在一起足足弄了我半天。引以为戒啊。

附上最后的代码:

#include <pcap.h>
#include <stdlib.h>
#include <string.h>

#define ARP_REQUEST 1
#define ARP_REPLY 2
#define MAXBYTES2CAPTURE 2048

typedef struct arphdr
{
	u_int16_t htype;
	u_int16_t ptype;
	u_char hlen;
	u_char plen;
	u_int16_t oper;
	u_char sha[6];
	u_char spa[4];
	u_char tha[6];
	u_char tpa[4];
}arphdr_t;

int main()
{
	int i=0;
	char *dev;
	bpf_u_int32 netaddr=0,mask=0;
	struct bpf_program filter;
	char errbuf[PCAP_ERRBUF_SIZE];
	pcap_t *descr;
	struct pcap_pkthdr pkthdr;
	const unsigned char *packet;
	arphdr_t *arpheader=NULL;
	memset(errbuf, 0, PCAP_ERRBUF_SIZE);
	if((dev=pcap_lookupdev(errbuf)) == NULL)
	{
		printf("pcap_lookupdev(): %s\n",errbuf);
		exit(1);
	}
	else
		printf("found device: %s\n",dev);
	if((descr=pcap_open_live(dev, MAXBYTES2CAPTURE, 1, 0, errbuf)) == NULL)
	{
		printf("pcap_open_live(): %s\n",errbuf);
		exit(1);
	}
	else
		printf("Open device success\n");
	if((i=pcap_lookupnet(dev, &netaddr, &mask, errbuf)) == -1)
	{
		printf("pcap_lookupnet(): %s\n",errbuf);
		exit(1);
	}
	else
		printf("Lookupnet success\n");
	i=0;
	if((i=pcap_compile(descr, &filter, "arp", 1, mask)) == -1)
	{
		printf("Compile error\n");
		exit(1);
	}
	else
		printf("Compile success\n");
	i=0;
	if((i=pcap_setfilter(descr, &filter)) == -1)
	{
		printf("Setfilter error\n");
		exit(1);
	}
	else
		printf("Setfilter success\n");
	while(1)
	{
		if((packet=pcap_next(descr, &pkthdr)) == NULL)
		{
			printf("pcap_next() error\n");
			exit(1);
		}
		printf("Received Packet Size: %d bytes\n",pkthdr.len);
		arpheader=(struct arphdr *)(packet+14);
		printf("Hardware type: %s\n",(ntohs(arpheader->htype) == 1)?"Ethernet":"Unknown");
		printf("Protocol type: %s\n",(ntohs(arpheader->ptype) == 0x0800)?"Ethernet":"Unknown");
		printf("Operation: %s\n",(ntohs(arpheader->oper) == ARP_REQUEST)?"ARP Request":"ARP Reply");
		if(ntohs(arpheader->htype) == 1 && ntohs(arpheader->ptype) == 0x0800)
		{
			printf("Sender MAC: ");
			for(i=0; i<6; i++)
				printf("%02x:",arpheader->sha[i]);
			printf("\nSender IP: ");
			for(i=0; i<4; i++)
				printf("%d.",arpheader->spa[i]);
			printf("\nTarget MAC: ");
			for(i=0; i<6; i++)
				printf("%02x:",arpheader->tha[i]);
			printf("\nTarget IP: ");
			for(i=0; i<4; i++)
				printf("%d.",arpheader->tpa[i]);
			printf("\n");
		}
	}
	return 0;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值