erf.cpp revision 0d4c9932
1/*
2*
3* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand.
4* All rights reserved.
5*
6* This software and documentation has been developed by Endace Technology Ltd.
7* along with the DAG PCI network capture cards. For further information please
8* visit http://www.endace.com/.
9*
10* Redistribution and use in source and binary forms, with or without
11* modification, are permitted provided that the following conditions are met:
12*
13*  1. Redistributions of source code must retain the above copyright notice,
14*  this list of conditions and the following disclaimer.
15*
16*  2. Redistributions in binary form must reproduce the above copyright
17*  notice, this list of conditions and the following disclaimer in the
18*  documentation and/or other materials provided with the distribution.
19*
20*  3. The name of Endace Technology Ltd may not be used to endorse or promote
21*  products derived from this software without specific prior written
22*  permission.
23*
24* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS
25* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
27* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33* POSSIBILITY OF SUCH DAMAGE.
34*
35* $Id: erf.c 15544 2005-08-26 19:40:46Z guy $
36*/
37
38/*****
39 * NAME
40 *
41 *
42 * AUTHOR
43 *   taken from SCE
44 *
45 * COPYRIGHT
46 *   Copyright (c) 2004-2011 by cisco Systems, Inc.
47 *   All rights reserved.
48 *
49 * DESCRIPTION
50 *
51 ****/
52
53/*
54 * erf - Endace ERF (Extensible Record Format)
55 *
56 * See
57 *
58 *	http://www.endace.com/support/EndaceRecordFormat.pdf
59 */
60
61
62
63#include <stdlib.h>
64#include <string.h>
65#include "erf.h"
66#include "basic_utils.h"
67#include "pal_utl.h"
68
69
70#define MAX_ERF_PACKET   READER_MAX_PACKET_SIZE
71
72
73extern long file_seek(void *stream, long offset, int whence, int *err);
74#define file_read fread
75#define file_write fwrite
76#define file_close fclose
77extern int file_error(FILE *fh);
78#define file_getc fgetc
79#define file_gets fgets
80#define file_eof feof
81
82
83long file_seek(FILE *stream, long offset, int whence, int *err)
84{
85	long ret;
86
87	ret = CAP_FSEEK_64(stream, offset, whence);
88	if (ret == -1)
89		*err = file_error(stream);
90	return ret;
91}
92
93
94int file_error(FILE *fh)
95{
96	if (ferror(fh))
97		return -1;
98	else
99		return 0;
100}
101
102
103int erf_open(wtap *wth, int *err)
104{
105	guint32 i;
106	int common_type = 0;
107	erf_timestamp_t prevts;
108
109	memset(&prevts, 0, sizeof(prevts));
110
111    long records_for_erf_check = 10;
112
113	/* ERF is a little hard because there's no magic number */
114
115	for (i = 0; i < (guint32)records_for_erf_check; i++) {
116
117		erf_header_t header;
118		guint32 packet_size;
119		erf_timestamp_t ts;
120
121		if (file_read(&header,1,sizeof(header),wth->fh) != sizeof(header)) {
122			if ((*err = file_error(wth->fh)) != 0)
123				return -1;
124			else
125				break; /* eof */
126		}
127
128		packet_size = g_ntohs(header.rlen) - sizeof(header);
129
130		/* fail on invalid record type, decreasing timestamps or non-zero pad-bits */
131		if (header.type == 0 || header.type != TYPE_ETH ||
132		    (header.flags & 0xc0) != 0) {
133			return 0;
134		}
135
136		if ((ts = pletohll(&header.ts)) < prevts) {
137			/* reassembled AAL5 records may not be in time order, so allow 1 sec fudge */
138			if (header.type != TYPE_AAL5 || ((prevts-ts)>>32) > 1) {
139				return 0;
140			}
141		}
142		memcpy(&prevts, &ts, sizeof(prevts));
143
144		if (common_type == 0) {
145			common_type = header.type;
146		} else
147		if (common_type > 0 && common_type != header.type) {
148			common_type = -1;
149		}
150
151		if (header.type == TYPE_HDLC_POS ) {
152            // do not support HDLS
153            return (-1);
154		}
155        if (file_seek(wth->fh, packet_size, SEEK_CUR, err) == -1) {
156            return -1;
157        }
158	}
159
160	if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) {	/* rewind */
161		return -1;
162	}
163	wth->data_offset = 0;
164    // VALID ERF file
165	return 1;
166}
167
168
169int erf_read(wtap *wth,char *p,uint32_t *sec,uint32_t *nsec, uint8_t *interface)
170{
171    erf_header_t header;
172    int common_type = 0;
173    if (file_read(&header,1,sizeof(header),wth->fh) != sizeof(header)) {
174        if (( file_error(wth->fh)) != 0)
175            return -1;
176        else
177            return (0); // end
178    }
179
180    guint32 packet_size = g_ntohs(header.rlen) - sizeof(header);
181
182    /* fail on invalid record type, decreasing timestamps or non-zero pad-bits */
183    if ( header.type != TYPE_ETH ||
184        (header.flags & 0xc0) != 0) {
185        //printf(" ERF header not supported \n");
186        // no valid
187        return -1;
188    }
189
190    if (common_type == 0) {
191        common_type = header.type;
192    } else
193    if (common_type > 0 && common_type != header.type) {
194        common_type = -1;
195    }
196
197
198    if ( (  packet_size >= MAX_ERF_PACKET ) ||
199        (g_ntohs(header.wlen)>MAX_ERF_PACKET) ) {
200        printf(" ERF packet size too big  \n");
201		assert(0);
202        return (-1);
203    }
204
205    int err;
206    if (file_seek(wth->fh, 2, SEEK_CUR, &err) == -1) {
207        return -1;
208    }
209    int realpkt_size = packet_size-2;
210
211    if (file_read(p,1,realpkt_size ,wth->fh) == realpkt_size) {
212        guint64 ts = pletohll(&header.ts);
213        *sec = (uint32_t) (ts >> 32);
214        uint32_t frac =(ts &0xffffffff);
215        double usec_frac =(double)frac*(1000000000.0/(4294967296.0));
216        *nsec = (uint32_t) (usec_frac);
217        *interface = header.flags & 0x3;
218        return (g_ntohs(header.wlen));
219    }else{
220        return (-1);
221    }
222}
223
224
225bool CErfFileWriter::Create(char *file_name){
226    m_fd=CAP_FOPEN_64(file_name,"wb");
227    if (m_fd==0) {
228        printf(" ERROR create file \n");
229        return(false);
230    }
231    m_cnt=0;
232    return(true);
233}
234
235void CErfFileWriter::Delete(){
236    if (m_fd) {
237       fclose(m_fd);
238       m_fd=0;
239    }
240}
241
242
243typedef struct erf_dummy_header_ {
244    uint16_t dummy;
245}erf_dummy_header_t ;
246
247static uint32_t frame_check[20];
248
249bool CErfFileWriter::write_packet(CCapPktRaw * lpPacket){
250    erf_header_t header;
251    erf_dummy_header_t dummy;
252
253    dummy.dummy =0;
254    memset(&header,0,sizeof(erf_header_t));
255    double nsec_frac = 4294967295.9 *(lpPacket->time_nsec /1000000000.0);
256    uint64_t ts= (((uint64_t)lpPacket->time_sec) <<32) +((uint32_t)nsec_frac);
257    header.ts =ts;
258
259    uint16_t size=lpPacket->pkt_len;
260
261    uint16_t total_size=(uint16_t)size+sizeof(erf_header_t)+2+4;
262    uint16_t align = (total_size & 0x7);
263    if (align >0 ) {
264        align = 8-align;
265    }
266
267    header.flags =4+lpPacket->getInterface();
268    header.type =TYPE_ETH;
269    header.wlen = g_ntohs((uint16_t)size+4);
270    header.rlen = g_ntohs(total_size+align);
271
272    int n = fwrite(&header,1,sizeof(header),m_fd);
273    n+= fwrite(&dummy,1,sizeof(dummy),m_fd);
274    n+= fwrite(lpPacket->raw,1,size,m_fd);
275    n+= fwrite(frame_check,1,4+align,m_fd);
276
277	if (n < (int)(total_size+align)) {
278		return false;
279	}
280	return true;
281}
282
283
284
285bool CPcapFileWriter::Create(char *file_name){
286    m_fd=CAP_FOPEN_64(file_name,"wb");
287    if (m_fd==0) {
288        printf(" ERROR create file \n");
289        return(false);
290    }
291    m_cnt=0;
292    return(true);
293}
294
295void CPcapFileWriter::Delete(){
296    if (m_fd) {
297       fclose(m_fd);
298       m_fd=0;
299    }
300}
301
302
303
304
305#define	PCAP_MAGIC			0xa1b2c3d4
306#define	PCAP_SWAPPED_MAGIC		0xd4c3b2a1
307#define	PCAP_MODIFIED_MAGIC		0xa1b2cd34
308#define	PCAP_SWAPPED_MODIFIED_MAGIC	0x34cdb2a1
309#define	PCAP_NSEC_MAGIC			0xa1b23c4d
310#define	PCAP_SWAPPED_NSEC_MAGIC		0x4d3cb2a1
311
312/* "libpcap" file header (minus magic number). */
313struct pcap_hdr {
314    guint32 magic_number;
315	guint16	version_major;	/* major version number */
316	guint16	version_minor;	/* minor version number */
317	gint32	thiszone;	/* GMT to local correction */
318	guint32	sigfigs;	/* accuracy of timestamps */
319	guint32	snaplen;	/* max length of captured packets, in octets */
320	guint32	network;	/* data link type */
321};
322
323/* "libpcap" record header. */
324struct pcaprec_hdr {
325	guint32	ts_sec;		/* timestamp seconds */
326	guint32	ts_usec;	/* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
327	guint32	incl_len;	/* number of octets of packet saved in file */
328	guint32	orig_len;	/* actual length of packet */
329};
330
331
332bool CPcapFileWriter::write_packet(CCapPktRaw * lpPacket){
333    if (m_cnt == 0) {
334        pcap_hdr header;
335        header.magic_number   = PCAP_NSEC_MAGIC;
336        header.version_major  = 0x0002;
337        header.version_minor  = 0x0004;
338        header.thiszone       = 0;
339        header.sigfigs        = 0;
340        header.snaplen        = 2000;
341        header.network        = 1;
342        fwrite(&header,1,sizeof(header),m_fd);
343    }
344    pcaprec_hdr pkt_header;
345    pkt_header.ts_sec   = lpPacket->time_sec ;
346    pkt_header.ts_usec  = lpPacket->time_nsec;
347    pkt_header.incl_len = lpPacket->pkt_len;
348    pkt_header.orig_len = lpPacket->pkt_len;
349    fwrite(&pkt_header,1,sizeof(pkt_header),m_fd);
350    fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_fd);
351    m_cnt++;
352	return true;
353}
354
355
356
357#if 0
358 //erf_create(wtap *wth,char *p,uint32_t *sec)
359
360static uint8_t DataPacket0[]={
361
3620x00, 0x50, 0x04, 0xB9 ,0xC8, 0xA0,
3630x00, 0x50, 0x04, 0xB9, 0xC5, 0x83,
3640x08, 0x00,
365
3660x45, 0x10, 0x00, 0x40,
3670x00, 0x00, 0x40, 0x00,
3680x80, 0x06, 0xDD, 0x99,
369
3700x0A, 0x01, 0x04, 0x91,
3710x0A, 0x01, 0x04, 0x90,
372
3730x05, 0x11,
3740x00, 0x50,
375
3760x00, 0x00, 0xF9, 0x00,
3770x00, 0x00, 0x00, 0x00,
378
3790x60, 0x00, 0x20, 0x00,
3800x5C, 0xA2, 0x00, 0x00,
3810x02, 0x04, 0x05, 0xB4,
3820x00, 0x00, 0x76, 0x4A,
383
3840x60, 0x02, 0x20, 0x00,
3850x5C, 0xA2, 0x00, 0x00,
3860x02, 0x04, 0x05, 0xB4,
3870x00, 0x00, 0x76, 0x4A,
3880x60, 0x02, 0x20, 0x00,
3890x5C, 0xA2, 0x00, 0x00,
3900x02, 0x04, 0x05, 0xB4,
3910x00, 0x00, 0x76, 0x4A,
392
393};
394
395
396void test_erf_create(void){
397    CPcapFileWriter erf ;
398    erf.Create("my_test.erf");
399    int i;
400    for (i=0; i<10; i++) {
401        erf.write_packet((char *)&DataPacket0[0],sizeof(DataPacket0));
402    }
403    erf.Delete();
404}
405#endif
406
407
408bool CErfFileReader::Create(char *filename, int loops){
409
410    this->m_loops = loops;
411	m_handle = CAP_FOPEN_64(filename, "rb");
412    if (m_handle == NULL) {
413        fprintf(stderr, "Failed to open file `%s'.\n", filename);
414        return false;
415    }
416
417
418    CAP_FSEEK_64 (m_handle, 0, SEEK_END);
419    m_file_size = CAP_FTELL_64(m_handle);
420    rewind (m_handle);
421
422    wtap wth;
423    memset(&wth,0,sizeof(wtap));
424    int err=0;
425    wth.fh =m_handle;
426    if ( erf_open(&wth, &err)== 1){
427        return (true);
428    }else{
429        return (false);
430    }
431}
432
433void CErfFileReader::Delete(){
434    if (m_handle) {
435        fclose(m_handle);
436        m_handle=0;
437    }
438}
439
440
441bool CErfFileReader::ReadPacket(CCapPktRaw * lpPacket){
442    uint8_t interface;
443    wtap wth;
444
445    wth.fh = m_handle;
446    int length = erf_read(&wth,
447                          lpPacket->raw,
448                          &lpPacket->time_sec,
449                          &lpPacket->time_nsec,
450                          &interface);
451    if ( length >0   ) {
452        lpPacket->pkt_len =(uint16_t)length;
453        lpPacket->pkt_cnt++;
454        lpPacket->setInterface(interface);
455        return (true);
456    }
457    return (false);
458}
459
460