pcap.cpp revision 537f5831
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    /* prepare the write counter */
227    m_pkt_count = 0;
228    return init();
229}
230
231void LibPCapWriter::flush_to_disk() {
232    if (m_is_open) {
233        fflush(m_file_handler);
234    }
235}
236
237/**
238 *
239 * Write the libpcap header.
240 *
241 * @return bool - true on success
242 */
243bool LibPCapWriter::init()
244{
245
246	// prepare the file header (one time header for each libpcap file)
247	// and write it.
248	packet_file_header_t header;
249    header.magic   = MAGIC_NUM_DONT_FLIP;
250    header.version_major  = 0x0002;
251    header.version_minor  = 0x0004;
252    header.thiszone       = 0;
253    header.sigfigs        = 0;
254    header.snaplen        = 2000;
255	header.linktype       = 1;
256
257    int n = fwrite(&header,1,sizeof(header),m_file_handler);
258	if ( n == sizeof(packet_file_header_t )) {
259		m_is_open = true;
260		return true;
261	}
262    fclose(m_file_handler);
263	return false;
264}
265
266
267/**
268 * Write packet to file.
269 * Must be called after successfull Create call.
270 * @param p
271 * @param size
272 *
273 * @return bool  - true on success.
274 */
275bool LibPCapWriter::write_packet(CCapPktRaw * lpPacket)
276{
277	if (!m_is_open) {
278		return false;
279	}
280
281	// build the packet libpcap header
282    sf_pkthdr_t pkt_header;
283	pkt_header.caplen = lpPacket->pkt_len;
284	pkt_header.len = lpPacket->pkt_len;
285	pkt_header.ts.msec = (lpPacket->time_nsec/1000);
286	pkt_header.ts.sec  = lpPacket->time_sec;
287
288	m_timestamp++;
289
290	// write header and then the packet.
291	int n = fwrite(&pkt_header,1,sizeof(sf_pkthdr_t),m_file_handler);
292    n+= fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_file_handler);
293
294	if (n< ( (int)sizeof(sf_pkthdr_t) + lpPacket->pkt_len)) {
295		return false;
296	}
297    /* advance the counter on success */
298    m_pkt_count++;
299    return true;
300}
301
302uint32_t LibPCapWriter::get_pkt_count() {
303    return m_pkt_count;
304}
305
306