利用libpcap局域网内抓取arp包

本人在fedora17下编写、测试正常运行,代码如下:


  1 #include
  2 #include
  3 #include
  4
  5 //ARP Header,(assuming Ethernet + ip4)
  6
  7 #define ARP_REQUEST 1
  8 #define ARP_REPLY 2
  9
 10 struct arphdr{
 11         u_int16_t htype;        //hardware type
 12         u_int16_t ptype;        //protocol type
 13         u_char hlen;            //hardware address length
 14         u_char plen;            //protocol address length
 15         u_int16_t oper;         //operation code
 16         u_char sha[6];          //sendHardware address
 17         u_char spa[4];          //sender ip address
 18         u_char tha[6];          //target hardware address
 19         u_char tpa[4];          //target ip address
 20 };
 21
 22 #define MAXBYTES2CAPTURE 2048
 23 int pcap_dloff(pcap_t *pd)
 24 {
 25         int offset = -1;
 26         switch (pcap_datalink(pd))
 27         {
 28                 case DLT_EN10MB:
 29                         offset = 14;
 30                         break;
 31                 case DLT_IEEE802:
 32                         offset = 22;
 33                         break;
 34                 case DLT_FDDI:
 35                         offset = 21;
 36                         break;
 37                 #ifdef DLT_LOOP
 38                 case DLT_LOOP:
 39                 #endif
 40                 case DLT_NULL:
 41                 offset = 4;
 42                         break;
 43                 default:
 44                 warnx("unsupported datalink type");
 45                         break;
 46         }
 47         return (offset);
 48 }
 49
 50 int main()
 51 {
 52         int i=0,offset=0;
 53         bpf_u_int32 netaddr=0,mask=0;
 54         struct bpf_program filter;
 55         char errbuf[PCAP_ERRBUF_SIZE];
 56         pcap_t *descr=NULL;
 57         struct pcap_pkthdr *pkthdr;
 58         const unsigned char *packet=NULL;
 59         struct arphdr *arpheader=NULL;
 60         memset(errbuf,0,PCAP_ERRBUF_SIZE);
 61         char *device=NULL;
 62
 63         device = pcap_lookupdev(errbuf);
 64         printf("Opening device %s\n",device);
 65         descr=pcap_open_live(device,MAXBYTES2CAPTURE,0,512,errbuf);
 66         pcap_lookupnet(device,&netaddr,&mask,errbuf);
 67         pcap_compile(descr,&filter,"arp",1,mask);
 68         pcap_setfilter(descr,&filter);
 69
 70         offset=pcap_dloff(descr);
 71         printf("offset=%d\n",offset);
 72
 73         while(1)
 74         {
 75                 if((packet=pcap_next(descr,pkthdr))==NULL)
 76                 {
 77                         printf("no arp packet waiting.");
 78                         continue;
 79                 }
 80                 printf("\n\nReceived Packet Size: %d bytes\n",pkthdr->len);
 81
 82                 arpheader = (struct arphdr *)(packet + offset);
 83                 printf("Hardware type: %s\n", (ntohs(arpheader->htype) == 1)?"Ethernet" : "Unknown");
 84                 printf("Protocol type: %s\n", (ntohs(arpheader->ptype) == 0x0800) ? "Ethernet" : "Unknown");
 85                 printf("Operation: %s\n", (ntohs(arpheader->oper) == ARP_REQUEST) ?"ARP Request" : "ARP Reply");
 86
 87                 if (ntohs(arpheader->htype) == 1 && ntohs(arpheader->ptype) == 0x0800)
 88                 {
 89                         printf("Sender MAC: ");
 90                         for (i=0; i<6; i++)
 91                                 printf("%02x:", arpheader->sha[i]);
 92                         printf("\nSender IP: ");
 93                         for (i=0; i<4; i++)
 94                                 printf("%d.", arpheader->spa[i]);
 95                         printf("\nTarget MAC: ");
 96                         for (i=0; i<6; i++)
 97                                 printf("%02x:", arpheader->tha[i]);
 98                         printf("\nTarget IP: ");
 99                         for (i=0; i<4; i++)
100                                 printf("%d.", arpheader->tpa[i]);
101                         printf("\n");
102                 }
103
104         }
105         return 0;
106 }
107

值得一提的是const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)方法、pcap API对此方法描述如下:

pcap_next() reads the next packet (by calling pcap_dispatch() with a cnt of 1) and returns a u_char pointer to the data in that packet. (The pcap_pkthdr struct for that packet is not supplied.) NULL is returned if an error occured, or if no packets were read from a live capture (if, for example, they were discarded because they didn't pass the packet filter, or if, on platforms that support a read timeout that starts before any packets arrive, the timeout expires before any packets arrive, or if the file descriptor for the capture device is in non-blocking mode and no packets were available to be read), or if no more packets are available in a ``savefile.'' Unfortunately, there is no way to determine whether an error occured or not.

由pcap API我们发现在很多情况比如没有数据包经过过滤器即没有arp包的时候此方法会返回NULL,如果没有相应处理则程序会出现断错误,本程序巧妙的处理了返回之为NULL的情况使得其能持续监听网络。



你可能感兴趣的:(源代码)