/******************************************************************************* M O D - C A P Modify and manipulate PCAP file for lab/test purpouses, See the following references: - http://wiki.wireshark.org/Development/LibpcapFileFormat - http://en.wikipedia.org/wiki/Transmission_Control_Protocol - http://en.wikipedia.org/wiki/User_Datagram_Protocol - http://en.wikipedia.org/wiki/Internet_Protocol - http://en.wikipedia.org/wiki/IPv4 - http://en.wikipedia.org/wiki/IPv6 You can change time, speed and rate of the file (not it's content) Contatcs: --------- marco . crotta (at) gmail . com Latest version: --------------- http://www.emcy.it/Linux/files/modcap.c Compilation: ------------ Compile with "g++ -O3 -omodcap modcap.c". This code makes use of STL libray, so check it first For the same reason it will NOT compile with gcc or other similar Note: ----- Just a fast job to get things going, nothing you can trust too much even if test with wireshark resuted good enought. (C) Copyright 2007 Marco Crotta, Released under GPL(2) Licence. This is free software Version: -------- */ #define VERSION "V 0.0.5 (2008/05/22)" /* Next Steps: ----------- * complete it! * adjust overall speed * debug... debug... debug... debug... History: -------- V 0.0.1 (2007/12/18) First experimental Release V 0.0.2 (2008/03/20) Lot of Debug, more is likely to come V 0.0.3 (2008/03/28) Still more debug... and more to come Added "-b" option: minimum Mbps Added "-i" option: modify ip addres Added "-m" option: motify MAC address v 0.0.4 (2008/04/05) Added "-d" option: modify IPv4/UDP port v 0.0.5 (2008/04/05) Debug in IP/TCP Checksum Debug in MAC address change *******************************************************************************/ /******************************************************************************* D E F I N E S & I N C L U D E S *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define guint32 unsigned int #define guint16 unsigned short int #define gint32 int #define gint16 short int #define byte unsigned char #define STD_IN 0 #define STD_OUT 1 #define STD_ERR 2 #define PACKLEN 65535 #define MICRO 1000000 #define BUFFSIZE 1024 #define DEBUG 1 #define INFO 2 #define WARNING 3 #define ERROR 4 #define CRITICAL 5 #define ETHEADER 14 // Macros #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) /******************************************************************************* S T R U C T S *******************************************************************************/ // Global FILE header typedef struct pcap_hdr_s { guint32 magic_number; /* magic number */ guint16 version_major; /* major version number */ guint16 version_minor; /* minor version number */ gint32 thiszone; /* GMT to local correction */ guint32 sigfigs; /* accuracy of timestamps */ guint32 snaplen; /* max length of captured packets, in octets */ guint32 network; /* data link type */ } pcap_hdr_t; // Single PCAP record Header typedef struct pcaprec_hdr_s { guint32 ts_sec; /* timestamp seconds */ guint32 ts_usec; /* timestamp microseconds */ guint32 incl_len; /* number of octets of packet saved in file */ guint32 orig_len; /* actual length of packet */ } pcaprec_hdr_t; // Single PCAP record = Header + Data typedef struct pcaprec{ pcaprec_hdr_t header; byte body[PACKLEN]; } pcaprec_t; /******************************************************************************* G L O B A L V A R S *******************************************************************************/ // Command line parameters values long double Param=0.0; char StrParam[BUFFSIZE]; int Grane=1; // Logging Vars int Log_File = STD_OUT; int Log_RecordDate=1; int Log_RecordPid=0; int Log_RecordLevel=1; int Log_Trigger=DEBUG; //int Log_Trigger=INFO; // Files int InFile=0; int OutFile=0; /******************************************************************************* F U N C T I O N S *******************************************************************************/ void DateStr (char* buff,char* append) { /// Put's actual Date in 'YYYY-MM-DD HH:mm:ss' format into buff and append an extra /// string to it (if provided) time_t now; struct tm now_str; char e=0,*A; time(&now); gmtime_r(&now, &now_str); A = (append)? append:&e; sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d%s", 1900+now_str.tm_year, 1+now_str.tm_mon, now_str.tm_mday, now_str.tm_hour, now_str.tm_min, now_str.tm_sec, A); } void Log(int level, const char* string, ...) { char newstring[BUFFSIZE]; va_list ap; int r; /// Logging is done only if the level is higher the the defined LogLevel parameter if (level < Log_Trigger) return; /// If a LogFile is not defined simply return without doing anything if (Log_File < 0) return; /// Otherwise write to the file bzero(newstring,1024); if (Log_RecordDate) DateStr(newstring,(char*) " "); if (Log_RecordPid) sprintf(newstring,"%s%06u ",newstring,(unsigned long)pthread_self()); if (Log_RecordLevel) { switch (level) { case 1: sprintf(newstring,"%s%s ",newstring,"DEBUG "); break; case 2: sprintf(newstring,"%s%s ",newstring,"INFO "); break; case 3: sprintf(newstring,"%s%s ",newstring,"WARNING "); break; case 4: sprintf(newstring,"%s%s ",newstring,"ERROR "); break; case 5: sprintf(newstring,"%s%s ",newstring,"CRITICAL"); break; default:sprintf(newstring,"%s%s ",newstring,"--*?*-- "); break; } } va_start(ap, string); r = vsprintf(&newstring[strlen(newstring)],string, ap); va_end(ap); sprintf(newstring,"%s\n",newstring); write (Log_File, newstring, MIN(strlen(newstring),BUFFSIZE) ); sync(); } void Usage() { printf("modcap: modify a PCAP file in \"shape\" speed, time and content.\n"); printf("Version: %s\n",VERSION); printf("Usage: modcap [operation] [parameter] <[] []> [infile]\n"); printf(" one operation only and it's parameter should be supplied at the time\n"); printf(" otherwise result could be messy\n"); printf("Operatoins:\n"); printf("time: -t : set capture time to secs afther EPOC (gen 1st 1970, 00:00:00)\n"); printf(" -s : shift capture time by secs\n"); printf("speed: -P : Maximum packet per seconds rate (slowdown faster parts)\n"); printf(" -p : Minimum packet per seconds rate (speedup slower parts)\n"); printf(" -B : Maximum MBits per seconds rate (slowdown faster parts)\n"); printf(" -b : Minimum MBits per seconds rate (speedup slower parts)\n"); printf("file: -o : Output file name\n"); printf("address:-i : change any occurrence of ip1 (in IP headers) to ip2\n"); printf(" (do NOT use spaces in the parameter!)\n"); printf(" -m : change any occurence of MAC address mac1 to mac2\n"); printf(" (do NOT use spaces in the parameter!)\n"); printf(" -d : change any occurrence of TCP/UDP port port1 to port2\n"); printf(" (do NOT use spaces in the parameter!)\n"); printf("\n"); _exit(0); } int CheckIPAddress(char* IP) { struct in_addr dst; int r=inet_aton(IP, &dst); Log(DEBUG,"IP = %x",dst.s_addr); return ((r==0)? -1 : 1); } int CheckMACAddress(char* MAC) { guint32 hex[6]; char check[20]; memset(check,':',20); sscanf (MAC,"%02x:%02x:%02x:%02x:%02x:%02x",&hex[0],&hex[1],&hex[2],&hex[3],&hex[4],&hex[5]); sprintf(check,"%02x:%02x:%02x:%02x:%02x:%02x",hex[0],hex[1],hex[2],hex[3],hex[4],hex[5]); Log(DEBUG,"Checking %s -> %s", MAC, check); if (strcmp(MAC,check)==0) return 1; else return -1; } /******************************************************************************* PCAP HELPER FUNCTIONS *******************************************************************************/ void CopyFileHeader() { /// Copy the PCAP Header from source to dest int i; pcap_hdr_t FH; lseek(InFile,0,SEEK_SET); lseek(OutFile,0,SEEK_SET); Log(DEBUG,"Out file ok"); i=read(InFile,&FH, sizeof(FH)); Log(DEBUG,"Pcap File Header read %i bytes",i); i=write(OutFile,&FH,sizeof(FH)); Log(DEBUG,"Pcap File Header write %i bytes",i); } int ReadRec(pcaprec_t *PR) { /// Read 1 PCAP Record from Source, return the size of the record guint32 i,j; i=read(InFile, &(PR->header), sizeof(pcaprec_hdr_t)); if (i!=sizeof(pcaprec_hdr_t)) { Log(ERROR,"Header read resulted in %i bytes, expeted %i",i,sizeof(pcaprec_hdr_t)); return -1; } bzero(PR->body, PACKLEN); j=read(InFile, &(PR->body), PR->header.incl_len); if (j!=PR->header.incl_len) { Log(ERROR,"Body read resulted in %i bytes, expeted %i",i,sizeof(pcaprec_hdr_t)); return -1; } return i+j; } int WriteRec(pcaprec_t *PR) { /// Write the passed record to destination file. int w = sizeof(pcaprec_hdr_t) + PR->header.incl_len, W = 0; W=write(OutFile, PR, w); if (W!=w) { Log(ERROR,"OutFile Write resulted in &i bytes, expeted %i",W,w); return -1; } return W; } guint32 CountNextSecondPackets() { /// Count how many packet are in the next second of recorded data guint32 Res=0; pcaprec_t Rec; off_t InitialPos=lseek(InFile, 0, SEEK_CUR); /// Get & Save File position guint32 Delta = 0; guint32 Prev_sec = 0; guint32 Prev_usec = 0; if (InitialPos==-1) return -1; if (ReadRec(&Rec)==-1) return -1; Res++; Prev_sec = Rec.header.ts_sec; Prev_usec = Rec.header.ts_usec; while ( ReadRec(&Rec) > 0) { //Log (DEBUG,"looping in CountNextSecondPackets "); Delta += ((Rec.header.ts_sec - Prev_sec)*MICRO + (Rec.header.ts_usec - Prev_usec)); if (Delta > MICRO) break; Res++; Prev_sec = Rec.header.ts_sec; Prev_usec = Rec.header.ts_usec; } /// Restore previous position lseek(InFile, InitialPos, SEEK_SET); return Res; } guint32 CountNextSecondBytes() { /// Count how many bytes are in the next second of recorded data guint32 Res=0; pcaprec_t Rec; off_t InitialPos=lseek(InFile, 0, SEEK_CUR); /// Get & Save File position guint32 Delta = 0; guint32 Prev_sec = 0; guint32 Prev_usec = 0; if (InitialPos==-1) return -1; if (ReadRec(&Rec)==-1) return -1; Res+=Rec.header.incl_len; Prev_sec = Rec.header.ts_sec; Prev_usec = Rec.header.ts_usec; while ( ReadRec(&Rec) > 0) { //Log (DEBUG,"looping in CountNextSecondPackets "); Delta += ((Rec.header.ts_sec - Prev_sec)*MICRO + (Rec.header.ts_usec - Prev_usec)); if (Delta > MICRO) break; Res+=Rec.header.incl_len; Prev_sec = Rec.header.ts_sec; Prev_usec = Rec.header.ts_usec; } /// Restore previous position lseek(InFile, InitialPos, SEEK_SET); return Res; } /******************************************************************************* COMMAND FUNCTIONS *******************************************************************************/ void SetTime() { /// Shift file time: pcaprec_t PR; gint32 Delta; /// Copy Header and calculate time difference CopyFileHeader(); ReadRec(&PR); Delta=(PR.header.ts_sec - ((guint32)round(Param))); Log(DEBUG,"Delta is %i, Param is %Lf,Orig is %i", Delta,Param, PR.header.ts_sec); PR.header.ts_sec -= Delta; /// Iterate: read each record and change his time WriteRec(&PR); while (ReadRec(&PR) > 0) { PR.header.ts_sec -= Delta; WriteRec(&PR); } } void ShiftTime() { pcaprec_t PR; CopyFileHeader(); /// Blindly apply a shift in dime/date of each record Log(DEBUG,"Shift is %Lf (%i)",Param, ((gint32)round(Param))); while (ReadRec(&PR) > 0) { PR.header.ts_sec += ((gint32)round(Param)); WriteRec(&PR); } } void SetMaxMBps() { pcaprec_t PR; guint32 Delta = 0; guint32 Delta_sec = 0; guint32 Delta_usec = 0; guint32 Prev_sec = 0; guint32 Prev_usec = 0; /// GH! due to speed and values the resolution of the /// counters is not small enought !! long double MaxDelta = (Param*1024*1024)/(8*MICRO); //Bytes each 1/1000000 sec guint32 MaxBytes = 0; CopyFileHeader(); /// Get First Packet and write it unhanged ReadRec(&PR); WriteRec(&PR); Prev_sec=PR.header.ts_sec; Prev_usec=PR.header.ts_usec; while (ReadRec(&PR) > 0) { /// Apply (commulative) shift forward (and normalyze) PR.header.ts_usec += Delta_usec; PR.header.ts_sec += Delta_sec; while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } /// Get usecs ( = 1/1000000 sec) between this new Record and previous one Delta = (PR.header.ts_sec - Prev_sec ) * MICRO; Delta += (PR.header.ts_usec - Prev_usec); ///Bytes allowed in this Delta MaxBytes = (guint32)(round(Delta*MaxDelta)); //Log(DEBUG,"Delta is %i, MaxDelta is %Lf, MaxBytes is %Li",Delta,MaxDelta,MaxBytes); /// Compare Bytes read and Max allowed if (MaxBytes < PR.header.incl_len) { /// Too much! delay packet time further Delta_usec += ((guint32)ceil( (PR.header.incl_len-MaxBytes)/MaxDelta )); while (Delta_usec >= MICRO) { Delta_usec -= MICRO; Delta_sec++; } //Log(DEBUG,"Delta_sec is %i, Delta_usec is %i",Delta_sec, Delta_usec); /// Apply another shift forward (and normalyze) PR.header.ts_usec += ((guint32)ceil( (PR.header.incl_len-MaxBytes)/MaxDelta )); while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } } /// Remember values for next Packet Prev_sec=PR.header.ts_sec; Prev_usec=PR.header.ts_usec; WriteRec(&PR); } } void SetMaxPps() { pcaprec_t PR; guint32 Delta = 0; guint32 Delta_sec = 0; guint32 Delta_usec = 0; guint32 Prev_sec = 0; guint32 Prev_usec = 0; guint32 MinUDelta = MICRO / ((guint32)round(Param)); if (Param > MICRO) { Log(ERROR,"Rate is too high !!"); return; } /// Number of microseconds between two subsequent packets //Log (DEBUG,"MinUDelta is %i",MinUDelta); CopyFileHeader(); /// Get First Packet ReadRec(&PR); WriteRec(&PR); Prev_sec=PR.header.ts_sec; Prev_usec=PR.header.ts_usec; while (ReadRec(&PR) > 0) { /// Apply (cummulative) time shift of packets PR.header.ts_usec += Delta_usec; PR.header.ts_sec += Delta_sec; while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } /// Microseconds between this read packet and previous Delta = (PR.header.ts_sec-Prev_sec)*MICRO; Delta += PR.header.ts_usec - Prev_usec; //Log(DEBUG,"Delta is %i, MinUDelta is %i",Delta,MinUDelta); if (Delta < MinUDelta) { Delta_usec +=(MinUDelta-Delta+1); while (Delta_usec >= MICRO) { Delta_usec -= MICRO; Delta_sec++; } //Log(DEBUG,"Delta_sec is %i, Delta_usec is %i",Delta_sec, Delta_usec); PR.header.ts_usec += (MinUDelta-Delta+1); while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } } Prev_sec = PR.header.ts_sec; Prev_usec = PR.header.ts_usec; WriteRec(&PR); } } void SetMinPps() { pcaprec_t PR; guint32 Delta_sec=0; guint32 Delta_usec=0; guint32 Prev_sec=0; guint32 Prev_usec=0; int NSP; if (Param > MICRO) { Log(ERROR,"Rate is too high !!"); return; } CopyFileHeader(); while (1) { /// How many packets in next second of load? NSP=(int)CountNextSecondPackets(); //Log (DEBUG,"looping in SetMinPps, NSP=%i",NSP); if (NSP<0) /// EOF already reached, exit loop break; if (NSP > Param) for (;NSP;NSP--) { /// Write Packet as they are, shifting backwards ReadRec(&PR); PR.header.ts_sec -= Delta_sec; if (PR.header.ts_usec >= Delta_usec) PR.header.ts_usec -= Delta_usec; else { PR.header.ts_sec--; PR.header.ts_usec += (MICRO-Delta_usec); } WriteRec(&PR); } else { /// Read First Packet of this burst, shift back, write ReadRec(&PR); PR.header.ts_sec -= Delta_sec; if (PR.header.ts_usec >= Delta_usec) PR.header.ts_usec -= Delta_usec; else { PR.header.ts_sec--; PR.header.ts_usec += (MICRO-Delta_usec); } WriteRec(&PR); /// Store beginning of burst Prev_sec=PR.header.ts_sec; Prev_usec=PR.header.ts_usec; for (int i=1;i<=NSP;i++) { /// Read, shift ReadRec(&PR); /// Compress PR.header.ts_sec = Prev_sec; PR.header.ts_usec = (guint32)(Prev_usec + MICRO*i/Param); while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } /// Write WriteRec(&PR); } /// Update Shift Delta_usec += (guint32)(MICRO*(Param-NSP)/Param); while (Delta_usec >= MICRO) { Delta_usec -= MICRO; Delta_sec++; } //Log (DEBUG,"Delta_sec %i, Delta_usec %i", Delta_sec, Delta_usec); } } } void SetMinMbps() { pcaprec_t PR; guint32 Delta_sec=0; guint32 Delta_usec=0; guint32 Prev_sec=0; guint32 Prev_usec=0; guint32 NSB=0; guint32 NSP=0; /// From MegaBits/sec to Bytes/sec unsigned long LParam = (unsigned long)(Param*1024*1024/8); CopyFileHeader(); while (1) { /// How many Bytes in next second of load? NSB=(int)CountNextSecondBytes(); Log (DEBUG,"looping in SetMinPps, NSB=%i, NSP=%i, LPar=%i",NSB,NSP,LParam); if (NSB<0) /// EOF already reached, exit loop break; if (NSB > LParam) { NSP=CountNextSecondPackets(); for (;NSP;NSP--) { /// Write Packet as they are, shifting backwards ReadRec(&PR); PR.header.ts_sec -= Delta_sec; if (PR.header.ts_usec >= Delta_usec) PR.header.ts_usec -= Delta_usec; else { PR.header.ts_sec--; PR.header.ts_usec += (MICRO-Delta_usec); } WriteRec(&PR); } } else { NSP=CountNextSecondPackets(); /// Read First Packet of this burst, shift, write ReadRec(&PR); PR.header.ts_sec -= Delta_sec; if (PR.header.ts_usec >= Delta_usec) PR.header.ts_usec -= Delta_usec; else { PR.header.ts_sec--; PR.header.ts_usec += (MICRO-Delta_usec); } WriteRec(&PR); /// Store beginning of burst Prev_sec=PR.header.ts_sec; Prev_usec=PR.header.ts_usec; for (guint32 i=1;i<=NSP;i++) { /// Read, shift ReadRec(&PR); /// Compress PR.header.ts_sec = Prev_sec; PR.header.ts_usec = (guint32)(Prev_usec + MICRO*((float)i*NSB)/((float)LParam*NSP)); while (PR.header.ts_usec >= MICRO) { PR.header.ts_usec -= MICRO; PR.header.ts_sec++; } /// Write WriteRec(&PR); } /// Update Shift Delta_usec += (guint32)(MICRO*(float)(LParam-NSB)/(float)LParam); while (Delta_usec >= MICRO) { Delta_usec -= MICRO; Delta_sec++; } Log (DEBUG,"Delta_sec %i, Delta_usec %i", Delta_sec, Delta_usec); } } } void ChangeIP() { char *ip1=StrParam; char *ip0=strstr(StrParam,","); char *ip2=ip0+1; struct in_addr dst; guint32 Lip1,Lip2,Lip1H,Lip2H; pcaprec_t Rec; int match; int RunLen=0; int DeltaCks; guint16 cks; guint32 Checksum=0; *ip0 = 0; inet_aton(ip1, &dst); Lip1 = dst.s_addr; inet_aton(ip2, &dst); Lip2 = dst.s_addr; Log(DEBUG,"IPs are %x , %x",Lip1,Lip2); // Pre calculate part of the Checksum difference Lip1H=ntohl(Lip1); Lip2H=ntohl(Lip2); DeltaCks = ( ((Lip2H>>16)&0xFFFF) + (Lip2H&0xFFFF) ); DeltaCks -= ( ((Lip1H>>16)&0xFFFF) + (Lip1H&0xFFFF) ); DeltaCks = ( DeltaCks>>16 ) + (DeltaCks & 0xFFFF); //Log(DEBUG,"DeltaCks=%04x",DeltaCks); CopyFileHeader(); while(ReadRec(&Rec)>0) { // Find Match (can it be both???) match=-1; if (memcmp(&Lip1,&Rec.body[ETHEADER+12],4)==0) match=12; if (memcmp(&Lip1,&Rec.body[ETHEADER+16],4)==0) match=16; if (match>=0) { // lenth of IP Header guint32 IPHeader=(Rec.body[ETHEADER+0] & 0x0F)<<2; /// Change the address memcpy(&Rec.body[ETHEADER+match],&Lip2,4); /// FIX IP Header Checksum RunLen = IPHeader; bzero (&Rec.body[ETHEADER+10],2); Checksum=0; for (int i=0; i> 16) + (Checksum & 0xFFFF); Checksum+= (Checksum >> 16); cks=(signed short)htons(~Checksum); memcpy(&Rec.body[ETHEADER+10],&cks,2); /// If TCP fix UDP/TCP Header Checksum too if ( (Rec.body[ETHEADER+9]==0x06) || (Rec.body[ETHEADER+9]==0x11) ) { guint32 L4Header=ETHEADER+IPHeader; Checksum=0; // Clear old checksum switch (Rec.body[ETHEADER+9]) { case 0x06 : Checksum = (Rec.body[L4Header+16]<<8)+Rec.body[L4Header+17]; break; case 0x11 : Checksum = (Rec.body[L4Header+6]<<8)+Rec.body[L4Header+7]; break; } /// Since I Know 'what' changed I also Know How that made the Chesum change /// so don't compute all bach, just the difference ;-) Checksum = (~Checksum)&0xFFFF; Checksum += DeltaCks; //Log (DEBUG,"Chsum=%06x",Checksum); Checksum = (Checksum >> 16) + (Checksum & 0xFFFF); cks=(signed short)htons(~Checksum); // Write Checksum switch (Rec.body[ETHEADER+9]) { case 0x06 : memcpy(&Rec.body[L4Header+16],&cks,2); break; case 0x11 : memcpy(&Rec.body[L4Header+6],&cks,2); break; } } // TCP or UDP } // if (match) WriteRec(&Rec); } // while read } void ChangeMAC () { char *mac1=StrParam; char *mac0=strstr(StrParam,","); char *mac2=mac0+1; byte Mac1[6],Mac2[6]; pcaprec_t Rec; int match; *mac0 = 0; sscanf (mac2,"%02x:%02x:%02x:%02x:%02x:%02x",&Mac2[0],&Mac2[1],&Mac2[2],&Mac2[3],&Mac2[4],&Mac2[5]); sscanf (mac1,"%02x:%02x:%02x:%02x:%02x:%02x",&Mac1[0],&Mac1[1],&Mac1[2],&Mac1[3],&Mac1[4],&Mac1[5]); CopyFileHeader(); while(ReadRec(&Rec)>0) { // Find Match (can it be both???) match=-1; if (memcmp(Mac1,&Rec.body[0],6)==0) match=0; if (memcmp(Mac1,&Rec.body[6],6)==0) match=6; if (match>=0) { // Repalce Address memcpy(&Rec.body[match],Mac2,6); // Log(DEBUG,"m=%i, M1=%012h, M2=%012h",match,Mac1,Mac2); } WriteRec(&Rec); } // while read } void ChangePort () { char *Port1=optarg; char *Port0=strstr(optarg,","); char *Port2=Port0+1; pcaprec_t Rec; gint32 match; guint16 port1; guint16 port2; guint16 port; *Port0=0; port1=strtol(Port1,NULL,10); port2=strtol(Port2,NULL,10); CopyFileHeader(); while(ReadRec(&Rec)>0) { guint32 IPHeader=(Rec.body[ETHEADER+0] & 0x0F)<<2; /// Find Match (can it be both???) match=-1; port=(Rec.body[ETHEADER+IPHeader]<<8) +Rec.body[ETHEADER+IPHeader+1]; if (port==port1) match=ETHEADER+IPHeader; port=(Rec.body[ETHEADER+IPHeader+sizeof(guint16)]<<8) +Rec.body[ETHEADER+IPHeader+sizeof(guint16)+1]; if (port==port1) match=ETHEADER+IPHeader+sizeof(guint16); if (match>=0) { guint32 Checksum=0; guint16 cks=0; /// lenth of IP Header guint32 IPHeader=(Rec.body[ETHEADER+0] & 0x0F)<<2; guint32 TCPHeader= IPHeader+ETHEADER; guint32 RunLen = (Rec.body[ETHEADER+2]<<8) + (Rec.body[ETHEADER+3]) - IPHeader; /// Repalce PORT Rec.body[match] = (port2 & 0xFF00)>>8; Rec.body[match+1] = (port2 & 0x00FF); /// Clear Previous Checksum a Bytes bzero (&Rec.body[TCPHeader+16],2); /// Summ Header and Dat for (int i=0; i> 16) + (Checksum & 0xFFFF); Checksum+= (Checksum >> 16); cks=(signed short)htons(~Checksum); memcpy(&Rec.body[TCPHeader+16],&cks,2); } WriteRec(&Rec); } // while read } /******************************************************************************* M A I N *******************************************************************************/ int main (int argc, char **argv) { int opt,firstrun=1; char InFileName[BUFFSIZE]; char OutFileName[BUFFSIZE]; char TmpFileName[BUFFSIZE]; char *endptr; pcaprec_t mover; /// Check Parameters Number if (argc < 4) { Log(ERROR,"Not enought Parameters Provided"); Usage(); } /// Input/Output Files Operations bzero(InFileName,BUFFSIZE); bzero(OutFileName,BUFFSIZE); /// Check Command & Parameter while ((opt = getopt(argc, argv, "t:s:P:p:B:b:o:i:m:d:")) != -1) { Param=-1; switch (opt) { case 't': case 's': case 'B': case 'b': case 'P': case 'p': /// Param is numeric only for commands stated above Param = strtold(optarg, &endptr); if (endptr==optarg) { Log(ERROR,"No digits found in parameter!"); Usage(); } if ((errno == ERANGE && (Param == LONG_MAX || Param == LONG_MIN)) || (errno != 0 && Param == 0)) { Log(ERROR,"Wrong parameter (value or type)"); Usage(); } /// Command Specific Parameter Checks if (opt != 's') Param=(Param<0)?-1.0*Param:Param; case 'o': /// Other commands may allow a strign (non numeric) parameter if (opt == 'o') strcat(OutFileName,optarg); break; case 'i': /// Change IP address in IP Packets if (strstr(optarg,",")==NULL) { Log(ERROR,"Wrong parameter for IP parameter"); Usage(); } else { char *ip1=optarg; char *ip0=strstr(optarg,","); char *ip2=ip0+1; *ip0=0; if (CheckIPAddress(ip1)<0) { Log(ERROR,"Parameter %s is not a valid IPv4 address",ip1); Usage(); } if (CheckIPAddress(ip2)<0) { Log(ERROR,"Parameter %s is not a valid IPv4 address",ip2); Usage(); } *ip0=','; sprintf(StrParam,"%s",optarg); } break; case 'm': if (strstr(optarg,",")==NULL) { Log(ERROR,"Wrong parameter for MAC parameter"); Usage(); } else { char *mac1=optarg; char *mac0=strstr(optarg,","); char *mac2=mac0+1; *mac0=0; if (CheckMACAddress(mac1)<0) { Log(ERROR,"Parameter %s is not a valid MAC address",mac1); Usage(); } if (CheckMACAddress(mac2)<0) { Log(ERROR,"Parameter %s is not a valid MAC address",mac2); Usage(); } *mac0=','; sprintf(StrParam,"%s",optarg); } break; case 'd': if (strstr(optarg,",")==NULL) { Log(ERROR,"Wrong parameter for Port parameter"); Usage(); } else { char *port1=optarg; char *port0=strstr(optarg,","); char *port2=port0+1; gint32 port=-1; *port0=0; port=-1;port=strtol(port1,NULL,10); if (port<0 || port>0xFFFF) { Log(ERROR,"Parameter %s is not a valid Port address",port1); Usage(); } port=-1;port=strtol(port2,NULL,10); if (port<0 || port>0xFFFF) { Log(ERROR,"Parameter %s is not a valid Port address",port2); Usage(); } *port0=','; sprintf(StrParam,"%s",optarg); } break; default: Usage(); break; } // switch (opt...1) Log(DEBUG,"Command: %c",opt); // No operation should be performed here if (opt == 'o') continue; /// Get / Open Input file if (firstrun) InFile=open(argv[argc-1],O_RDONLY); else InFile=open(TmpFileName,O_RDONLY); if (InFile==-1) { Log(ERROR,"Can't open IN file for reading"); Usage(); } Log(DEBUG,"IN file ok"); /// Play with temp(out) file for operations memcpy(InFileName,TmpFileName,BUFFSIZE); bzero(TmpFileName,BUFFSIZE); sprintf(TmpFileName,"/tmp/modcap_tmp_XXXXXX"); OutFile=mkstemp(TmpFileName); if (!strlen(TmpFileName)) { Log(ERROR,"Can't create tmp file %s",TmpFileName); close(InFile); _exit(0); } //OutFile=open(TmpFileName,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (OutFile==-1) { Log(ERROR,"Can't open file %s for writing",TmpFileName); close(InFile); _exit(0); } Log(DEBUG,"Tmp file %s ok",TmpFileName); /// Perform actual operation (if any) switch (opt) { case 't': SetTime(); break; case 's': ShiftTime(); break; case 'B': SetMaxMBps(); break; case 'b': SetMinMbps(); break; case 'P': SetMaxPps(); break; case 'p': SetMinPps(); break; case 'i': ChangeIP(); break; case 'm': ChangeMAC(); break; case 'd': ChangePort(); break; } /// Close all involved files close (InFile); close (OutFile); sync(); /// Delete "InputFile", but not on first loop if (!firstrun) { unlink (InFileName); bzero (InFileName,BUFFSIZE); } /// Go on firstrun=0; } // while (getopt()) /// Check/Make final Output file name if (OutFileName[0]==0) { /// Creates new file name (appending a '_' to the name of the source file) strcat(OutFileName,argv[argc-1]); strcat(OutFileName,"_"); } OutFile=open(OutFileName,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (OutFile==-1) { Log(ERROR,"Can't open file %s for writing",OutFileName); close(InFile); _exit(0); } Log (DEBUG,"Using %s as output file name",OutFileName); /// Open Last TMP file for reading InFile=open(TmpFileName,O_RDONLY); /// Copy CopyFileHeader(); while(ReadRec(&mover)>0) { WriteRec(&mover); } Log(DEBUG,"Out file ok"); /// Finally remove last TMP file unlink (TmpFileName); }