18b52a31eSHanoh Haim/*
28b52a31eSHanoh HaimCopyright (c) 2015-2015 Cisco Systems, Inc.
38b52a31eSHanoh Haim
48b52a31eSHanoh HaimLicensed under the Apache License, Version 2.0 (the "License");
58b52a31eSHanoh Haimyou may not use this file except in compliance with the License.
68b52a31eSHanoh HaimYou may obtain a copy of the License at
78b52a31eSHanoh Haim
88b52a31eSHanoh Haim    http://www.apache.org/licenses/LICENSE-2.0
98b52a31eSHanoh Haim
108b52a31eSHanoh HaimUnless required by applicable law or agreed to in writing, software
118b52a31eSHanoh Haimdistributed under the License is distributed on an "AS IS" BASIS,
128b52a31eSHanoh HaimWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138b52a31eSHanoh HaimSee the License for the specific language governing permissions and
148b52a31eSHanoh Haimlimitations under the License.
158b52a31eSHanoh Haim*/
168b52a31eSHanoh Haim
178b52a31eSHanoh Haim#include "pcap.h"
188b52a31eSHanoh Haim#include <errno.h>
198b52a31eSHanoh Haim#include <string.h>
208b52a31eSHanoh Haim#include "pal_utl.h"
218b52a31eSHanoh Haim
228b52a31eSHanoh Haim
238b52a31eSHanoh Haim
248b52a31eSHanoh Haim
258b52a31eSHanoh Haimstatic uint32_t MAGIC_NUM_FLIP = 0xd4c3b2a1;
268b52a31eSHanoh Haimstatic uint32_t MAGIC_NUM_DONT_FLIP = 0xa1b2c3d4;
278b52a31eSHanoh Haim
288b52a31eSHanoh Haim
298b52a31eSHanoh HaimLibPCapReader::LibPCapReader()
308b52a31eSHanoh Haim{
318b52a31eSHanoh Haim	m_is_open = false;
328b52a31eSHanoh Haim	m_last_time = 0;
338b52a31eSHanoh Haim	m_is_valid = false;
348b52a31eSHanoh Haim    m_file_handler = NULL;
358b52a31eSHanoh Haim	m_is_flip = false;
368b52a31eSHanoh Haim}
378b52a31eSHanoh Haim
388b52a31eSHanoh HaimLibPCapReader::~LibPCapReader()
398b52a31eSHanoh Haim{
408b52a31eSHanoh Haim	if (m_is_open && m_file_handler) {
418b52a31eSHanoh Haim        fclose(m_file_handler);
428b52a31eSHanoh Haim	}
438b52a31eSHanoh Haim}
448b52a31eSHanoh Haim
458b52a31eSHanoh Haimvoid LibPCapReader::Rewind() {
468b52a31eSHanoh Haim   if (m_is_open && m_file_handler) {
478b52a31eSHanoh Haim       rewind(m_file_handler);
488b52a31eSHanoh Haim       this->init();
498b52a31eSHanoh Haim   }
508b52a31eSHanoh Haim}
518b52a31eSHanoh Haim
528b52a31eSHanoh Haim/**
538b52a31eSHanoh Haim * open file for read.
548b52a31eSHanoh Haim * @param name
558b52a31eSHanoh Haim *
568b52a31eSHanoh Haim * @return bool
578b52a31eSHanoh Haim */
588b52a31eSHanoh Haimbool LibPCapReader::Create(char * name, int loops)
598b52a31eSHanoh Haim{
608b52a31eSHanoh Haim    this->m_loops = loops;
618b52a31eSHanoh Haim
628b52a31eSHanoh Haim    if(name == NULL) {
638b52a31eSHanoh Haim	return false;
648b52a31eSHanoh Haim    }
658b52a31eSHanoh Haim
668b52a31eSHanoh Haim    if (m_is_open) {
678b52a31eSHanoh Haim        return true;
688b52a31eSHanoh Haim    }
698b52a31eSHanoh Haim    m_file_handler = CAP_FOPEN_64(name,"rb");
708b52a31eSHanoh Haim
718b52a31eSHanoh Haim    if (m_file_handler == 0) {
728b52a31eSHanoh Haim        printf(" failed to open cap file %s : errno : %d\n",name, errno);
738b52a31eSHanoh Haim        return false;
748b52a31eSHanoh Haim    }
758b52a31eSHanoh Haim
768b52a31eSHanoh Haim   CAP_FSEEK_64 (m_file_handler, 0, SEEK_END);
778b52a31eSHanoh Haim   m_file_size = CAP_FTELL_64 (m_file_handler);
788b52a31eSHanoh Haim   rewind (m_file_handler);
798b52a31eSHanoh Haim
808b52a31eSHanoh Haim   if (init()) {
818b52a31eSHanoh Haim	   m_is_open = true;
828b52a31eSHanoh Haim	   return true;
838b52a31eSHanoh Haim   }
848b52a31eSHanoh Haim
858b52a31eSHanoh Haim   fclose(m_file_handler);
868b52a31eSHanoh Haim
878b52a31eSHanoh Haim   return false;
888b52a31eSHanoh Haim}
898b52a31eSHanoh Haim
908b52a31eSHanoh Haim/**
918b52a31eSHanoh Haim * init the reader.
928b52a31eSHanoh Haim * First read the header of the file make sure it is libpacp.
938b52a31eSHanoh Haim * If so read the flip value. records are senstive to the local
948b52a31eSHanoh Haim * recording machine endianity.
958b52a31eSHanoh Haim *
968b52a31eSHanoh Haim * @return bool
978b52a31eSHanoh Haim */
988b52a31eSHanoh Haimbool LibPCapReader::init()
998b52a31eSHanoh Haim{
1008b52a31eSHanoh Haim	packet_file_header_t header;
1018b52a31eSHanoh Haim	memset(&header,0,sizeof(packet_file_header_t));
1028b52a31eSHanoh Haim    size_t n = fread(&header,1,sizeof(packet_file_header_t),m_file_handler);
1038b52a31eSHanoh Haim	if (n < sizeof(packet_file_header_t)) {
1048b52a31eSHanoh Haim		return false;
1058b52a31eSHanoh Haim	}
1068b52a31eSHanoh Haim
1078b52a31eSHanoh Haim	if (header.magic == MAGIC_NUM_FLIP) {
1088b52a31eSHanoh Haim		m_is_flip = true;
1098b52a31eSHanoh Haim	} else if (header.magic == MAGIC_NUM_DONT_FLIP){
1108b52a31eSHanoh Haim		m_is_flip = false;
1118b52a31eSHanoh Haim	} else {
1128b52a31eSHanoh Haim		// capture file in not libpcap format.
1138b52a31eSHanoh Haim		m_is_valid = false;
1148b52a31eSHanoh Haim		return false;
1158b52a31eSHanoh Haim	}
1168b52a31eSHanoh Haim
1178b52a31eSHanoh Haim	m_is_valid = true;
1188b52a31eSHanoh Haim	return true;
1198b52a31eSHanoh Haim}
1208b52a31eSHanoh Haim
1218b52a31eSHanoh Haim/**
1228b52a31eSHanoh Haim * flip header values.
1238b52a31eSHanoh Haim * @param toflip
1248b52a31eSHanoh Haim */
1258b52a31eSHanoh Haimvoid LibPCapReader::flip(sf_pkthdr_t * toflip)
1268b52a31eSHanoh Haim{
1278b52a31eSHanoh Haim   toflip->ts.sec  = PAL_NTOHL(toflip->ts.sec);
1288b52a31eSHanoh Haim   toflip->ts.msec = PAL_NTOHL(toflip->ts.msec);
1298b52a31eSHanoh Haim   toflip->len     = PAL_NTOHL(toflip->len);
1308b52a31eSHanoh Haim   toflip->caplen  = PAL_NTOHL(toflip->caplen);
1318b52a31eSHanoh Haim}
1328b52a31eSHanoh Haim
1338b52a31eSHanoh Haimbool LibPCapReader::ReadPacket(CCapPktRaw *lpPacket)
1348b52a31eSHanoh Haim{
1358b52a31eSHanoh Haim	if(!m_is_valid || !m_is_open)
1368b52a31eSHanoh Haim		return false;
1378b52a31eSHanoh Haim
1388b52a31eSHanoh Haim   sf_pkthdr_t pkt_header;
1398b52a31eSHanoh Haim   memset(&pkt_header,0,sizeof(sf_pkthdr_t));
1408b52a31eSHanoh Haim
1418b52a31eSHanoh Haim   if (CAP_FTELL_64(m_file_handler) == m_file_size) {
1428b52a31eSHanoh Haim       /* reached end of file - do we loop ?*/
1438b52a31eSHanoh Haim       if (m_loops > 0) {
1448b52a31eSHanoh Haim           rewind(m_file_handler);
1458b52a31eSHanoh Haim           this->init();
1468b52a31eSHanoh Haim
1478b52a31eSHanoh Haim       }
1488b52a31eSHanoh Haim   }
1498b52a31eSHanoh Haim   int n = fread(&pkt_header,1,sizeof(sf_pkthdr_t),m_file_handler);
1508b52a31eSHanoh Haim   if (n < sizeof(sf_pkthdr_t)) {
1518b52a31eSHanoh Haim	   return false;
1528b52a31eSHanoh Haim   }
1538b52a31eSHanoh Haim
1548b52a31eSHanoh Haim   if (m_is_flip) {
1558b52a31eSHanoh Haim		flip(&pkt_header);
1568b52a31eSHanoh Haim   }
1575bbf8a6dSimarom   if (pkt_header.caplen > READER_MAX_PACKET_SIZE) {
1588b52a31eSHanoh Haim       /* cannot read this packet */
15975ce59e5Simarom       //printf("ERROR packet is too big, bigger than %d \n",READER_MAX_PACKET_SIZE);
1608b52a31eSHanoh Haim       return false;
1618b52a31eSHanoh Haim   }
1628b52a31eSHanoh Haim
1635bbf8a6dSimarom   lpPacket->pkt_len = fread(lpPacket->raw,1,pkt_header.caplen,m_file_handler);
1648b52a31eSHanoh Haim
1658b52a31eSHanoh Haim   lpPacket->time_sec  = pkt_header.ts.sec;
1668b52a31eSHanoh Haim   lpPacket->time_nsec = pkt_header.ts.msec*1000;
1678b52a31eSHanoh Haim
1685bbf8a6dSimarom   if ( lpPacket->pkt_len < pkt_header.caplen) {
1698b52a31eSHanoh Haim       lpPacket->pkt_len = 0;
1708b52a31eSHanoh Haim	   return false;
1718b52a31eSHanoh Haim   }
1728b52a31eSHanoh Haim
1738b52a31eSHanoh Haim   /* decrease packet limit count */
1748b52a31eSHanoh Haim   if (m_loops > 0) {
1758b52a31eSHanoh Haim       m_loops--;
1768b52a31eSHanoh Haim   }
1778b52a31eSHanoh Haim   lpPacket->pkt_cnt++;
1788b52a31eSHanoh Haim   return true;
1798b52a31eSHanoh Haim}
1808b52a31eSHanoh Haim
1818b52a31eSHanoh HaimLibPCapWriter::LibPCapWriter()
1828b52a31eSHanoh Haim{
1838b52a31eSHanoh Haim	m_file_handler = NULL;
1848b52a31eSHanoh Haim	m_timestamp = 0;
1858b52a31eSHanoh Haim    m_is_open = false;
1868b52a31eSHanoh Haim}
1878b52a31eSHanoh Haim
1888b52a31eSHanoh HaimLibPCapWriter::~LibPCapWriter()
1898b52a31eSHanoh Haim{
1908b52a31eSHanoh Haim	Close();
1918b52a31eSHanoh Haim}
1928b52a31eSHanoh Haim
1938b52a31eSHanoh Haim/**
1948b52a31eSHanoh Haim * close and release file desc.
1958b52a31eSHanoh Haim*/
1968b52a31eSHanoh Haimvoid LibPCapWriter::Close()
1978b52a31eSHanoh Haim{
1988b52a31eSHanoh Haim	if (m_is_open) {
1998b52a31eSHanoh Haim		fclose(m_file_handler);
2008b52a31eSHanoh Haim		m_file_handler = NULL;
2018b52a31eSHanoh Haim		m_is_open = false;
2028b52a31eSHanoh Haim	}
2038b52a31eSHanoh Haim}
2048b52a31eSHanoh Haim
2058b52a31eSHanoh Haim/**
2068b52a31eSHanoh Haim * Try to open file for writing.
2078b52a31eSHanoh Haim * @param name - file nae
2088b52a31eSHanoh Haim *
2098b52a31eSHanoh Haim * @return bool
2108b52a31eSHanoh Haim */
2118b52a31eSHanoh Haimbool LibPCapWriter::Create(char * name)
2128b52a31eSHanoh Haim{
2138b52a31eSHanoh Haim	if (name == NULL) {
2148b52a31eSHanoh Haim		return false;
2158b52a31eSHanoh Haim	}
2168b52a31eSHanoh Haim
2178b52a31eSHanoh Haim	if (m_is_open) {
2188b52a31eSHanoh Haim		return true;
2198b52a31eSHanoh Haim	}
2208b52a31eSHanoh Haim
2218b52a31eSHanoh Haim	m_file_handler = CAP_FOPEN_64(name,"wb");
2228b52a31eSHanoh Haim    if (m_file_handler == 0) {
2238b52a31eSHanoh Haim        printf(" ERROR create file \n");
2248b52a31eSHanoh Haim        return(false);
2258b52a31eSHanoh Haim    }
2278b52a31eSHanoh Haim    /* prepare the write counter */
2288b52a31eSHanoh Haim    m_pkt_count = 0;
2298b52a31eSHanoh Haim    return init();
2308b52a31eSHanoh Haim}
2318b52a31eSHanoh Haim
232537f5831Simaromvoid LibPCapWriter::flush_to_disk() {
233537f5831Simarom    if (m_is_open) {
234537f5831Simarom        fflush(m_file_handler);
235537f5831Simarom    }
2388b52a31eSHanoh Haim/**
2398b52a31eSHanoh Haim *
2408b52a31eSHanoh Haim * Write the libpcap header.
2418b52a31eSHanoh Haim *
2428b52a31eSHanoh Haim * @return bool - true on success
2438b52a31eSHanoh Haim */
2448b52a31eSHanoh Haimbool LibPCapWriter::init()
2458b52a31eSHanoh Haim{
2468b52a31eSHanoh Haim
2478b52a31eSHanoh Haim	// prepare the file header (one time header for each libpcap file)
2488b52a31eSHanoh Haim	// and write it.
2498b52a31eSHanoh Haim	packet_file_header_t header;
2508b52a31eSHanoh Haim    header.magic   = MAGIC_NUM_DONT_FLIP;
2518b52a31eSHanoh Haim    header.version_major  = 0x0002;
2528b52a31eSHanoh Haim    header.version_minor  = 0x0004;
2538b52a31eSHanoh Haim    header.thiszone       = 0;
2548b52a31eSHanoh Haim    header.sigfigs        = 0;
2558b52a31eSHanoh Haim    header.snaplen        = 2000;
2568b52a31eSHanoh Haim	header.linktype       = 1;
2578b52a31eSHanoh Haim
2588b52a31eSHanoh Haim    int n = fwrite(&header,1,sizeof(header),m_file_handler);
2598b52a31eSHanoh Haim	if ( n == sizeof(packet_file_header_t )) {
2608b52a31eSHanoh Haim		m_is_open = true;
2618b52a31eSHanoh Haim		return true;
2628b52a31eSHanoh Haim	}
2638b52a31eSHanoh Haim    fclose(m_file_handler);
2648b52a31eSHanoh Haim	return false;
2658b52a31eSHanoh Haim}
2668b52a31eSHanoh Haim
2678b52a31eSHanoh Haim
2688b52a31eSHanoh Haim/**
2698b52a31eSHanoh Haim * Write packet to file.
2708b52a31eSHanoh Haim * Must be called after successfull Create call.
2718b52a31eSHanoh Haim * @param p
2728b52a31eSHanoh Haim * @param size
2738b52a31eSHanoh Haim *
2748b52a31eSHanoh Haim * @return bool  - true on success.
2758b52a31eSHanoh Haim */
2768b52a31eSHanoh Haimbool LibPCapWriter::write_packet(CCapPktRaw * lpPacket)
2778b52a31eSHanoh Haim{
2788b52a31eSHanoh Haim	if (!m_is_open) {
2798b52a31eSHanoh Haim		return false;
2808b52a31eSHanoh Haim	}
2818b52a31eSHanoh Haim
2828b52a31eSHanoh Haim	// build the packet libpcap header
2838b52a31eSHanoh Haim    sf_pkthdr_t pkt_header;
2848b52a31eSHanoh Haim	pkt_header.caplen = lpPacket->pkt_len;
2858b52a31eSHanoh Haim	pkt_header.len = lpPacket->pkt_len;
2868b52a31eSHanoh Haim	pkt_header.ts.msec = (lpPacket->time_nsec/1000);
2878b52a31eSHanoh Haim	pkt_header.ts.sec  = lpPacket->time_sec;
2888b52a31eSHanoh Haim
2898b52a31eSHanoh Haim	m_timestamp++;
2908b52a31eSHanoh Haim
2918b52a31eSHanoh Haim	// write header and then the packet.
2928b52a31eSHanoh Haim	int n = fwrite(&pkt_header,1,sizeof(sf_pkthdr_t),m_file_handler);
2938b52a31eSHanoh Haim    n+= fwrite(lpPacket->raw,1,lpPacket->pkt_len,m_file_handler);
2948b52a31eSHanoh Haim
2958b52a31eSHanoh Haim	if (n< ( (int)sizeof(sf_pkthdr_t) + lpPacket->pkt_len)) {
2968b52a31eSHanoh Haim		return false;
2978b52a31eSHanoh Haim	}
2988b52a31eSHanoh Haim    /* advance the counter on success */
2998b52a31eSHanoh Haim    m_pkt_count++;
3008b52a31eSHanoh Haim    return true;
3018b52a31eSHanoh Haim}
3028b52a31eSHanoh Haim
3038b52a31eSHanoh Haimuint32_t LibPCapWriter::get_pkt_count() {
3048b52a31eSHanoh Haim    return m_pkt_count;
3058b52a31eSHanoh Haim}
3068b52a31eSHanoh Haim