1/*
2Copyright (c) 2015-2015 Cisco Systems, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#include "pcap.h"
18#include <errno.h>
19#include <string.h>
20#include "pal_utl.h"
21
22
23
24
25static uint32_t MAGIC_NUM_FLIP = 0xd4c3b2a1;
26static uint32_t MAGIC_NUM_DONT_FLIP = 0xa1b2c3d4;
27
28
29LibPCapReader::LibPCapReader()
30{
31	m_is_open = false;
32	m_last_time = 0;
33	m_is_valid = false;
34    m_file_handler = NULL;
35	m_is_flip = false;
36}
37
38LibPCapReader::~LibPCapReader()
39{
40	if (m_is_open && m_file_handler) {
41        fclose(m_file_handler);
42	}
43}
44
45void LibPCapReader::Rewind() {
46   if (m_is_open && m_file_handler) {
47       rewind(m_file_handler);
48       this->init();
49   }
50}
51
52/**
53 * open file for read.
54 * @param name
55 *
56 * @return bool
57 */
58bool LibPCapReader::Create(char * name, int loops)
59{
60    this->m_loops = loops;
61
62    if(name == NULL) {
63	return false;
64    }
65
66    if (m_is_open) {
67        return true;
68    }
69    m_file_handler = CAP_FOPEN_64(name,"rb");
70
71    if (m_file_handler == 0) {
72        printf(" failed to open cap file %s : errno : %d\n",name, errno);
73        return false;
74    }
75
76   CAP_FSEEK_64 (m_file_handler, 0, SEEK_END);
77   m_file_size = CAP_FTELL_64 (m_file_handler);
78   rewind (m_file_handler);
79
80   if (init()) {
81	   m_is_open = true;
82	   return true;
83   }
84
85   fclose(m_file_handler);
86
87   return false;
88}
89
90/**
91 * init the reader.
92 * First read the header of the file make sure it is libpacp.
93 * If so read the flip value. records are senstive to the local
94 * recording machine endianity.
95 *
96 * @return bool
97 */
98bool LibPCapReader::init()
99{
100	packet_file_header_t header;
101	memset(&header,0,sizeof(packet_file_header_t));
102    size_t n = fread(&header,1,sizeof(packet_file_header_t),m_file_handler);
103	if (n < sizeof(packet_file_header_t)) {
104		return false;
105	}
106
107	if (header.magic == MAGIC_NUM_FLIP) {
108		m_is_flip = true;
109	} else if (header.magic == MAGIC_NUM_DONT_FLIP){
110		m_is_flip = false;
111	} else {
112		// capture file in not libpcap format.
113		m_is_valid = false;
114		return false;
115	}
116
117	m_is_valid = true;
118	return true;
119}
120
121/**
122 * flip header values.
123 * @param toflip
124 */
125void LibPCapReader::flip(sf_pkthdr_t * toflip)
126{
127   toflip->ts.sec  = PAL_NTOHL(toflip->ts.sec);
128   toflip->ts.msec = PAL_NTOHL(toflip->ts.msec);
129   toflip->len     = PAL_NTOHL(toflip->len);
130   toflip->caplen  = PAL_NTOHL(toflip->caplen);
131}
132
133bool LibPCapReader::ReadPacket(CCapPktRaw *lpPacket)
134{
135	if(!m_is_valid || !m_is_open)
136		return false;
137
138   sf_pkthdr_t pkt_header;
139   memset(&pkt_header,0,sizeof(sf_pkthdr_t));
140
141   if (CAP_FTELL_64(m_file_handler) == m_file_size) {
142       /* reached end of file - do we loop ?*/
143       if (m_loops > 0) {
144           rewind(m_file_handler);
145           this->init();
146
147       }
148   }
149   int n = fread(&pkt_header,1,sizeof(sf_pkthdr_t),m_file_handler);
150   if (n < sizeof(sf_pkthdr_t)) {
151	   return false;
152   }
153
154   if (m_is_flip) {
155		flip(&pkt_header);
156   }
157   if (pkt_header.caplen > READER_MAX_PACKET_SIZE) {
158       /* cannot read this packet */
159       //printf("ERROR packet is too big, bigger than %d \n",READER_MAX_PACKET_SIZE);
160       return false;
161   }
162
163   lpPacket->pkt_len = fread(lpPacket->raw,1,pkt_header.caplen,m_file_handler);
164
165   lpPacket->time_sec  = pkt_header.ts.sec;
166   lpPacket->time_nsec = pkt_header.ts.msec*1000;
167
168   if ( lpPacket->pkt_len < pkt_header.caplen) {
169       lpPacket->pkt_len = 0;
170	   return false;
171   }
172
173   /* decrease packet limit count */
174   if (m_loops > 0) {
175       m_loops--;
176   }
177   lpPacket->pkt_cnt++;
178   return true;
179}
180
181LibPCapWriter::LibPCapWriter()
182{
183	m_file_handler = NULL;
184	m_timestamp = 0;
185    m_is_open = false;
186}
187
188LibPCapWriter::~LibPCapWriter()
189{
190	Close();
191}
192
193/**
194 * close and release file desc.
195*/
196void LibPCapWriter::Close()
197{
198	if (m_is_open) {
199		fclose(m_file_handler);
200		m_file_handler = NULL;
201		m_is_open = false;
202	}
203}
204
205/**
206 * Try to open file for writing.
207 * @param name - file nae
208 *
209 * @return bool
210 */
211bool LibPCapWriter::Create(char * name)
212{
213	if (name == NULL) {
214		return false;
215	}
216
217	if (m_is_open) {
218		return true;
219	}
220
221	m_file_handler = CAP_FOPEN_64(name,"wb");
222    if (m_file_handler == 0) {
223        printf(" ERROR create file \n");
224        return(false);
225    }
226
227    /* prepare the write counter */
228    m_pkt_count = 0;
229    return init();
230}
231
232void LibPCapWriter::flush_to_disk() {
233    if (m_is_open) {
234        fflush(m_file_handler);
235    }
236}
237
238/**
239 *
240 * Write the libpcap header.
241 *
242 * @return bool - true on success
243 */
244bool LibPCapWriter::init()
245{
246
247	// prepare the file header (one time header for each libpcap file)
248	// and write it.
249	packet_file_header_t header;
250    header.magic   = MAGIC_NUM_DONT_FLIP;
251    header.version_major  = 0x0002;
252    header.version_minor  = 0x0004;
253    header.thiszone       = 0;
254    header.sigfigs        = 0;
255    header.snaplen        = 2000;
256	header.linktype       = 1;
257
258    int n = fwrite(&header,1,sizeof(header),m_file_handler);
259	if ( n == sizeof(packet_file_header_t )) {
260		m_is_open = true;
261		return true;
262	}
263    fclose(m_file_handler);
264	return false;
265}
266
267
268/**
269 * Write packet to file.
270 * Must be called after successfull Create call.
271 * @param p
272 * @param size
273 *
274 * @return bool  - true on success.
275 */
276bool LibPCapWriter::write_packet(CCapPktRaw * lpPacket)
277{
278	if (!m_is_open) {
279		return false;
280	}
281
282	// build the packet libpcap header
283    sf_pkthdr_t pkt_header;
284	pkt_header.caplen = lpPacket->pkt_len;
285	pkt_header.len = lpPacket->pkt_len;
286	pkt_header.ts.msec = (lpPacket->time_nsec/1000);
287	pkt_header.ts.sec  = lpPacket->time_sec;
288
289	m_timestamp++;
290
291	// write header and then the packet.
292	int n = fwrite(&pkt_header,1,sizeof(sf_pkthdr_t),m_file_handler);
293    n+= fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_file_handler);
294
295	if (n< ( (int)sizeof(sf_pkthdr_t) + lpPacket->pkt_len)) {
296		return false;
297	}
298    /* advance the counter on success */
299    m_pkt_count++;
300    return true;
301}
302
303uint32_t LibPCapWriter::get_pkt_count() {
304    return m_pkt_count;
305}
306
307