原文:http://xiexiaohui.com.host2.ugocn.com/index.php/archives/34
轉(zhuǎn)載請注明出處。來自 hello xiexh (xiexiaohui0921@163.com)
這是進(jìn)公司寫的一個練手程序,程序功能為解析由Wireshark生成的pcap文件。
實(shí)現(xiàn)步驟:
1)用Wireshark軟件抓包得到test.pcap文件
2)程序:分析pcap文件頭 -> 分析pcap_pkt頭 -> 分析幀頭 -> 分析ip頭 -> 分析tcp頭 -> 分析http信息
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<netinet/in.h> #include<time.h> #define BUFSIZE 10240 #define STRSIZE 1024 typedef long bpf_int32; typedef unsigned long bpf_u_int32; typedef unsigned short ?u_short; typedef unsigned long u_int32; typedef unsigned short u_int16; typedef unsigned char u_int8; //pacp文件頭結(jié)構(gòu)體 struct pcap_file_header { bpf_u_int32 magic; ? ? ? /* 0xa1b2c3d4 */ u_short version_major; ? /* magjor Version 2 */ u_short version_minor; ? /* magjor Version 4 */ bpf_int32 thiszone; ? ? ?/* gmt to local correction */ bpf_u_int32 sigfigs; ? ? /* accuracy of timestamps */ bpf_u_int32 snaplen; ? ? /* max length saved portion of each pkt */ bpf_u_int32 linktype; ? ?/* data link type (LINKTYPE_*) */ }; //時間戳 struct time_val { long tv_sec; ? ? ? ? /* seconds 含義同 time_t 對象的值 */ long tv_usec; ? ? ? ?/* and microseconds */ }; //pcap數(shù)據(jù)包頭結(jié)構(gòu)體 struct pcap_pkthdr { struct time_val ts; ?/* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; ? ?/* length this packet (off wire) */ }; //數(shù)據(jù)幀頭 typedef struct FramHeader_t { //Pcap捕獲的數(shù)據(jù)幀頭 u_int8 DstMAC[6]; //目的MAC地址 u_int8 SrcMAC[6]; //源MAC地址 u_short FrameType; ? ?//幀類型 } FramHeader_t; //IP數(shù)據(jù)報頭 typedef struct IPHeader_t { //IP數(shù)據(jù)報頭 u_int8 Ver_HLen; ? ? ? //版本+報頭長度 u_int8 TOS; ? ? ? ? ? ?//服務(wù)類型 u_int16 TotalLen; ? ? ? //總長度 u_int16 ID; //標(biāo)識 u_int16 Flag_Segment; ? //標(biāo)志+片偏移 u_int8 TTL; ? ? ? ? ? ?//生存周期 u_int8 Protocol; ? ? ? //協(xié)議類型 u_int16 Checksum; ? ? ? //頭部校驗(yàn)和 u_int32 SrcIP; //源IP地址 u_int32 DstIP; //目的IP地址 } IPHeader_t; //TCP數(shù)據(jù)報頭 typedef struct TCPHeader_t { //TCP數(shù)據(jù)報頭 u_int16 SrcPort; //源端口 u_int16 DstPort; //目的端口 u_int32 SeqNO; //序號 u_int32 AckNO; //確認(rèn)號 u_int8 HeaderLen; //數(shù)據(jù)報頭的長度(4 bit) + 保留(4 bit) u_int8 Flags; //標(biāo)識TCP不同的控制消息 u_int16 Window; //窗口大小 u_int16 Checksum; //校驗(yàn)和 u_int16 UrgentPointer; ?//緊急指針 }TCPHeader_t; // void match_http(FILE *fp, char *head_str, char *tail_str, char *buf, int total_len); //查找 http 信息函數(shù) // int main() { struct pcap_file_header *file_header; struct pcap_pkthdr *ptk_header; IPHeader_t *ip_header; TCPHeader_t *tcp_header; FILE *fp, *output; int ? pkt_offset, i=0; int ip_len, http_len, ip_proto; int src_port, dst_port, tcp_flags; char buf[BUFSIZE], my_time[STRSIZE]; char src_ip[STRSIZE], dst_ip[STRSIZE]; char ?host[STRSIZE], uri[BUFSIZE]; //初始化 file_header = (struct pcap_file_header *)malloc(sizeof(struct pcap_file_header)); ptk_header ?= (struct pcap_pkthdr *)malloc(sizeof(struct pcap_pkthdr)); ip_header = (IPHeader_t *)malloc(sizeof(IPHeader_t)); tcp_header = (TCPHeader_t *)malloc(sizeof(TCPHeader_t)); memset(buf, 0, sizeof(buf)); // if((fp = fopen(“test.pcap”,”r”)) == NULL) { printf(“error: can not open pcap file\n”); exit(0); } if((output = fopen(“output.txt”,”w+”)) == NULL) { printf(“error: can not open output file\n”); exit(0); } //開始讀數(shù)據(jù)包 pkt_offset = 24; //pcap文件頭結(jié)構(gòu) 24個字節(jié) while(fseek(fp, pkt_offset, SEEK_SET) == 0) //遍歷數(shù)據(jù)包 { i++; //pcap_pkt_header 16 byte if(fread(ptk_header, 16, 1, fp) != 1) //讀pcap數(shù)據(jù)包頭結(jié)構(gòu) { printf(“\nread end of pcap file\n”); break; } pkt_offset += 16 + ptk_header->caplen; ? //下一個數(shù)據(jù)包的偏移值 strftime(my_time, sizeof(my_time), “%Y-%m-%d %T”, localtime(&(ptk_header->ts.tv_sec))); //獲取時間 // printf(“%d: %s\n”, i, my_time); //數(shù)據(jù)幀頭 14字節(jié) fseek(fp, 14, SEEK_CUR); //忽略數(shù)據(jù)幀頭 //IP數(shù)據(jù)報頭 20字節(jié) if(fread(ip_header, sizeof(IPHeader_t), 1, fp) != 1) { printf(“%d: can not read ip_header\n”, i); break; } inet_ntop(AF_INET, (void *)&(ip_header->SrcIP), src_ip, 16); inet_ntop(AF_INET, (void *)&(ip_header->DstIP), dst_ip, 16); ip_proto = ip_header->Protocol; ip_len = ip_header->TotalLen; //IP數(shù)據(jù)報總長度 // printf(“%d: ?src=%s\n”, i, src_ip); if(ip_proto != 0×06) //判斷是否是 TCP 協(xié)議 { continue; } //TCP頭 20字節(jié) if(fread(tcp_header, sizeof(TCPHeader_t), 1, fp) != 1) { printf(“%d: can not read ip_header\n”, i); break; } src_port = ntohs(tcp_header->SrcPort); dst_port = ntohs(tcp_header->DstPort); tcp_flags = tcp_header->Flags; // printf(“%d: ?src=%x\n”, i, tcp_flags); if(tcp_flags == 0×18) // (PSH, ACK) 3路握手成功后 { if(dst_port == 80) // HTTP GET請求 { http_len = ip_len – 40; //http 報文長度 match_http(fp, “Host: “, “\r\n”, host, http_len); //查找 host 值 match_http(fp, “GET “, “HTTP”, uri, http_len); //查找 uri 值 sprintf(buf, “%d: ?%s ?src=%s:%d ?dst=%s:%d ?%s%s\r\n”, i, my_time, src_ip, src_port, dst_ip, dst_port, host, uri); //printf(“%s”, buf); if(fwrite(buf, strlen(buf), 1, output) != 1) { printf(“output file can not write”); break; } } } } // end while fclose(fp); fclose(output); return 0; } //查找 HTTP 信息 void match_http(FILE *fp, char *head_str, char *tail_str, char *buf, int total_len) { int i; int http_offset; int head_len, tail_len, val_len; char head_tmp[STRSIZE], tail_tmp[STRSIZE]; //初始化 memset(head_tmp, 0, sizeof(head_tmp)); memset(tail_tmp, 0, sizeof(tail_tmp)); head_len = strlen(head_str); tail_len = strlen(tail_str); //查找 head_str http_offset = ftell(fp); //記錄下HTTP報文初始文件偏移 while((head_tmp[0] = fgetc(fp)) != EOF) //逐個字節(jié)遍歷 { if((ftell(fp) – http_offset) > total_len) //遍歷完成 { sprintf(buf, “can not find %s \r\n”, head_str); exit(0); } if(head_tmp[0] == *head_str) //匹配到第一個字符 { for(i=1; i<head_len; i++) //匹配 head_str 的其他字符 { head_tmp[i]=fgetc(fp); if(head_tmp[i] != *(head_str+i)) break; } if(i == head_len) //匹配 head_str 成功,停止遍歷 break; } } // printf(“head_tmp=%s \n”, head_tmp); //查找 tail_str val_len = 0; while((tail_tmp[0] = fgetc(fp)) != EOF) //遍歷 { if((ftell(fp) – http_offset) > total_len) //遍歷完成 { sprintf(buf, “can not find %s \r\n”, tail_str); exit(0); } buf[val_len++] = tail_tmp[0]; //用buf 存儲 value 直到查找到 tail_str if(tail_tmp[0] == *tail_str) //匹配到第一個字符 { for(i=1; i<tail_len; i++) //匹配 head_str 的其他字符 { tail_tmp[i]=fgetc(fp); if(tail_tmp[i] != *(tail_str+i)) break; } if(i == tail_len) //匹配 head_str 成功,停止遍歷 { buf[val_len-1] = 0; //清除多余的一個字符 break; } } } // printf(“val=%s\n”, buf); fseek(fp, http_offset, SEEK_SET); //將文件指針 回到初始偏移 }
轉(zhuǎn)載于:https://www.cnblogs.com/hnrainll/archive/2012/06/17/2553000.html
總結(jié)
以上是生活随笔為你收集整理的C语言解析pcap文件得到HTTP信息实例(原创,附源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。