erf.cpp revision 8b52a31e
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    int 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)
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        return (g_ntohs(header.wlen));
218    }else{
219        return (-1);
220    }
221}
222
223
224bool CErfFileWriter::Create(char *file_name){
225    m_fd=CAP_FOPEN_64(file_name,"wb");
226    if (m_fd==0) {
227        printf(" ERROR create file \n");
228        return(false);
229    }
230    m_cnt=0;
231    return(true);
232}
233
234void CErfFileWriter::Delete(){
235    if (m_fd) {
236       fclose(m_fd);
237       m_fd=0;
238    }
239}
240
241
242typedef struct erf_dummy_header_ {
243    uint16_t dummy;
244}erf_dummy_header_t ;
245
246static uint32_t frame_check[20];
247
248bool CErfFileWriter::write_packet(CCapPktRaw * lpPacket){
249    erf_header_t header;
250    erf_dummy_header_t dummy;
251
252    dummy.dummy =0;
253    memset(&header,0,sizeof(erf_header_t));
254    double nsec_frac = 4294967295.9 *(lpPacket->time_nsec /1000000000.0);
255    uint64_t ts= (((uint64_t)lpPacket->time_sec) <<32) +((uint32_t)nsec_frac);
256    header.ts =ts;
257
258    uint16_t size=lpPacket->pkt_len;
259
260    uint16_t total_size=(uint16_t)size+sizeof(erf_header_t)+2+4;
261    uint16_t align = (total_size & 0x7);
262    if (align >0 ) {
263        align = 8-align;
264    }
265
266    header.flags =4+lpPacket->getInterface();
267    header.type =TYPE_ETH;
268    header.wlen = g_ntohs((uint16_t)size+4);
269    header.rlen = g_ntohs(total_size+align);
270
271    int n = fwrite(&header,1,sizeof(header),m_fd);
272    n+= fwrite(&dummy,1,sizeof(dummy),m_fd);
273    n+= fwrite(lpPacket->raw,1,size,m_fd);
274    n+= fwrite(frame_check,1,4+align,m_fd);
275
276	if (n < (int)(total_size+align)) {
277		return false;
278	}
279	return true;
280}
281
282
283
284bool CPcapFileWriter::Create(char *file_name){
285    m_fd=CAP_FOPEN_64(file_name,"wb");
286    if (m_fd==0) {
287        printf(" ERROR create file \n");
288        return(false);
289    }
290    m_cnt=0;
291    return(true);
292}
293
294void CPcapFileWriter::Delete(){
295    if (m_fd) {
296       fclose(m_fd);
297       m_fd=0;
298    }
299}
300
301
302
303
304#define	PCAP_MAGIC			0xa1b2c3d4
305#define	PCAP_SWAPPED_MAGIC		0xd4c3b2a1
306#define	PCAP_MODIFIED_MAGIC		0xa1b2cd34
307#define	PCAP_SWAPPED_MODIFIED_MAGIC	0x34cdb2a1
308#define	PCAP_NSEC_MAGIC			0xa1b23c4d
309#define	PCAP_SWAPPED_NSEC_MAGIC		0x4d3cb2a1
310
311/* "libpcap" file header (minus magic number). */
312struct pcap_hdr {
313    guint32 magic_number;
314	guint16	version_major;	/* major version number */
315	guint16	version_minor;	/* minor version number */
316	gint32	thiszone;	/* GMT to local correction */
317	guint32	sigfigs;	/* accuracy of timestamps */
318	guint32	snaplen;	/* max length of captured packets, in octets */
319	guint32	network;	/* data link type */
320};
321
322/* "libpcap" record header. */
323struct pcaprec_hdr {
324	guint32	ts_sec;		/* timestamp seconds */
325	guint32	ts_usec;	/* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
326	guint32	incl_len;	/* number of octets of packet saved in file */
327	guint32	orig_len;	/* actual length of packet */
328};
329
330
331bool CPcapFileWriter::write_packet(CCapPktRaw * lpPacket){
332    if (m_cnt == 0) {
333        pcap_hdr header;
334        header.magic_number   = PCAP_NSEC_MAGIC;
335        header.version_major  = 0x0002;
336        header.version_minor  = 0x0004;
337        header.thiszone       = 0;
338        header.sigfigs        = 0;
339        header.snaplen        = 2000;
340        header.network        = 1;
341        fwrite(&header,1,sizeof(header),m_fd);
342    }
343    pcaprec_hdr pkt_header;
344    pkt_header.ts_sec   = lpPacket->time_sec ;
345    pkt_header.ts_usec  = lpPacket->time_nsec;
346    pkt_header.incl_len = lpPacket->pkt_len;
347    pkt_header.orig_len = lpPacket->pkt_len;
348    fwrite(&pkt_header,1,sizeof(pkt_header),m_fd);
349    fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_fd);
350    m_cnt++;
351	return true;
352}
353
354
355
356#if 0
357 //erf_create(wtap *wth,char *p,uint32_t *sec)
358
359static uint8_t DataPacket0[]={
360
3610x00, 0x50, 0x04, 0xB9 ,0xC8, 0xA0,
3620x00, 0x50, 0x04, 0xB9, 0xC5, 0x83,
3630x08, 0x00,
364
3650x45, 0x10, 0x00, 0x40,
3660x00, 0x00, 0x40, 0x00,
3670x80, 0x06, 0xDD, 0x99,
368
3690x0A, 0x01, 0x04, 0x91,
3700x0A, 0x01, 0x04, 0x90,
371
3720x05, 0x11,
3730x00, 0x50,
374
3750x00, 0x00, 0xF9, 0x00,
3760x00, 0x00, 0x00, 0x00,
377
3780x60, 0x00, 0x20, 0x00,
3790x5C, 0xA2, 0x00, 0x00,
3800x02, 0x04, 0x05, 0xB4,
3810x00, 0x00, 0x76, 0x4A,
382
3830x60, 0x02, 0x20, 0x00,
3840x5C, 0xA2, 0x00, 0x00,
3850x02, 0x04, 0x05, 0xB4,
3860x00, 0x00, 0x76, 0x4A,
3870x60, 0x02, 0x20, 0x00,
3880x5C, 0xA2, 0x00, 0x00,
3890x02, 0x04, 0x05, 0xB4,
3900x00, 0x00, 0x76, 0x4A,
391
392};
393
394
395void test_erf_create(void){
396    CPcapFileWriter erf ;
397    erf.Create("my_test.erf");
398    int i;
399    for (i=0; i<10; i++) {
400        erf.write_packet((char *)&DataPacket0[0],sizeof(DataPacket0));
401    }
402    erf.Delete();
403}
404#endif
405
406
407bool CErfFileReader::Create(char *filename, int loops){
408
409    this->m_loops = loops;
410	m_handle = CAP_FOPEN_64(filename, "rb");
411    if (m_handle == NULL) {
412        fprintf(stderr, "Failed to open file `%s'.\n", filename);
413        return false;
414    }
415
416
417    CAP_FSEEK_64 (m_handle, 0, SEEK_END);
418    m_file_size = CAP_FTELL_64(m_handle);
419    rewind (m_handle);
420
421    wtap wth;
422    memset(&wth,0,sizeof(wtap));
423    int err=0;
424    wth.fh =m_handle;
425    if ( erf_open(&wth, &err)== 1){
426        return (true);
427    }else{
428        return (false);
429    }
430}
431
432void CErfFileReader::Delete(){
433    if (m_handle) {
434        fclose(m_handle);
435        m_handle=0;
436    }
437}
438
439
440bool CErfFileReader::ReadPacket(CCapPktRaw * lpPacket){
441    wtap wth;
442    wth.fh = m_handle;
443    int length;
444    length=erf_read(&wth,lpPacket->raw,&lpPacket->time_sec,
445                    &lpPacket->time_nsec
446                    );
447    if ( length >0   ) {
448        lpPacket->pkt_len =(uint16_t)length;
449		lpPacket->pkt_cnt++;
450        return (true);
451    }
452    return (false);
453}
454
455