libpcap是一个与实现无关的访问操作系统所提供的分组捕获机制的分组捕获函数库,目前只支持分组的读取,当然增加一些代码之后,也可以写数据链路分组(如果有人对句话有疑问,去找已故的Richard Steven讨论吧,这是他说的:P)。
libcap支持大多数Unix系统,当然也支持Linux,而且在现在linux的发行版中都有集成,大名鼎鼎的tcpdump就用到了它。libcap大约是由25个函数组成的,我在这里只是介绍一下比较简单的使用,至于大家需要深入专研的,在自己的linux上面输入 man 3 pcap就可以了。
有一点要说明的是,libpcap是用来抓取以太网包的,至于能不能抓取ppp链路的包,我觉得是不能的,因为我看过一个在专有网络中抓包的程序,人家是专门写了一个类来读取com设备的。至于理论上为什么不行,我也很难说出个所以然来,等我哪天搞清楚了再写一篇blog好了。
好了,废话少说,Let's begin!看看我们的第一个程序。。。。
/*pcap_1.c*/
#include
#include
#include /* 如果没有pcap的系统,要自己下载一个 */
#include
#include
#include
#include
int main(int argc, char **argv)
{
char *dev; /* name of the device to use */
char *net; /* dot notation of the network address */
char *mask;/* dot notation of the network mask */
int ret; /* return code */
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 netp; /* ip */
bpf_u_int32 maskp;/* subnet mask */
struct in_addr addr;
/* ask pcap to find a valid device for use to sniff on */
dev = pcap_lookupdev(errbuf);
/* error checking */
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
/* print out device name */
printf("DEV: %s\n",dev);
/* ask pcap for the network address and mask of the device */
ret = pcap_lookupnet(dev,&netp,&maskp,errbuf);
if(ret == -1)
{
printf("%s\n",errbuf);
exit(1);
}
/* get the network address in a human readable form */
addr.s_addr = netp;
net = inet_ntoa(addr);
if(net == NULL)/* thanks Scott :-P */
{
perror("inet_ntoa");
exit(1);
}
printf("NET: %s\n",net);
/* do the same as above for the device's mask */
addr.s_addr = maskp;
mask = inet_ntoa(addr);
if(mask == NULL)
{
perror("inet_ntoa");
exit(1);
}
printf("MASK: %s\n",mask);
return 0;
}
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
char *dev; /* name of the device to use */
char *net; /* dot notation of the network address */
char *mask;/* dot notation of the network mask */
int ret; /* return code */
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 netp; /* ip */
bpf_u_int32 maskp;/* subnet mask */
struct in_addr addr;
/* ask pcap to find a valid device for use to sniff on */
dev = pcap_lookupdev(errbuf);
/* error checking */
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
/* print out device name */
printf("DEV: %s\n",dev);
/* ask pcap for the network address and mask of the device */
ret = pcap_lookupnet(dev,&netp,&maskp,errbuf);
if(ret == -1)
{
printf("%s\n",errbuf);
exit(1);
}
/* get the network address in a human readable form */
addr.s_addr = netp;
net = inet_ntoa(addr);
if(net == NULL)/* thanks Scott :-P */
{
perror("inet_ntoa");
exit(1);
}
printf("NET: %s\n",net);
/* do the same as above for the device's mask */
addr.s_addr = maskp;
mask = inet_ntoa(addr);
if(mask == NULL)
{
perror("inet_ntoa");
exit(1);
}
printf("MASK: %s\n",mask);
return 0;
}
然后gcc -o pcap_1 pcap_1.c -lpcap(一定要-lpcap参数)
编译ok~,执行./pcap_1,可以看到:
DEV: eth0
NET: 192.168.12.0
MASK: 255.255.255.0
NET: 192.168.12.0
MASK: 255.255.255.0
好了,第一个pcap程序出炉了。。。。。
但是(当然有但是了,要不然我后面写啥),上面那个程序除了向我们展现pcap_lookupdev和pcap_lookupnet之外什么都没有干,好,我们接着来,动手编写我们的第一个抓包程序。
/*pcap_2.c*/
#include
#include
#include /* if this gives you an error try pcap/pcap.h */
#include
#include
#include
#include
#include /* includes net/ethernet.h */
int main(int argc, char **argv)
{
int i;
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* descr; /*you can man it*/
const u_char *packet;
struct pcap_pkthdr hdr; /* pcap.h */
struct ether_header *eptr; /* net/ethernet.h */
u_char *ptr; /* printing out hardware header info */
/* grab a device to peak into... */
dev = pcap_lookupdev(errbuf);
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
printf("DEV: %s\n",dev);
/* open the device for sniffing.
pcap_t *pcap_open_live(char *device,int snaplen, int prmisc,int to_ms,
char *ebuf)
snaplen - maximum size of packets to capture in bytes
promisc - set card in promiscuous mode?
to_ms - time to wait for packets in miliseconds before read
times out
errbuf - if something happens, place error string here
Note if you change "prmisc" param to anything other than zero, you will
get all packets your device sees, whether they are intendeed for you or
not!! Be sure you know the rules of the network you are running on
before you set your card in promiscuous mode!! */
descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
if(descr == NULL)
{
printf("pcap_open_live(): %s\n",errbuf);
exit(1);
}
/*
grab a packet from descr (yay!)
u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h)
so just pass in the descriptor we got from
our call to pcap_open_live and an allocated
struct pcap_pkthdr */
packet = pcap_next(descr,&hdr);
if(packet == NULL)
{/* dinna work *sob* */
printf("Didn't grab packet\n");
exit(1);
}
/* struct pcap_pkthdr {
struct timeval ts; time stamp
bpf_u_int32 caplen; length of portion present
bpf_u_int32; lebgth this packet (off wire)
}
*/
printf("Grabbed packet of length %d\n",hdr.len);
printf("Recieved at ..... %s\n",ctime((const time_t*)&hdr.ts.tv_sec));
printf("Ethernet address length is %d\n",ETHER_HDR_LEN);
/* lets start with the ether header... */
eptr = (struct ether_header *) packet;
/* Do a couple of checks to see what packet type we have..*/
if (ntohs (eptr->ether_type) == ETHERTYPE_IP)
{
printf("Ethernet type hex:%x dec:%d is an IP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}else if (ntohs (eptr->ether_type) == ETHERTYPE_ARP)
{
printf("Ethernet type hex:%x dec:%d is an ARP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}else {
printf("Ethernet type %x not IP", ntohs(eptr->ether_type));
exit(1);
}
/* THANK YOU RICHARD STEVENS!!! RIP*/
ptr = eptr->ether_dhost;
i = ETHER_ADDR_LEN;
printf(" Destination Address: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
}while(--i>0);
printf("\n");
ptr = eptr->ether_shost;
i = ETHER_ADDR_LEN;
printf(" Source Address: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
}while(--i>0);
printf("\n");
return 0;
}
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int i;
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* descr; /*you can man it*/
const u_char *packet;
struct pcap_pkthdr hdr; /* pcap.h */
struct ether_header *eptr; /* net/ethernet.h */
u_char *ptr; /* printing out hardware header info */
/* grab a device to peak into... */
dev = pcap_lookupdev(errbuf);
if(dev == NULL)
{
printf("%s\n",errbuf);
exit(1);
}
printf("DEV: %s\n",dev);
/* open the device for sniffing.
pcap_t *pcap_open_live(char *device,int snaplen, int prmisc,int to_ms,
char *ebuf)
snaplen - maximum size of packets to capture in bytes
promisc - set card in promiscuous mode?
to_ms - time to wait for packets in miliseconds before read
times out
errbuf - if something happens, place error string here
Note if you change "prmisc" param to anything other than zero, you will
get all packets your device sees, whether they are intendeed for you or
not!! Be sure you know the rules of the network you are running on
before you set your card in promiscuous mode!! */
descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
if(descr == NULL)
{
printf("pcap_open_live(): %s\n",errbuf);
exit(1);
}
/*
grab a packet from descr (yay!)
u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h)
so just pass in the descriptor we got from
our call to pcap_open_live and an allocated
struct pcap_pkthdr */
packet = pcap_next(descr,&hdr);
if(packet == NULL)
{/* dinna work *sob* */
printf("Didn't grab packet\n");
exit(1);
}
/* struct pcap_pkthdr {
struct timeval ts; time stamp
bpf_u_int32 caplen; length of portion present
bpf_u_int32; lebgth this packet (off wire)
}
*/
printf("Grabbed packet of length %d\n",hdr.len);
printf("Recieved at ..... %s\n",ctime((const time_t*)&hdr.ts.tv_sec));
printf("Ethernet address length is %d\n",ETHER_HDR_LEN);
/* lets start with the ether header... */
eptr = (struct ether_header *) packet;
/* Do a couple of checks to see what packet type we have..*/
if (ntohs (eptr->ether_type) == ETHERTYPE_IP)
{
printf("Ethernet type hex:%x dec:%d is an IP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}else if (ntohs (eptr->ether_type) == ETHERTYPE_ARP)
{
printf("Ethernet type hex:%x dec:%d is an ARP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}else {
printf("Ethernet type %x not IP", ntohs(eptr->ether_type));
exit(1);
}
/* THANK YOU RICHARD STEVENS!!! RIP*/
ptr = eptr->ether_dhost;
i = ETHER_ADDR_LEN;
printf(" Destination Address: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
}while(--i>0);
printf("\n");
ptr = eptr->ether_shost;
i = ETHER_ADDR_LEN;
printf(" Source Address: ");
do{
printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
}while(--i>0);
printf("\n");
return 0;
}
好了,编译运行!
[root@norman libpcap]# ./pcap_2
DEV: eth0
Grabbed packet of length 76
Recieved at time..... Mon Mar 12 22:23:29 2001
Ethernet address length is 14
Ethernet type hex:800 dec:2048 is an IP packet
Destination Address: 0:20:78:d1:e8:1
Source Address: 0:a0:cc:56:c2:91
[root@pepe libpcap]#
Grabbed packet of length 76
Recieved at time..... Mon Mar 12 22:23:29 2001
Ethernet address length is 14
Ethernet type hex:800 dec:2048 is an IP packet
Destination Address: 0:20:78:d1:e8:1
Source Address: 0:a0:cc:56:c2:91
[root@pepe libpcap]#
可能有人等了半天都没有一个包过来,有个好办法,再开一个控制台,ping一下某个网站,比如google~~,呵呵
马上就有反应了
这个程序是一个老外写的,大家看看注释应该没有问题吧~