WinPcap笔记(8):分析数据包(2)
来源:互联网 发布:无烟艾条 知乎 编辑:程序博客网 时间:2024/06/11 17:29
上一讲里分析了UDP数据包,这里简单分析一下TCP数据包。
TCP是面向有连接的传输协议,因此相对来说比较复杂。下面是TCP报头的格式:
同样,需要我们自己定义TCP报头:
/* tcp 首部 */typedef struct tcp_header {u_short sport; //源端口u_short dport; //目的端口u_int th_seq; //序列号u_int th_ack; //确认号u_short doff : 4, hlen : 4, fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1; //4 bits 首部长度,6 bits 保留位,6 bits 标志位u_short th_window; //窗口大小u_short th_sum; //校验和u_short th_urp; //紧急指针}tcp_header;
下面的程序捕获TCP数据包,并将数据包中的数据打印出来:
#include "pcap.h"/* 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_short tlen; // 总长(Total length) u_short identification; // 标识(Identification)u_short flags_fo; // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)u_char ttl; // 存活时间(Time to live)u_char proto; // 协议(Protocol)u_short crc; // 首部校验和(Header checksum)ip_address saddr; // 源地址(Source address)ip_address daddr; // 目的地址(Destination address)u_int op_pad; // 选项与填充(Option + Padding)}ip_header;/* tcp 首部 */typedef struct tcp_header {u_short sport; //源端口u_short dport; //目的端口u_int th_seq; //序列号u_int th_ack; //确认号u_short doff : 4, hlen : 4, fin : 1, syn : 1, rst : 1, psh : 1, ack : 1, urg : 1, ece : 1, cwr : 1; //4 bits 首部长度,6 bits 保留位,6 bits 标志位u_short th_window; //窗口大小u_short th_sum; //校验和u_short th_urp; //紧急指针}tcp_header;/* UDP 首部*/typedef struct udp_header {u_short sport; // 源端口(Source port)u_short dport; // 目的端口(Destination port)u_short len; // UDP数据包长度(Datagram length)u_short crc; // 校验和(Checksum)}udp_header;/* 回调函数原型 */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);main(){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i = 0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[] = "ip and tcp";struct bpf_program fcode;/* 获得设备列表 */if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1){fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);exit(1);}/* 打印列表 */for (d = alldevs; d; d = d->next){printf("%d. %s", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (No description available)\n");}if (i == 0){printf("\nNo interfaces found! Make sure WinPcap is installed.\n");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);return -1;}/* 跳转到已选设备 */for (d = alldevs, i = 0; i< inum - 1;d = d->next, i++);/* 打开适配器 */if ((adhandle = pcap_open(d->name, // 设备名65536, // 要捕捉的数据包的部分 // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式1000, // 读取超时时间NULL, // 远程机器验证errbuf // 错误缓冲池)) == NULL){fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n");/* 释放设备列表 */pcap_freealldevs(alldevs);return -1;}/* 检查数据链路层,为了简单,我们只考虑以太网 */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 *uh;u_int ip_len;u_int tcp_len;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.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);/* 获得IP数据包头部的位置 */ih = (ip_header *)(pkt_data +14); //以太网头部长度 /* 获得TCP首部的位置 */ip_len = (ih->ver_ihl & 0xf) * 4;uh = (tcp_header *)((u_char*)ih + ip_len);tcp_len = uh->hlen*4;char *data = (char*)uh + tcp_len;u_int data_len = ntohs(ih->tlen) - ip_len - tcp_len;char buffer[20000];memcpy(buffer, data, data_len);buffer[data_len] = '\0';/* 将网络字节序列转换成主机字节序列 */sport = ntohs(uh->sport);dport = ntohs(uh->dport);/* 打印IP地址和TCP端口 */printf("%d.%d.%d.%d.%d -> %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("ip:%d tcp:%d (%d) data:%s\n",ip_len,tcp_len,data_len, buffer);}
结果如下:
0 0
- WinPcap笔记(8):分析数据包(2)
- WinPcap笔记:分析数据包(1)
- WinPcap笔记(7):分析数据包(1)
- WinPcap学习(七)分析数据包
- WinPcap笔记(6):过滤数据包
- WinPcap笔记(4):打开适配器并捕获数据包
- WinPcap笔记(5):不用回调方法捕获数据包
- WinPcap笔记(9):保存数据包到堆文件
- WinPcap笔记(10):从堆文件中读取数据包
- winpcap数据包分析
- WinPcap基础知识(第六课:翻译数据包)
- WinPcap基础知识(第八课:发送数据包)
- WinPcap学习(六)过滤数据包
- WinPcap学习(九)发送数据包
- WinPcap编程【6】过滤、分析数据包
- VC++基于winpcap实现数据包分析
- WinPcap编程【6】过滤、分析数据包
- WinPcap笔记(2):获取设备列表
- AJAX【Asynchronous异步的JS和XML】,工作原理与特点
- 黑马程序员_NSString
- C#之VS自带RDLC报表学习
- Testing Round #12 597ABC题解
- Web Service 教程
- WinPcap笔记(8):分析数据包(2)
- Redis中的排序
- C++Builder实现鼠标钩子
- CodeForces CF 360E Levko and Game 贪心+SPFA
- Python3.5安装numpy,SciPy后,出现ImportError
- max-min fairness 最大最小公平算法
- B. Rebranding
- ubuntu14.04.3 LTS中的atime, ctime, mtime的含义
- 纳兰性德词全集