“pcap.h”
内有:#ifndef lib_pcap_pcap_h
#define lib_pcap_pcap_h
#if defined(WIN32)
#include
#elif defined(MSDOS)
#include
#include /* u_int, u_char etc. */
#else /* UN*X */
#include
#include
#endif /* WIN32/MSDOS/UN*X */
pcap支持WIM32、MSDOS、UNIX,所以在首部添加#define WIN32
即可。
包过滤器的设置
过滤串表达式语法。
ntohs()
没有分析哪个字段需要由网络字节顺序转换为主机字节顺序,直接按照输出加上了ntohs,具体分析日后再写。
#define WIN32
#include "pcap.h"
#include
#include
#define MAX_PRINT 80
#define MAX_LINE 16
#define LINE_LEN 16
struct ether_header//以太网首部
{
u_int8_t ether_dhost[6]; //目的Mac地址
u_int8_t ether_shost[6]; //源Mac地址
u_int16_t ether_type; //协议类型
};
/* IP报文包数据结构 */
struct ip_header{
#if defined(WORDS_BIENDIAN) //考虑大端序与小端序
u_int8_t ip_version : 4,
ip_header_length : 4;
#else
u_int8_t ip_header_length : 4,//首部长度
ip_version : 4;//版本
#endif
u_int8_t ip_tos;//服务类型
u_int16_t ip_length;//总长度
u_int16_t ip_id;//标识
u_int16_t ip_off;//片偏移
u_int8_t ip_ttl;//生存时间
u_int8_t ip_protocol;//协议
u_int16_t ip_checksum;//首部检验和
struct in_addr ip_souce_address;//源地址
struct in_addr ip_destination_address;//目的地址
};
/* ARP报文包数据结构 */
struct ether_arp{
u_int16_t ar_hrd;//硬件类型
u_int16_t ar_pro;//协议类型
u_int8_t ar_hln;//硬件地址长度(6)
u_int8_t ar_pln;//协议地址长度(4)
u_int16_t ar_op;//操作类型
u_int8_t arp_sha[6];//发送者硬件地址
struct in_addr arp_spa;//发送者IP地址
u_int8_t arp_tha[6];//目标硬件地址
struct in_addr arp_tpa;//目标IP地址
};
void ip_protool_packet(struct pcap_pkthdr *header, const u_char *pkt_data, FILE *fp);
void arp_protool_packet(struct pcap_pkthdr *header, const u_char *pkt_data, FILE *fp);
int ip_counter, icmp_counter, arp_counter;
int main(int argc, char **argv)
{
time_t start, now;//计时
long float time_sum;
pcap_if_t *alldevs, *d;
pcap_t *fp;
u_int inum, i = 0;
struct bpf_program fcode;
u_int netmask;
char errbuf[PCAP_ERRBUF_SIZE];
int res;
struct pcap_pkthdr *header;//抓到的包的一般信息
const u_char *pkt_data; //抓到的包的数据
u_short ethernet_type;//以太网类型
struct ether_header *ethernet_protocol;
FILE *stream;//文件流
ip_counter = icmp_counter = arp_counter = 0;
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)//查找网卡
{
fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf);
system("pause");
return -1;
}
for (d = alldevs; d; d = d->next)
{
printf("%d. %s\n ", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if (i == 0)
{
fprintf(stderr, "No interfaces found! Exiting.\n");
system("pause");
return -1;
}
printf("Enter the interface number (1-%d):", i);
scanf("%d", &inum);
if (inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* 释放设备 */
pcap_freealldevs(alldevs);
system("pause");
return -1;
}
/* 跳到选中的设备 */
for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);
/* 打开设备 */
if ((fp = pcap_open(d->name,
100 /*snaplen*/,
PCAP_OPENFLAG_PROMISCUOUS /*flags*/,
20 /*read timeout*/,
NULL /* remote authentication */,
errbuf)
) == NULL)
{
fprintf(stderr, "\nError opening adapter\n");
system("pause");
return -1;
}
/* 获取掩码 */
if (d->addresses != NULL)
netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
netmask = 0xffffff; /* 255.255.255.0 */
//编译过滤串表达式,语法参见:http://www.tcpdump.org/manpages/pcap-filter.7.html
if (pcap_compile(fp, &fcode, "ip or arp or icmp", 1, netmask) < 0)
{
fprintf(stderr, "\nError compiling filter: wrong syntax.\n");
system("pause");
return -1;
}
//绑定过滤器
if (pcap_setfilter(fp, &fcode)<0)
{
fprintf(stderr, "\nError setting the filter\n");
system("pause");
return -1;
}
/* 以只读形式打开输出文件 */
if ((stream = fopen("capture.txt", "w")) == NULL) {
printf("The file 'capture.txt' was not opened\n");
system("pause");
return -1;
}
start = time(NULL);
int counter = 0;
/* 抓包 */
while ((res = pcap_next_ex(fp, &header, &pkt_data)) >= 0)
{
now = time(NULL);
if ((time_sum = difftime(now, start)) > 60)//计时一分钟
break;;
if (kbhit()) {//键盘监听,回车键退出,两个getch()的问题(vs平台)参见:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=vs-2017
char ch = getch();
getch();
if (ch == '\n' || ch == '\r')
break;
}
if (res == 0)
/* 超时,获取的包无效 */
continue;
printf("历时%2.0lf秒\n", time_sum);
ethernet_protocol = (struct ether_header*)pkt_data;//获得数据包内容
ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网类型
switch (ethernet_type){
case 0x0800:
++ip_counter;
printf("No.%-4d上层协议:IP协议\n", counter++);
fprintf(stream, "No.%-4d上层协议:IP协议\n", counter);
ip_protool_packet(header, pkt_data, stream);
break;
case 0x0806:
++arp_counter;
printf("No.%-4d上层协议:ARP协议\n", counter++);
fprintf(stream, "No.%-4d上层协议:ARP协议\n", counter);
arp_protool_packet(header, pkt_data, stream);
break;
case 0x8035:
printf("No.%-4d上层协议:RARP协议\n", counter++);
fprintf(stream, "No.%-4d上层协议:RARP协议\n", counter);
for (i = 1; (i < header->caplen + 1); i++)
{
fprintf(stream, "%.2x ", pkt_data[i - 1]);
if ((i % LINE_LEN) == 0)
fprintf(stream, "\n");
}
fprintf(stream, "\n\n");
break;
default:
break;
}
printf("\n\n");
}
fprintf(stream, "计时:%.0lf秒\nIP:%d、ICMP:%d、ARP:%d\n", time_sum,ip_counter, icmp_counter, arp_counter);
fclose(stream);
if (res == -1)
{
fprintf(stderr, "Error reading the packets: %s\n", pcap_geterr(fp));
system("pause");
return -1;
}
system("pause");
return 0;
}
void ip_protool_packet(struct pcap_pkthdr *header, const u_char *pkt_data, FILE *fp)
{
struct ip_header *ip_protocol;
u_int header_length;
u_int offset;
u_char tos;
u_int16_t checksum;
ip_protocol = (struct ip_header *) (pkt_data + 14);//以太网首部14位
checksum = ntohs(ip_protocol->ip_checksum);
tos = ip_protocol->ip_tos;
offset = ntohs(ip_protocol->ip_off);
fprintf(fp, "版本号:%d\n", ip_protocol->ip_version);
fprintf(fp, "首部长度:%d\n", ip_protocol->ip_header_length);
fprintf(fp, "服务质量:%d\n", tos);
fprintf(fp, "总长度:%d\n", ntohs(ip_protocol->ip_length));
fprintf(fp, "标识:%d\n", ntohs(ip_protocol->ip_id));
fprintf(fp, "偏移:%d\n", (offset & 0x1fff) * 8);
fprintf(fp, "生存时间:%d\n", ip_protocol->ip_ttl);
fprintf(fp, "协议类型:%d", ip_protocol->ip_protocol);
switch (ip_protocol->ip_protocol)
{
case 1: fprintf(fp, "(上层协议是ICMP协议)\n"); ++icmp_counter; break;
case 2: fprintf(fp, "(上层协议是IGMP协议)\n"); break;
case 6: fprintf(fp, "(上层协议是TCP协议)\n"); break;
case 17: fprintf(fp, "(上层协议是UDP协议)\n"); break;
default:break;
}
fprintf(fp, "检验和:%d\n", checksum);
fprintf(fp, "源IP地址:%s\n", inet_ntoa(ip_protocol->ip_souce_address));
fprintf(fp, "目的地址:%s\n", inet_ntoa(ip_protocol->ip_destination_address));
fprintf(fp, "\n");
}
void arp_protool_packet(struct pcap_pkthdr *header, const u_char *pkt_data, FILE *fp)
{
struct ether_arp *arp_protocol;
arp_protocol = (struct ether_arp *)(pkt_data + 14);
u_int8_t *arp_sha = arp_protocol->arp_sha;
u_int8_t *arp_tha = arp_protocol->arp_tha;
fprintf(fp, "硬件类型:%d\n", ntohs(arp_protocol->ar_hrd));
fprintf(fp, "协议类型:0x%04x\n", ntohs(arp_protocol->ar_pro));
fprintf(fp, "硬件地址长度:%d\n", arp_protocol->ar_hln);
fprintf(fp, "协议地址长度:%d\n", arp_protocol->ar_pln);
fprintf(fp, "操作类型:%d\n", ntohs(arp_protocol->ar_op));
fprintf(fp, "发送者硬件地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *arp_sha, *(arp_sha + 1), *(arp_sha + 2), *(arp_sha + 3), *(arp_sha + 4), *(arp_sha + 5));
fprintf(fp, "发送者IP地址:%s\n", inet_ntoa(arp_protocol->arp_spa));
fprintf(fp, "目标硬件地址:%02x:%02x:%02x:%02x:%02x:%02x\n", *arp_tha, *(arp_tha + 1), *(arp_tha + 2), *(arp_tha + 3), *(arp_tha + 4), *(arp_tha + 5));
fprintf(fp, "目标IP地址:%s\n", inet_ntoa(arp_protocol->arp_tpa));
fprintf(fp, "\n");
}
```