WinPcap笔记(8):分析数据包(2)
生活随笔
收集整理的這篇文章主要介紹了
WinPcap笔记(8):分析数据包(2)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
上一講里分析了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); }
結果如下:
總結
以上是生活随笔為你收集整理的WinPcap笔记(8):分析数据包(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinPcap笔记(7):分析数据包(1
- 下一篇: 成都欢乐谷生日当天有优惠吗