Tcpdump解析重发包程序
在做网络编程的时候,如果是在公司里面做项目,经常需要做联调。假如你做的是后台,在项目中就要和前台的服务器进行联调,前面收到一个什么操作,然后就向你后台发一个TCP或者UDP包,调试是一个多个人的工作,如果前面发过来一个包没错,但是你这边解包或者别的逻辑上出了点问题,那么当你修改编译完你的代码后你又要跟前台说“你再发个包给我吧”,这样是很麻烦的,如果能先自己模拟前台发过来的包,这样就可以自己给自己发包测试解包或者别的逻辑什么的,知道自己这边没什么问题了,再跟前台正式联调一次,这样不仅效率可以更高,而且,方便你我他~
要怎么模拟前台发包呢?有个方法,就是先用TCPDUMP监听端口,遇到前台的包就重定向到一个txt文本中。一般tcpdump拿到的包格式就像下面这个那样。上面有IP,端口,时间,UDP还是TCP,数据包的长度等信息。
13:56:37.898494 IP 10.130.68.226.51851 > 10.130.92.40.8791: UDP, length 311 0x0000: 4500 0153 0000 4000 3d11 868c 0a82 44e2 E..S..@.=.....D. 0x0010: 0a82 5c28 ca8b 2257 013f 6ea5 0a01 3700 ..(.."W.?n...7. 0x0020: 0505 c041 ac4f ff00 0000 6570 6f63 686c ...A.O....epochl 0x0030: 6975 0000 0065 706f 6368 6c69 7500 0000 iu...epochliu... 0x0040: ac19 642e 6d69 6372 6f62 6c6f 675f 7365 ..d.microblog_se 0x0050: 7276 6900 ffe2 defe 0000 2da9 00d3 8f32 rvi.......-....2 0x0060: 4300 0000 006d 6963 726f 626c 6f67 5f73 C....microblog_s 0x0070: 6572 7669 6300 41ac 4fff 0000 0000 0000 ervic.A.O....... 0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0090: 0000 0000 0000 0000 0000 0000 0015 0258 ...............X 0x00a0: 0000 0000 0a00 06b1 e122 f03b 4a00 0000 .........".;J... 0x00b0: 0000 0000 0012 0000 0000 0000 0000 0000 ................ 0x00c0: 0000 0600 0200 0402 0012 004e 2100 3ce5 ...........N!.<. 0x00d0: 8a9e e79a 84e5 a5bd efbc 8ce6 9c80 e5a5 ................ 0x00e0: bde5 88b0 e4bd a0e8 87aa e5b7 b1e5 aeb6 ................ 0x00f0: e58a 9ee5 8ebb efbc 8ce4 bb80 e4b9 88e7 ................ 0x0100: 8ea9 e684 8fe5 84bf efbc 9f00 0a00 1800 ................ 0x0110: 0002 650b cfad ea25 12fe 6500 0002 650b ..e....%..e...e. 0x0120: cfad ea25 12fe 654e 2300 0800 0141 ac4f ...%..eN#....A.O 0x0130: ff00 0100 6600 1100 0003 f000 0000 0000 ....f........... 0x0140: 0000 0000 0000 0000 7530 0006 0100 0300 ........u0...... 0x0150: 0100 03
拿到这个文档之后,我们只要解析这个文档,把包的数据复制出来,自己给自己发就行了。
但是我们在这么做的时候,一定要严格检查文本里面的各种细节,因为我们知道网络的端口经常有大量的数据流过,有时数据流量大于写进文本的速度,就会出现各种问题。如果是丢包的问题,那么我们也没办法,但是如果是TCPDUMP写进文本时有些书写的错误,我们就要严格检查出来!!比如说上面那个例子中,我们要检查包的数据长度是否严格是311,第一行的格式是不是类似“13:56:37.898494 IP 10.130.68.226.51851 > 10.130.92.40.8791: UDP, length 311”,后面每一行是否先是一个制表符,然后0x??????:,再一个制表符?第二行开始每一行的数据前后显示是否一致?写进包的时间是否按照时间顺序等等。如果出了错应该禁止发包,并且提示错误在哪方便检查。
不过呢,我们有考虑到另一个需求,我们知道一个包里面经常有些数据一个字节就代表了某个变量,我们有时希望可以自己偷偷的改一下txt里面的某个变量,但是这样可能就造成某一行前后不一致了,我们要有时允许这种情况发生,这样就可以自己该小参数调试了。。
最后程序代码如下,编译过后就可以运行了,运行时格式如下:
tcpdumpResend.exe tcpdump_file IP PORT [-i] [Begin_Time] [End_Time]
tcpdumpResend是编译后的程序名,tcpdump_file 是要解析的文件名,然后后面跟上要发送的IP地址和端口,之后是可选参数,如果加上了-i(gnore),那么会忽略自己做的小修改,但是对于包长度不对这种事情是不会饶恕的!!接下来可以选择只发送文件中的部分包,写上起始时间和截止时间就可以,都不写的话就全发,只写开始时间就是从开始时间一直发到文件末尾。
举个例子如下:tcpdumpResend.exe a.txt 127.0.0.1 5454 -i 16:34:45.234123 16:34:46.234123
#include <stdio .h> #include <fstream> #include <string .h> #include <sys /socket.h> #include </sys><sys /types.h> #include <arpa /inet.h> using namespace std; #define BUFFER_LEN 512 #define PACKAGE_SEND_LIMIT 5 #define SELECT_WAITTIME 1000 //us int show_errorinfo = 1; int Warming_ignore = 0; struct str_time { int32_t hour; int32_t min; int32_t sec; int32_t usec; }; struct str_packagetitle { str_time time; int32_t length; int32_t ip_src[4]; int32_t ip_dst[4]; char port_src[128]; char port_dst[128]; }; static void InitTitleStruct(str_packagetitle &title) { title.time.hour = title.time.min = title.time.sec = title.time.usec = title.length = 0; for(int ii = 0;ii < 4;ii++) title.ip_src[ii] = title.ip_dst[ii] = 0; } static int32_t GetNum(const char* string,int begin,int end) { if(!string) { //printf("wrong line:%d\n",__LINE__); return -1; } int str_length = strlen(string); if(begin < 0 || begin > str_length || end < 0 || end > str_length || end < begin) { //printf("wrong line:%d\n",__LINE__); return -2; } int32_t sum = 0; for(int i = begin;i <= end;i++) { if(string[i] < '0' || string[i] > '9') { //printf("wrong line:%d\n",__LINE__); return -3; } sum = sum*10 + string[i] - '0'; } return sum; } static int GetChar(const char a,const char b,char &c) { int shiwei = 0,gewei = 0; if(a >= '0' && a < = '9') shiwei = a - '0'; else if(a >= 'a' && a < = 'f') shiwei = a - 'a' + 10; else { //printf("wrong line:%d\n",__LINE__); return -1; } if(b >= '0' && b < = '9') gewei = b - '0'; else if(b >= 'a' && b < = 'f') gewei = b - 'a' + 10; else { //printf("wrong line:%d\n",__LINE__); return -1; } c = char(16 * shiwei + gewei); return 1; } /* CHECK THE FORMAT:xx:xx:xx.xxxxxx */ static int InitTime(const char* buf,str_time &time) { int32_t temp = GetNum(buf,0,1); if(temp >= 0 && temp < 24) time.hour = temp; else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("hour error\n"); return -1; } if(buf[2] != ':') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("syntax error\n"); return -2; } temp = GetNum(buf,3,4); if(temp >= 0 && temp < 60) time.min = temp; else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("minute error\n"); return -3; } if(buf[5] != ':') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("syntax error\n"); return -4; } temp = GetNum(buf,6,7); if(temp >= 0 && temp < 60) time.sec = temp; else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("second error\n"); return -5; } if(buf[8] != '.') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("syntax error\n"); return -6; } temp = GetNum(buf,9,14); if(temp >= 0) time.usec = temp; else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("usec error\n"); return -7; } return 1; } static int SetTime(const char* buf,str_packagetitle &title) { return InitTime(buf,title.time); } static int GetNextPos(const char* string,const int begin,const char c) { if(!string) { //printf("wrong line:%d\n",__LINE__); return -1; } int len = strlen(string); if(begin < 0 || begin+1 >= len) { //printf("wrong line:%d\n",__LINE__); return -2; } if(c == '\n') return len+1; for(int i = begin+1;i < = len;i++) { if(string[i] == c) return i; else continue; } //printf("wrong line:%d\n",__LINE__); return -3; } static int SetIp(const char* buf,str_packagetitle &title) { if(buf[15] != ' ')//check " IP " { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("space error\n"); return -1; } if(buf[16] != 'I') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("'I' is error\n"); return -2; } if(buf[17] != 'P') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("'p' is error\n"); return -3; } if(buf[18] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("space error\n"); return -4; } int begin,end; int32_t temp; end = 18; for(int i = 0;i < 4;i++)//check "*.*.*.*.* > *.*.*.*.*: UDP, length" { begin = end + 1; if((end = GetNextPos(buf,begin,'.')) < 0) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("src ip format error\n"); return -5; } temp = GetNum(buf,begin,end-1); if(temp >= 0 && temp < = 255) { title.ip_src[i] = temp; } else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("src IP error\n"); return -6; } } begin = end + 1; if((end = GetNextPos(buf,begin,' ')) < 0) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("there should be a space after src ip address\n"); return -5; } memcpy(title.port_src,buf + begin,end-begin); title.port_src[end-begin] = ''; if(buf[end+1] != '>') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("there should be a '>' after src ip address\n"); return -7; } if(buf[end+2] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("there should be a space after '>'\n"); return -8; } end += 2; for(int i = 0;i < 4;i++) { begin = end + 1; if((end = GetNextPos(buf,begin,'.')) < 0) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("dst ip format error\n"); return -5; } temp = GetNum(buf,begin,end-1); if(temp >= 0 && temp < = 255) { title.ip_dst[i] = temp; } else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("dst IP error\n"); return -6; } } begin = end + 1; if((end = GetNextPos(buf,begin,':')) < 0) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("there should be a ':' after dst ip address\n"); return -5; } memcpy(title.port_dst,buf + begin,end-begin); title.port_src[end-begin] = ''; if(buf[end+1] != ' ' || buf[end+2] != 'U' || buf[end+3] != 'D' || buf[end+4] != 'P' || buf[end+5] != ',' || buf[end+6] != ' ' || buf[end+7] != 'l' || buf[end+8] != 'e' || buf[end+9] != 'n' || buf[end+10] != 'g' || buf[end+11] != 't' || buf[end+12] != 'h' || buf[end+13] != ' ' ) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("syntax after after dst ip address\n"); return -9; } begin = end+14; if((end = GetNextPos(buf,begin,'\n')) < 0) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("length read fail!\n"); return -5; } temp = GetNum(buf,begin,end-2); if(temp >= 0) { title.length= temp; } else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("length read fail!\n"); return -6; } return 1; } static int32_t OximalString2Int(const char* oximal) { int32_t sum = 0; for(uint32_t i = 0;i < strlen(oximal);i++) { int value; if(oximal[i] >= '0' && oximal[i] < = '9') value = oximal[i] - '0'; else if(oximal[i] >= 'a' && oximal[i] < = 'f') value = oximal[i] - 'a' + 10; else { //printf("wrong line:%d\n",__LINE__); return -1; } sum = sum * 16 + value; } return sum; } static int is_packagetitle(const char* buf,str_packagetitle &title) { InitTitleStruct(title); for(int step = 0;step != -1;) { switch(step) { case 0://check and set the time if(SetTime(buf,title) == 1) step++; else return -1; break; case 1://check and set the Ip address and port format if(SetIp(buf,title) == 1) step++; else return -2; break; default:step = -1; } } return 1; } /* return @param <0:error 1:success >1:warmming */ static int CheckBodyLine(const char* string,int32_t &i32_bytenum,const int32_t i32_packagelength,char* &package) { //check " 0x" if(string[0] != '\t' || string[1] != '0' || string[2] != 'x') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("should begin with ' 0x'!\n"); return -1; } //check byte number char temp[5]; memcpy(temp,string+3,4); temp[4] = ''; if(OximalString2Int(temp) != i32_bytenum) { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("line number error!\n"); return -2; } //check": " if(string[7] != ':' || string[8] != ' ' || string[9] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("should be ': ' after line number!\n"); return -3; } int counter = i32_bytenum;//i32_bytebum-counter == byte in this line; int32_t i32_testpointer = 10; char c[16]; memset(c,'.',16); for(int ii = 0;ii < 8;ii++) { if(i32_bytenum < i32_packagelength + 28)//28 is the length of the head of the package { if(GetChar(string[i32_testpointer],string[i32_testpointer+1],c[2*ii]) == 1) { if(i32_bytenum >= 28) package[i32_bytenum-28] = c[2*ii]; i32_bytenum++; i32_testpointer += 2; if((c[2*ii] >= '0' && c[2*ii] < ='9')||(c[2*ii] >= 'A' && c[2*ii] < ='Z')||(c[2*ii] >= 'a' && c[2*ii] < ='z')) //if(c[2*ii] > 32 && c[2*ii] < = 127) ;//printf("%c",c[2*ii]); else { c[2*ii] = '.'; //printf("."); } } else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("error found in the %d byte\n",2*ii+1); return -4; } } else//the final line of the package { int32_t jj; for(jj = i32_testpointer;jj < i32_testpointer + (8-ii)*5;jj++) { if(string[jj] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("byte number is not consistent with the length showed in title!\n"); return -6; } } i32_testpointer = jj; break; } if(i32_bytenum < i32_packagelength + 28)//28 is the length of the head of the package { if(GetChar(string[i32_testpointer],string[i32_testpointer+1],c[2*ii+1]) == 1) { if(i32_bytenum >= 28) package[i32_bytenum-28] = c[2*ii+1]; i32_bytenum++; i32_testpointer += 2; if((c[2*ii+1] >= '0' && c[2*ii+1] < ='9')||(c[2*ii+1] >= 'A' && c[2*ii+1] < ='Z')||(c[2*ii+1] >= 'a' && c[2*ii+1] < ='z')) //if(c[2*ii+1] > 32 && c[2*ii+1] < = 127) ;//printf("%c",c[2*ii+1]); else { c[2*ii+1] = '.'; //printf("."); } } else { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("error found in the %d byte\n",2*(ii+1)); return -4; } } else//the final line of the package { int32_t jj; for(jj = i32_testpointer;jj < i32_testpointer + (7-ii)*5+3;jj++) { if(string[jj] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("byte number is not consistent with the length showed in title!\n"); return -6; } } i32_testpointer = jj; break; } if(string[i32_testpointer] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("format error!\n"); return -5; } i32_testpointer++; } if(string[i32_testpointer++] != ' ') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("format error!\n"); return -7; } int is_Warmming = 0; for(int32_t ii = i32_testpointer;ii < i32_testpointer + i32_bytenum - counter;ii++) { if(c[ii-i32_testpointer] != '.')//may have a more careful check { if(string[ii] == c[ii-i32_testpointer]) { continue; } else { //printf("wrong line:%d\n",__LINE__); if(Warming_ignore == 0) printf("found the %dth byte not consistent!\n",ii-i32_testpointer+1); is_Warmming = 1; } } } if(string[i32_testpointer + i32_bytenum - counter] != '') { //printf("wrong line:%d\n",__LINE__); if(show_errorinfo) printf("error happened at the end of line!\n"); return -9; } if(is_Warmming) return 2; else return 1; } static int BeforeTime(const str_time ref_time,const str_time cur_time) { if(ref_time.hour == -1) return 1; if(ref_time.hour > cur_time.hour) return 1; else if(ref_time.hour < cur_time.hour) return -1; else { if(ref_time.min > cur_time.min) return 1; else if(ref_time.min < cur_time.min) return -1; else { if(ref_time.sec > cur_time.sec) return 1; else if(ref_time.sec < cur_time.sec) return -1; else { if(ref_time.usec >= cur_time.usec) return 1; else if(ref_time.usec < cur_time.usec) return -1; } } } return -1; } static int AfterTime(const str_time ref_time,const str_time cur_time) { if(ref_time.hour == -1) return 1; if(ref_time.hour < cur_time.hour) return 1; else if(ref_time.hour > cur_time.hour) return -1; else { if(ref_time.min < cur_time.min) return 1; else if(ref_time.min > cur_time.min) return -1; else { if(ref_time.sec < cur_time.sec) return 1; else if(ref_time.sec > cur_time.sec) return -1; else { if(ref_time.usec < = cur_time.usec) return 1; else if(ref_time.usec > cur_time.usec) return -1; } } } return -1; } static int WithinTimeScale(const str_time begin_time,const str_time end_time,const str_time cur_time) { if((BeforeTime(end_time,cur_time) == 1) && (AfterTime(begin_time,cur_time) == 1)) return 1; else return -1; } int main(int argc,char* argv[]) { if(argc < 4) { printf("paramaters wrong!!\n"); printf("tcpdumpResend.exe tcpdump_file IP PORT [-i] [Begin_Time] [End_Time]\n"); printf("for example:\n./tcpdumpResend.exe a.txt 127.0.0.1 5454 -i 16:34:45.234123 16:34:46.234123\n"); exit(1); } ifstream in(argv[1],ios::in); if(! in.is_open()) { printf("file open fail!!\n"); exit(1); } char buf[BUFFER_LEN]; char *package = NULL; str_packagetitle title; int32_t i32_hanghao = 0; str_time begin_time,end_time; begin_time.hour = -1; end_time.hour = -1; if(argc > 4) { if(argv[4][0] == '-' && argv[4][1] == 'i') { Warming_ignore = 1; show_errorinfo = 0; } } if(argc > 4+Warming_ignore) { if(InitTime(argv[4+Warming_ignore],begin_time) != 1) { printf("begin time error!!\n"); exit(1); } } if(argc > 5+Warming_ignore) { if(InitTime(argv[5+Warming_ignore],end_time) != 1) { printf("end time error!!\n"); exit(1); } } if(argc > 6+Warming_ignore) { printf("syntax error!\n"); exit(1); } int sockfd = socket(AF_INET,SOCK_DGRAM,0); if(sockfd < 0) { printf("socket create fail!!\n"); exit(1); } int size=109568*20; int size_len = sizeof(size); int nSockRes = setsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,(char*)&size,(socklen_t)size_len); nSockRes = getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,(char*)&size,(socklen_t*)&size_len); //printf("%d\n",size); int port = atoi(argv[3]); if(port == 0) { printf("port error!!\n"); close(sockfd); exit(1); } struct sockaddr_in address; int len = sizeof(address); address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = inet_addr(argv[2]); if(address.sin_addr.s_addr == INADDR_NONE) { printf("IP address error!!\n"); close(sockfd); exit(1); } printf("Attention:\n\trecommend format of tcpdump:tcpdump -s0 -an -X...\n\n"); int send_num = 0; while(!in.eof()) { in.getline(buf,BUFFER_LEN,'\n'); i32_hanghao++; if(strlen(buf) == 0) break; if(is_packagetitle(buf,title) == 1) { if(package) delete []package; package = new char[title.length]; int32_t i32_bytenum = 0; for(int i = 0;i < int((title.length+28)/16) + ((title.length+28)%16 != 0);i++) { in.getline(buf,BUFFER_LEN,'\n'); i32_hanghao++; int checkline_result = CheckBodyLine(buf,i32_bytenum,title.length,package); if(checkline_result < 0) { printf("error!! line:%d\n",i32_hanghao); close(sockfd); exit(1); } else if(checkline_result == 2 && Warming_ignore == 0) { printf("warmming!! line:%d\n",i32_hanghao); } } if(WithinTimeScale(begin_time,end_time,title.time) == 1) { sendto(sockfd,package,title.length,0,(sockaddr*)&address,len); send_num++; if(send_num % PACKAGE_SEND_LIMIT == 0) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec= SELECT_WAITTIME; select(0, NULL, NULL, NULL ,&tv); } } } else { printf("error!! line:%d\n",i32_hanghao); close(sockfd); exit(1); } } if(package) delete []package; close(sockfd); in.close(); return 0; }
【完】
本文内容遵从CC版权协议,转载请注明出自http://www.kylen314.com