#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
/*4字节的IP地址*/
typedef struct ip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
/*定义IPv4首部*/
typedef struct ip_header{
u_char ver_ihl; // 版本 (4 bits) + 首部长度 (4 bits)
u_char tos; // 服务类型(Type of service)
u_char tlen1; // 总长度前一个字节部分(Total length)
u_char tlen2; // 总长度后一个字节部分(Total length)
u_char identification1; // 标识前一个字节部分(Identification)
u_char identification2; // 标识后一个字节部分(Identification)
u_char flags_fo1; // 标志位(Flags) (3 bits) + 段偏移量 //(Fragment offset) (前5 bits)
u_char flags_fo2; // 段偏移量 (Fragment offset) (后8 bits)
u_char ttl; // 存活时间(Time to live)
u_char proto; // 协议(Protocol)
u_char crc1; // 首部校验和前一字节(Header checksum)
u_char crc2; // 首部校验和后一字节(Header checksum)
ip_address saddr; // 源地址(Source address)
ip_address daddr; // 目的地址(Destination address)
//u_char op_pad; // 选项与填充(Option + Padding)
}ip_header;
/*TCP首部*/
typedef struct tcp_header
{
u_short sport; // 源端口(Source port)
u_short dport; // 目的端口(Destination port)
u_int syq; // 序号(sequence)
u_int comf; //确认(comfirm)
u_short os_ot; //数据偏移+保留+URG+ACK+PSH+RST+SYN+FIN
u_short wind; //窗口
u_short crc; //检验和
u_short urg; //紧急指针
//u_int op_pad; //选项+填充
}tcp_header;
/* 回调函数原型 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int i = 0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int netmask;
char packet_filter[] = "ip and tcp";
//char packet_filter[] = "";
struct bpf_program fcode;
u_char packet[100];
int innum;
/* get local devices */
if (pcap_findalldevs( &alldevs, errbuf) == -1)
{
fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf);
exit(1);
}
printf("当前网络适配器列表如下:\n");
/* print devices list */
for (d = alldevs; d != NULL; d = d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf("(%s)\n", d->description);
else
printf("(No description available)\n");
}
if (i == 0)
{
printf("\nNo interfaces found!\n");
return -1;
}
/*打开适配器*/
printf("Enter the interface number (1-%d):", i);
scanf_s("%d", &innum);
if (innum < 1 || innum > i)
{
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs); /* 释放设备列表 */
return -1;
}
for (d = alldevs, i = 0; i< innum - 1; d = d->next, i++); /* 跳转到选中的适配器 */
adhandle = pcap_open_live(d->name, //适配器名字
65536, //捕获包最大字节数
1, //混杂模式
1000, //读取超时时间
errbuf); //错误信息保存
/*检查数据链路层,只考虑以太网*/
if (pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -1;
}
if (d->addresses != NULL)
/* 获得接口第一个地址的掩码 */
netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/* 如果接口没有地址,那么我们假设一个C类的掩码 */
netmask = 0xffffff;
//编译过滤器
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0)
{
fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -1;
}
//设置过滤器
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr, "\nError setting the filter.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d->description);
/* 释放设备列表 */
pcap_freealldevs(alldevs);
/* 开始捕捉 */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
/* 回调函数,当收到每一个数据包时会被libpcap所调用 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm *ltime;
char timestr[16];
ip_header *ih;
tcp_header *th;
u_int ip_len;
ip_address saddr, daddr;
u_short sport, dport;
time_t local_tv_sec;
/* 将时间戳转换成可识别的格式 */
local_tv_sec = header->ts.tv_sec;
ltime = localtime( &local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);
/* 打印数据包的时间戳和长度 */
//printf("%s %d len:%d \n", timestr, header->ts.tv_usec,header->len);
/* 获得IP数据包的头部 */
ih = (ip_header *)(pkt_data+14); //14是以太网头部长度
/* 获得TCP的首部 */
ip_len = (ih->ver_ihl & 0xf) * 4;
th = (tcp_header *)((u_char*)ih + ip_len);
/* 将网络字节序列转换成主机字节序列 */
sport = th->sport;
dport = th->dport;
/* 打印IP首部 */
printf("IP报文的首部字段的内容为:\n");
printf("%02x %02x %02x %02x\n", ih->ver_ihl, ih->tos, ih->tlen1,ih->tlen2);
printf("%02x %02x %02x %02x\n", ih->identification1, ih->identification2, ih->flags_fo1,ih->flags_fo2);
printf("%02x %02x %02x %02x\n", ih->ttl, ih->proto, ih->crc1,ih->crc2);
printf("%02x %02x %02x %02x\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4);
printf("%02x %02x %02x %02x\n", ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4);
printf("版本和首部长度:%x\n", ih->ver_ihl);
printf("区分服务:%x\n",ih->tos);
printf("总长度为:%02x %02x\n", ih->tlen1,ih->tlen2);
printf("标识:%02x\n", ih->identification1,ih->identification2);
printf("标志和片偏移:%02x %02x\n", ih->flags_fo1,ih->flags_fo2);
printf("生存时间:%02x\n", ih->ttl);
printf("协议:%02x\n", ih->proto);
printf("首部校验和:%02x %02x\n",ih->crc1,ih->crc2);
printf("源IP:端口=%d.%d.%d.%d:%d->目的IP:端口=%d.%d.%d.%d:%d\n",ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4,sport,ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4,dport);
printf("\n");
}