erf.cpp revision 537f5831
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
283void CErfFileWriter::flush_to_disk() {
284    if (m_fd) {
285        fflush(m_fd);
286    }
287}
288
289bool CPcapFileWriter::Create(char *file_name){
290    m_fd=CAP_FOPEN_64(file_name,"wb");
291    if (m_fd==0) {
292        printf(" ERROR create file \n");
293        return(false);
294    }
295    m_cnt=0;
296    return(true);
297}
298
299void CPcapFileWriter::Delete(){
300    if (m_fd) {
301       fclose(m_fd);
302       m_fd=0;
303    }
304}
305
306
307
308
309#define	PCAP_MAGIC			0xa1b2c3d4
310#define	PCAP_SWAPPED_MAGIC		0xd4c3b2a1
311#define	PCAP_MODIFIED_MAGIC		0xa1b2cd34
312#define	PCAP_SWAPPED_MODIFIED_MAGIC	0x34cdb2a1
313#define	PCAP_NSEC_MAGIC			0xa1b23c4d
314#define	PCAP_SWAPPED_NSEC_MAGIC		0x4d3cb2a1
315
316/* "libpcap" file header (minus magic number). */
317struct pcap_hdr {
318    guint32 magic_number;
319	guint16	version_major;	/* major version number */
320	guint16	version_minor;	/* minor version number */
321	gint32	thiszone;	/* GMT to local correction */
322	guint32	sigfigs;	/* accuracy of timestamps */
323	guint32	snaplen;	/* max length of captured packets, in octets */
324	guint32	network;	/* data link type */
325};
326
327/* "libpcap" record header. */
328struct pcaprec_hdr {
329	guint32	ts_sec;		/* timestamp seconds */
330	guint32	ts_usec;	/* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
331	guint32	incl_len;	/* number of octets of packet saved in file */
332	guint32	orig_len;	/* actual length of packet */
333};
334
335
336bool CPcapFileWriter::write_packet(CCapPktRaw * lpPacket){
337    if (m_cnt == 0) {
338        pcap_hdr header;
339        header.magic_number   = PCAP_NSEC_MAGIC;
340        header.version_major  = 0x0002;
341        header.version_minor  = 0x0004;
342        header.thiszone       = 0;
343        header.sigfigs        = 0;
344        header.snaplen        = 2000;
345        header.network        = 1;
346        fwrite(&header,1,sizeof(header),m_fd);
347    }
348    pcaprec_hdr pkt_header;
349    pkt_header.ts_sec   = lpPacket->time_sec ;
350    pkt_header.ts_usec  = lpPacket->time_nsec;
351    pkt_header.incl_len = lpPacket->pkt_len;
352    pkt_header.orig_len = lpPacket->pkt_len;
353    fwrite(&pkt_header,1,sizeof(pkt_header),m_fd);
354    fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_fd);
355    m_cnt++;
356	return true;
357}
358
359
360
361#if 0
362 //erf_create(wtap *wth,char *p,uint32_t *sec)
363
364static uint8_t DataPacket0[]={
365
3660x00, 0x50, 0x04, 0xB9 ,0xC8, 0xA0,
3670x00, 0x50, 0x04, 0xB9, 0xC5, 0x83,
3680x08, 0x00,
369
3700x45, 0x10, 0x00, 0x40,
3710x00, 0x00, 0x40, 0x00,
3720x80, 0x06, 0xDD, 0x99,
373
3740x0A, 0x01, 0x04, 0x91,
3750x0A, 0x01, 0x04, 0x90,
376
3770x05, 0x11,
3780x00, 0x50,
379
3800x00, 0x00, 0xF9, 0x00,
3810x00, 0x00, 0x00, 0x00,
382
3830x60, 0x00, 0x20, 0x00,
3840x5C, 0xA2, 0x00, 0x00,
3850x02, 0x04, 0x05, 0xB4,
3860x00, 0x00, 0x76, 0x4A,
387
3880x60, 0x02, 0x20, 0x00,
3890x5C, 0xA2, 0x00, 0x00,
3900x02, 0x04, 0x05, 0xB4,
3910x00, 0x00, 0x76, 0x4A,
3920x60, 0x02, 0x20, 0x00,
3930x5C, 0xA2, 0x00, 0x00,
3940x02, 0x04, 0x05, 0xB4,
3950x00, 0x00, 0x76, 0x4A,
396
397};
398
399
400void test_erf_create(void){
401    CPcapFileWriter erf ;
402    erf.Create("my_test.erf");
403    int i;
404    for (i=0; i<10; i++) {
405        erf.write_packet((char *)&DataPacket0[0],sizeof(DataPacket0));
406    }
407    erf.Delete();
408}
409#endif
410
411
412bool CErfFileReader::Create(char *filename, int loops){
413
414    this->m_loops = loops;
415	m_handle = CAP_FOPEN_64(filename, "rb");
416    if (m_handle == NULL) {
417        fprintf(stderr, "Failed to open file `%s'.\n", filename);
418        return false;
419    }
420
421
422    CAP_FSEEK_64 (m_handle, 0, SEEK_END);
423    m_file_size = CAP_FTELL_64(m_handle);
424    rewind (m_handle);
425
426    wtap wth;
427    memset(&wth,0,sizeof(wtap));
428    int err=0;
429    wth.fh =m_handle;
430    if ( erf_open(&wth, &err)== 1){
431        return (true);
432    }else{
433        return (false);
434    }
435}
436
437void CErfFileReader::Delete(){
438    if (m_handle) {
439        fclose(m_handle);
440        m_handle=0;
441    }
442}
443
444void CErfFileReader::Rewind() {
445   if (m_handle) {
446       rewind(m_handle);
447   }
448}
449
450
451bool CErfFileReader::ReadPacket(CCapPktRaw * lpPacket){
452    uint8_t interface;
453    wtap wth;
454
455    wth.fh = m_handle;
456    int length = erf_read(&wth,
457                          lpPacket->raw,
458                          &lpPacket->time_sec,
459                          &lpPacket->time_nsec,
460                          &interface);
461    if ( length >0   ) {
462        lpPacket->pkt_len =(uint16_t)length;
463        lpPacket->pkt_cnt++;
464        lpPacket->setInterface(interface);
465        return (true);
466    }
467    return (false);
468}
469
470