This file talks about converting .txt file to .pcap format file for wireshark.
Descriptions
Some time we may get the tcpdump logs, but we can't decode it in details like wireshark. For example.
>> tcpdump -i veip0.1 -s0 -eXxf host 199.71.142.187
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veip0.1, link-type EN10MB (Ethernet), capture size 65535 bytes
16:17:49.019616 d0:72:dc:8a:eb:30 (oui Unknown) > 00:06:31:eb:2d:f2 (oui Unknown), ethertype IPv4 (0x0800), length 74: 199.71.142.187.39117 > 100.74.0.180.30005: Flags [S], seq 1557343732, win 5840, options [mss 1380,sackOK,TS val 3117615132 ecr 0,nop,wscale 7], length 0
0x0000: 4500 003c d803 0000 0106 26b8 c747 8ebb E..<......&..G..
0x0010: 644a 00b4 98cd 7535 5cd3 2df4 0000 0000 dJ....u5\.-.....
0x0020: a002 16d0 1bc5 0000 0204 0564 0402 080a ...........d....
0x0030: b9d3 081c 0000 0000 0103 0307 ............
16:17:49.020058 00:06:31:eb:2d:f2 (oui Unknown) > d0:72:dc:8a:eb:30 (oui Unknown), ethertype IPv4 (0x0800), length 74: 100.74.0.180.30005 > 199.71.142.187.39117: Flags [S.], seq 1367236701, ack 1557343733, win 14480, options [mss 1460,sackOK,TS val 4821547 ecr 3117615132,nop,wscale 5], length 0
0x0000: 4500 003c 0000 4000 4006 7fbb 644a 00b4 E..<..@.@...dJ..
0x0010: c747 8ebb 7535 98cd 517e 605d 5cd3 2df5 .G..u5..Q~`]\.-.
0x0020: a012 3890 bb2f 0000 0204 05b4 0402 080a ..8../..........
0x0030: 0049 922b b9d3 081c 0103 0305 .I.+........
We may want this view

This file talks about the format of .pcap files, and implement it in C code.
Format of .pcap file
Format := [file_header][packet_header_1][packet_data_1][packet_header_2][packet_data_2]...[packet_header_N][packet_data_N]
typedef unsigned long DWORD;/* 4 BYTES*/
typedef unsigned short WORD;/* 2 BYTES*/
typedef unsigned char BYTE;
/* file type */
typedef struct pcap_file_header {
DWORD magic; /* magic number ,The magic number has the value hex a1b2c3d4. */
WORD version_major; /* major version number,The major version number should have the value 2. */
WORD version_minor; /* minor version number,The minor version number should have the value 4. */
DWORD thiszone; /* time zone offset field that actually not used, so you can (and probably should) just make it 0 */
DWORD sigfigs; /* time stamp accuracy field tha not actually used,so you can (and probably should) just make it 0*/
DWORD snaplen; /* snapshot length" field;The snapshot length field should be the maximum number of bytes perpacket that will be captured. If the entire packet is captured, make it 65535; if you only capture, for example, the first 64 bytes of the packet, make it 64.*/
DWORD linktype; /* link layer type field.The link-layer type depends on the type of link-layer header that the packets in the capture file have
0 BSD loopback devices, except for later OpenBSD
1 Ethernet, and Linux loopback devices
6 802.5 Token Ring
7 ARCnet
8 SLIP
9 PPP
10 FDDI
100 LLC/SNAP-encapsulated ATM
101 raw IP, with no link
102 BSD/OS SLIP
103 BSD/OS PPP
104 Cisco HDLC
105 802.11
108 later OpenBSD loopback devices (with the AF_value in network byte order)
113 special Linux cooked capture
114 LocalTalk */
} T_pcap_file_header;
/* time stamp */
struct tim {
DWORD GMTtime; /* UNIX-format time-in-seconds when the packet was captured. i.e. the number of seconds since January 1,1970, 00:00:00 GMT (that GMT, *NOT* local time!) */
DWORD microTime; /* the number of microseconds since that second when the packet was captured. */
};
/* Packet header */
typedef struct pcap_pkthdr {
struct tim ts; /* time stamp */
DWORD caplen; /* value giving the number of bytes of packet data that were captured. */
DWORD len; /* value giving the actual length of the packet, in bytes (which may be greater than the previous number, if you are not saving the entire packet).*/
} T_pcap_pkthdr;
/* The packet data is the frame date. For example, Ethernet frame. */
Parse the txt file
In the example, there're 2 types of txt lines: 1) descriptions and 2) data.
(I think the script may be easier than C language to parse it.)
To parse the descriptions, a new structure is defined to record these inform we'll uses later.
typedef struct desc_parse {
struct tim ts;
char macSrc[20];
char macDst[20];
unsigned int pro;
} T_desc_parse;
int parseDesc(const char *input, T_desc_parse *pDescParse);
To parse data, we also define a structure.
typedef struct pcap_data
{
T_pcap_pkthdr header;
BYTE dataBuff[DATA_BUFFER_MAX];
DWORD dataIndex;/* start from 0 */
} T_pcap_data;
int parseData(const char *input, T_pcap_data *pDataBuff);
And the program will read the txt file and output into the pcap file with a small state machine.
All the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pcap_typedef.h"
#define RTN_SUCCESS 0
#define RTN_FILE_ERROR 1
#define RTN_BAD_VALUE 2
#define LINE_TYPE_UNKNOWN 0 /* unknown */
#define LINE_TYPE_DESC 1 /* description */
#define LINE_TYPE_DATA 2 /* data */
#define LINE_BUFFER_MAX 512
T_pcap_file_header pcapHeader = {
.magic = 0xa1b2c3d4,
.version_major = 0x02,
.version_minor = 0x04,
.thiszone = 0,
.sigfigs = 0,
.snaplen = 65535,
.linktype = 1/* Ethernet */
};
typedef struct desc_parse {
struct tim ts;
char macSrc[20];
char macDst[20];
unsigned int pro;
} T_desc_parse;
typedef struct pcap_data
{
T_pcap_pkthdr header;
BYTE dataBuff[DATA_BUFFER_MAX];
DWORD dataIndex;/* start from 0 */
} T_pcap_data;
T_pcap_data dataBuff; /* The buffer to file out */
T_desc_parse currDecParse; /* the buff for parsing description */
void setMac(BYTE *mac, const char *macSrc)
{
unsigned int macs[6]={0};
if(6==sscanf(macSrc, "%x:%x:%x:%x:%x:%x", &macs[0],&macs[1],&macs[2],&macs[3],&macs[4], &macs[5]))
{
mac[0]=macs[0]&0xFF;
mac[1]=macs[1]&0xFF;
mac[2]=macs[2]&0xFF;
mac[3]=macs[3]&0xFF;
mac[4]=macs[4]&0xFF;
mac[5]=macs[5]&0xFF;
}
}
int initPcapFileHeader(FILE *out)
{
if(1 == fwrite(&pcapHeader, sizeof(T_pcap_file_header), 1, out))
{
return RTN_SUCCESS;
}
else
{
return RTN_FILE_ERROR;
}
}
int setFileLen(FILE *out, DWORD len)
{
pcapHeader.snaplen = len;
if(0!=fseek(out, 0, SEEK_SET))
{
return RTN_FILE_ERROR;
}
if(1 == fwrite(&pcapHeader, sizeof(T_pcap_file_header), 1, out))
{
return RTN_SUCCESS;
}
else
{
return RTN_FILE_ERROR;
}
}
int parseData(const char *input, T_pcap_data *pDataBuff)
{
int lineIndex = 0;
int count = 0;
unsigned short value;
char tmpBuff[100] = {0};
char *pEnd;
char *p;
int status = 0;/* 0--ready to calculate values, 1--values there*/
if(0 != strncmp(input, "0x", 2))
{
//printf("not data\n");
return RTN_BAD_VALUE;
}
int n = sscanf(input,"%x: %[^\r\n]", &lineIndex, tmpBuff);
if(2 == n)
{
pEnd = tmpBuff + strlen(tmpBuff) - 1;
while((*pEnd != ' ') && (pEnd>tmpBuff))
{
pEnd--;
}/* from the end, skip the last string */
pEnd++;
/* special, add the Ethernet frame header */
if(pDataBuff->dataIndex==0)
{
pDataBuff->dataIndex=(6*2+2);/* frame MAC+MAC+Protocol*/
}
p = tmpBuff;
while(p<pEnd && count<8)
{
/* value*/
if(*p == ' ')
{
if(status == 1)
{
pDataBuff->dataBuff[pDataBuff->dataIndex] = ((value>>8)&0xFF);
pDataBuff->dataIndex++;
pDataBuff->dataBuff[pDataBuff->dataIndex] = (value&0xFF);
pDataBuff->dataIndex++;
count++;
}
value = 0;
status = 0;
}
else if(*p>='0' && *p<='9')
{
value <<= 4;
value += (*p-'0');
status = 1;
}
else if(*p>='a' && *p<='f')
{
value <<= 4;
value += (*p-'a'+10);
status = 1;
}
else if(*p>='A' || *p<='F')
{
value <<= 4;
value += (*p-'A'+10);
status = 1;
}
else
{
value = 0;
status = 0;
}
p++;
}
}
else
{
printf("len is %d\n",n);
return RTN_BAD_VALUE;
}
return RTN_SUCCESS;
}
int parseDesc(const char *input, T_desc_parse *pDescParse)
{
int hour,minute,sec,msec;
char macSrc[18] = {0};
char macDst[18] = {0};
unsigned int pro = 0;
if(NULL == pDescParse)
{
return RTN_BAD_VALUE;
}
int n = sscanf(input, "%d:%d:%d.%d %[^( ] %*[^>] > %s %*[^)]), %*[^(] (%x) %*[^\r\n]",&hour,&minute,&sec,&msec, macSrc, macDst, &pro);
if(7 == n)
{
memset(pDescParse, 0, sizeof(T_pcap_pkthdr));
pDescParse->ts.GMTtime = sec+minute*60+hour*3600;
pDescParse->ts.microTime = msec;
strcpy(pDescParse->macDst,macDst);
strcpy(pDescParse->macSrc,macSrc);
pDescParse->pro = pro;
//printf("[%s]>[%s]\n", macSrc, macDst);
}
else
{
return RTN_BAD_VALUE;
}
return RTN_SUCCESS;
}
int parseLine(char *pLine, int prevStatus)
{
char *p = pLine;
char *pStr;
while((*p==' ') && (p<(pLine+LINE_BUFFER_MAX)))
{
p++;
} /* skip space */
if(p>=(pLine+LINE_BUFFER_MAX))
{
return LINE_TYPE_UNKNOWN;
}
pStr = p;
if(RTN_SUCCESS == parseData(pStr, &dataBuff))
{/* data*/
return LINE_TYPE_DATA;
}
pStr = p;
if(RTN_SUCCESS == parseDesc(pStr, &currDecParse))
{
//printf("parseDesc finished \n");
return LINE_TYPE_DESC;
}
return LINE_TYPE_UNKNOWN;
}
int parseString2Pcap(FILE *fpIn, FILE *fpOut, DWORD *pLen)
{
char line[LINE_BUFFER_MAX];
int status = LINE_TYPE_UNKNOWN;
int preStatus = LINE_TYPE_UNKNOWN;
DWORD len = 0;
int count = 0;
memset(&dataBuff, 0, sizeof(dataBuff));
memset(&currDecParse, 0, sizeof(currDecParse));
while (fgets(line, LINE_BUFFER_MAX, fpIn) > 0)
{/* read files */
status = parseLine(line, preStatus);
switch(status)
{
case LINE_TYPE_DATA:
if(preStatus == LINE_TYPE_DESC)
{
memcpy(&dataBuff.header, &currDecParse, sizeof(struct tim));
setMac(&dataBuff.dataBuff[0],currDecParse.macSrc);
setMac(&dataBuff.dataBuff[6],currDecParse.macDst);
//protocol
dataBuff.dataBuff[12]=((currDecParse.pro>>8)&0xFF);
dataBuff.dataBuff[13]=(currDecParse.pro&0xFF);
memset(&currDecParse, 0, sizeof(currDecParse));
}
else if(preStatus == LINE_TYPE_UNKNOWN)
{
printf("LINE_TYPE_UNKNOWN >> LINE_TYPE_DATA.\n");
return RTN_BAD_VALUE;
}
preStatus = LINE_TYPE_DATA;
break;
case LINE_TYPE_DESC:
/* out put the old one */
if(preStatus == LINE_TYPE_DATA)
{
dataBuff.header.len = dataBuff.dataIndex;
dataBuff.header.caplen = dataBuff.header.len;
len = (sizeof(dataBuff.header)+dataBuff.dataIndex);
*pLen += len;
//printf("write file len %d.\n",len);
if(len != fwrite(&dataBuff, sizeof(BYTE), len, fpOut))
{
printf("write file failed len %d.\n",len);
memset(&dataBuff, 0, sizeof(dataBuff));
return RTN_FILE_ERROR;
}
count++;
memset(&dataBuff,0,sizeof(dataBuff));
}
else if(preStatus == LINE_TYPE_DESC)
{
printf("LINE_TYPE_DESC >> LINE_TYPE_DESC.\n");
return RTN_BAD_VALUE;
}
preStatus = LINE_TYPE_DESC;
break;
default:
break;
}
}
/* The last one. */
dataBuff.header.len = dataBuff.dataIndex;
dataBuff.header.caplen = dataBuff.header.len;
len = (sizeof(dataBuff.header)+dataBuff.dataIndex);
*pLen += len;
//printf("write file len %d.\n",len);
if(len != fwrite(&dataBuff, sizeof(BYTE), len, fpOut))
{
printf("write file failed len %d.\n",len);
memset(&dataBuff, 0, sizeof(dataBuff));
return RTN_FILE_ERROR;
}
count++;
memset(&dataBuff,0,sizeof(dataBuff));
printf("totally parse %d lines.\n", count);
return RTN_SUCCESS;
}
int parse(const char *infile, const char *outfile)
{
DWORD len = 0;
int rtn = RTN_SUCCESS;
FILE *fpIn = NULL;
FILE *fpOut = NULL;
if((fpIn = fopen(infile, "r")) == NULL)
{
printf("error open file %s!\n", infile);
rtn = RTN_FILE_ERROR;
goto exit;
}
if((fpOut = fopen(outfile, "wb")) == NULL)
{
printf("error open file %s!\n", outfile);
rtn = RTN_FILE_ERROR;
goto exit;
}
rtn = initPcapFileHeader(fpOut);
if(RTN_SUCCESS!=rtn)
{
printf("error initPcapFileHeader !\n");
goto exit;
}
rtn = parseString2Pcap(fpIn, fpOut, &len);
if(RTN_SUCCESS!=rtn)
{
printf("error parseString2Pcap !\n");
goto exit;
}
rtn = setFileLen(fpOut, len);
if(RTN_SUCCESS!=rtn)
{
printf("error setFileLen !\n");
goto exit;
}
rtn = RTN_SUCCESS;
exit:
if(fpIn)
{
fclose(fpIn);
}
if(fpOut)
{
fflush(fpOut);
fclose(fpOut);
}
return rtn;
}
It could be used by calling the function
parse("E:\\text2pcap\\testinput.txt", "E:\\text2pcap\\testoutput.pcap");
If the txt format is changed, the parseDesc may also be changed.