Coverage Report

Created: 2023-01-25 06:41

/src/PcapPlusPlus/Pcap++/src/PcapFileDevice.cpp
Line
Count
Source (jump to first uncovered line)
1
50.6k
#define LOG_MODULE PcapLogModuleFileDevice
2
3
#include <stdio.h>
4
#include <cerrno>
5
#include "PcapFileDevice.h"
6
#include "light_pcapng_ext.h"
7
#include "Logger.h"
8
#include "TimespecTimeval.h"
9
#include "pcap.h"
10
#include <string.h>
11
#include <fstream>
12
#include "EndianPortable.h"
13
14
namespace pcpp
15
{
16
17
template <typename T, size_t N>
18
0
constexpr size_t ARRAY_SIZE(T (&)[N]) { return N; }
19
20
struct pcap_file_header
21
{
22
  uint32_t magic;
23
  uint16_t version_major;
24
  uint16_t version_minor;
25
  int32_t thiszone;
26
  uint32_t sigfigs;
27
  uint32_t snaplen;
28
  uint32_t linktype;
29
};
30
31
struct packet_header
32
{
33
  uint32_t tv_sec;
34
  uint32_t tv_usec;
35
  uint32_t caplen;
36
  uint32_t len;
37
};
38
39
// ~~~~~~~~~~~~~~~~~~~
40
// IFileDevice members
41
// ~~~~~~~~~~~~~~~~~~~
42
43
IFileDevice::IFileDevice(const std::string& fileName) : IPcapDevice()
44
17.8k
{
45
17.8k
  m_FileName = fileName;
46
17.8k
}
47
48
IFileDevice::~IFileDevice()
49
17.8k
{
50
17.8k
  IFileDevice::close();
51
17.8k
}
52
53
std::string IFileDevice::getFileName() const
54
0
{
55
0
  return m_FileName;
56
0
}
57
58
void IFileDevice::close()
59
33.5k
{
60
33.5k
  if (m_PcapDescriptor != NULL)
61
16.8k
  {
62
16.8k
    pcap_close(m_PcapDescriptor);
63
16.8k
    PCPP_LOG_DEBUG("Successfully closed file reader device for filename '" << m_FileName << "'");
64
16.8k
    m_PcapDescriptor = NULL;
65
16.8k
  }
66
67
33.5k
  m_DeviceOpened = false;
68
33.5k
}
69
70
71
// ~~~~~~~~~~~~~~~~~~~~~~~~~
72
// IFileReaderDevice members
73
// ~~~~~~~~~~~~~~~~~~~~~~~~~
74
75
IFileReaderDevice::IFileReaderDevice(const std::string& fileName) : IFileDevice(fileName)
76
17.8k
{
77
17.8k
  m_NumOfPacketsNotParsed = 0;
78
17.8k
  m_NumOfPacketsRead = 0;
79
17.8k
}
80
81
IFileReaderDevice* IFileReaderDevice::getReader(const std::string& fileName)
82
0
{
83
0
  const auto extensionPos = fileName.find_last_of('.');
84
0
  const auto fileExtension = extensionPos != std::string::npos ? fileName.substr(extensionPos) : "";
85
86
0
  if (fileExtension == ".pcapng" || fileExtension == ".zstd" || fileExtension == ".zst")
87
0
    return new PcapNgFileReaderDevice(fileName);
88
0
  else if (fileExtension == ".snoop")
89
0
    return new SnoopFileReaderDevice(fileName);
90
91
0
  return new PcapFileReaderDevice(fileName);
92
0
}
93
94
uint64_t IFileReaderDevice::getFileSize() const
95
0
{
96
0
  std::ifstream fileStream(m_FileName.c_str(), std::ifstream::ate | std::ifstream::binary);
97
0
  return fileStream.tellg();
98
0
}
99
100
int IFileReaderDevice::getNextPackets(RawPacketVector& packetVec, int numOfPacketsToRead)
101
0
{
102
0
  int numOfPacketsRead = 0;
103
104
0
  for (; numOfPacketsToRead < 0 || numOfPacketsRead < numOfPacketsToRead; numOfPacketsRead++)
105
0
  {
106
0
    RawPacket* newPacket = new RawPacket();
107
0
    bool packetRead = getNextPacket(*newPacket);
108
0
    if (packetRead)
109
0
    {
110
0
      packetVec.pushBack(newPacket);
111
0
    }
112
0
    else
113
0
    {
114
0
      delete newPacket;
115
0
      break;
116
0
    }
117
0
  }
118
119
0
  return numOfPacketsRead;
120
0
}
121
122
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123
// SnoopFileReaderDevice members
124
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125
126
SnoopFileReaderDevice::~SnoopFileReaderDevice()
127
0
{
128
0
  m_snoopFile.close();
129
0
}
130
131
bool SnoopFileReaderDevice::open()
132
0
{
133
0
  m_NumOfPacketsRead = 0;
134
0
  m_NumOfPacketsNotParsed = 0;
135
136
0
  m_snoopFile.open(m_FileName.c_str(), std::ifstream::binary);
137
0
  if (!m_snoopFile.is_open())
138
0
  {
139
0
    PCPP_LOG_ERROR("Cannot open snoop reader device for filename '" << m_FileName << "'");
140
0
    m_snoopFile.close();
141
0
    return false;
142
0
  }
143
144
0
  snoop_file_header_t snoop_file_header;
145
0
  m_snoopFile.read((char*)&snoop_file_header, sizeof(snoop_file_header_t));
146
0
  if (!m_snoopFile)
147
0
  {
148
0
    PCPP_LOG_ERROR("Cannot read snoop file header for '" << m_FileName << "'");
149
0
    m_snoopFile.close();
150
0
    return false;
151
0
  }
152
153
0
  if(be64toh(snoop_file_header.identification_pattern) != 0x736e6f6f70000000 && be32toh(snoop_file_header.version_number) == 2)
154
0
    return false;
155
156
  // From https://datatracker.ietf.org/doc/html/rfc1761
157
0
  static const pcpp::LinkLayerType snoop_encap[] = {
158
0
    LINKTYPE_ETHERNET,  /* IEEE 802.3 */
159
0
    LINKTYPE_NULL,    /* IEEE 802.4 Token Bus */
160
0
    LINKTYPE_IEEE802_5, /* IEEE 802.5 */
161
0
    LINKTYPE_NULL,    /* IEEE 802.6 Metro Net */
162
0
    LINKTYPE_ETHERNET,  /* Ethernet */
163
0
    LINKTYPE_C_HDLC,  /* HDLC */
164
0
    LINKTYPE_NULL,    /* Character Synchronous, e.g. bisync */
165
0
    LINKTYPE_NULL,    /* IBM Channel-to-Channel */
166
0
    LINKTYPE_FDDI   /* FDDI */
167
0
  };
168
0
  uint32_t datalink_type = be32toh(snoop_file_header.datalink_type);
169
0
  if (datalink_type > ARRAY_SIZE(snoop_encap) - 1)
170
0
  {
171
0
    PCPP_LOG_ERROR("Cannot read data link type for '" << m_FileName << "'");
172
0
    m_snoopFile.close();
173
0
    return false;
174
0
  }
175
176
0
  m_PcapLinkLayerType = snoop_encap[datalink_type];
177
178
0
  PCPP_LOG_DEBUG("Successfully opened file reader device for filename '" << m_FileName << "'");
179
0
  m_DeviceOpened = true;
180
0
  return true;
181
0
}
182
183
void SnoopFileReaderDevice::getStatistics(PcapStats& stats) const
184
0
{
185
0
  stats.packetsRecv = m_NumOfPacketsRead;
186
0
  stats.packetsDrop = m_NumOfPacketsNotParsed;
187
0
  stats.packetsDropByInterface = 0;
188
0
  PCPP_LOG_DEBUG("Statistics received for reader device for filename '" << m_FileName << "'");
189
0
}
190
191
bool SnoopFileReaderDevice::getNextPacket(RawPacket& rawPacket)
192
0
{
193
0
  rawPacket.clear();
194
0
  if (m_DeviceOpened != true)
195
0
  {
196
0
    PCPP_LOG_ERROR("File device '" << m_FileName << "' not opened");
197
0
    return false;
198
0
  }
199
0
  snoop_packet_header_t snoop_packet_header;
200
0
  m_snoopFile.read((char*)&snoop_packet_header, sizeof(snoop_packet_header_t));
201
0
  if(!m_snoopFile) {
202
0
    return false;
203
0
  }
204
0
  size_t packetSize = be32toh(snoop_packet_header.included_length);
205
0
  if(packetSize > 15000) {
206
0
    return false;
207
0
  }
208
0
  char* packetData = new char[packetSize];
209
0
  m_snoopFile.read(packetData, packetSize);
210
0
  if(!m_snoopFile) {
211
0
    return false;
212
0
  }
213
0
  timespec ts = { static_cast<time_t>(be32toh(snoop_packet_header.time_sec)), static_cast<long>(be32toh(snoop_packet_header.time_usec)) * 1000 };
214
0
  if (!rawPacket.setRawData((const uint8_t*)packetData, packetSize, ts, static_cast<LinkLayerType>(m_PcapLinkLayerType)))
215
0
  {
216
0
    PCPP_LOG_ERROR("Couldn't set data to raw packet");
217
0
    return false;
218
0
  }
219
0
  size_t pad = be32toh(snoop_packet_header.packet_record_length) - (sizeof(snoop_packet_header_t) + be32toh(snoop_packet_header.included_length));
220
0
  m_snoopFile.ignore(pad);
221
0
  if(!m_snoopFile) {
222
0
    return false;
223
0
  }
224
225
0
  m_NumOfPacketsRead++;
226
0
  return true;
227
0
}
228
229
void SnoopFileReaderDevice::close()
230
0
{
231
0
  m_snoopFile.close();
232
0
  m_DeviceOpened = false;
233
0
  PCPP_LOG_DEBUG("File reader closed for file '" << m_FileName << "'");
234
0
}
235
236
237
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238
// PcapFileReaderDevice members
239
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
240
241
242
bool PcapFileReaderDevice::open()
243
17.8k
{
244
17.8k
  m_NumOfPacketsRead = 0;
245
17.8k
  m_NumOfPacketsNotParsed = 0;
246
247
17.8k
  if (m_PcapDescriptor != NULL)
248
0
  {
249
0
    PCPP_LOG_DEBUG("Pcap descriptor already opened. Nothing to do");
250
0
    return true;
251
0
  }
252
253
17.8k
  char errbuf[PCAP_ERRBUF_SIZE];
254
17.8k
#if defined(PCAP_TSTAMP_PRECISION_NANO)
255
17.8k
  m_PcapDescriptor = pcap_open_offline_with_tstamp_precision(m_FileName.c_str(), PCAP_TSTAMP_PRECISION_NANO, errbuf);
256
#else
257
  m_PcapDescriptor = pcap_open_offline(m_FileName.c_str(), errbuf);
258
#endif
259
17.8k
  if (m_PcapDescriptor == NULL)
260
833
  {
261
833
    PCPP_LOG_ERROR("Cannot open file reader device for filename '" << m_FileName << "': " << errbuf);
262
833
    m_DeviceOpened = false;
263
833
    return false;
264
833
  }
265
266
16.9k
  int linkLayer = pcap_datalink(m_PcapDescriptor);
267
16.9k
  if (!RawPacket::isLinkTypeValid(linkLayer))
268
95
  {
269
95
    PCPP_LOG_ERROR("Invalid link layer (" << linkLayer << ") for reader device filename '" << m_FileName << "'");
270
95
    pcap_close(m_PcapDescriptor);
271
95
    m_PcapDescriptor = NULL;
272
95
    m_DeviceOpened = false;
273
95
    return false;
274
95
  }
275
276
16.8k
  m_PcapLinkLayerType = static_cast<LinkLayerType>(linkLayer);
277
278
16.8k
  PCPP_LOG_DEBUG("Successfully opened file reader device for filename '" << m_FileName << "'");
279
16.8k
  m_DeviceOpened = true;
280
16.8k
  return true;
281
16.9k
}
282
283
void PcapFileReaderDevice::getStatistics(PcapStats& stats) const
284
0
{
285
0
  stats.packetsRecv = m_NumOfPacketsRead;
286
0
  stats.packetsDrop = m_NumOfPacketsNotParsed;
287
0
  stats.packetsDropByInterface = 0;
288
0
  PCPP_LOG_DEBUG("Statistics received for reader device for filename '" << m_FileName << "'");
289
0
}
290
291
bool PcapFileReaderDevice::getNextPacket(RawPacket& rawPacket)
292
915k
{
293
915k
  rawPacket.clear();
294
915k
  if (m_PcapDescriptor == NULL)
295
0
  {
296
0
    PCPP_LOG_ERROR("File device '" << m_FileName << "' not opened");
297
0
    return false;
298
0
  }
299
915k
  pcap_pkthdr pkthdr;
300
915k
  const uint8_t* pPacketData = pcap_next(m_PcapDescriptor, &pkthdr);
301
915k
  if (pPacketData == NULL)
302
16.8k
  {
303
16.8k
    PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file");
304
16.8k
    return false;
305
16.8k
  }
306
307
898k
  uint8_t* pMyPacketData = new uint8_t[pkthdr.caplen];
308
898k
  memcpy(pMyPacketData, pPacketData, pkthdr.caplen);
309
898k
#if defined(PCAP_TSTAMP_PRECISION_NANO)
310
898k
  timespec ts = { pkthdr.ts.tv_sec, static_cast<long>(pkthdr.ts.tv_usec) }; //because we opened with nano second precision 'tv_usec' is actually nanos
311
#else
312
  struct timeval ts = pkthdr.ts;
313
#endif
314
898k
  if (!rawPacket.setRawData(pMyPacketData, pkthdr.caplen, ts, static_cast<LinkLayerType>(m_PcapLinkLayerType), pkthdr.len))
315
0
  {
316
0
    PCPP_LOG_ERROR("Couldn't set data to raw packet");
317
0
    return false;
318
0
  }
319
898k
  m_NumOfPacketsRead++;
320
898k
  return true;
321
898k
}
322
323
324
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
325
// PcapNgFileReaderDevice members
326
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
327
328
PcapNgFileReaderDevice::PcapNgFileReaderDevice(const std::string& fileName) : IFileReaderDevice(fileName)
329
0
{
330
0
  m_LightPcapNg = NULL;
331
0
}
332
333
bool PcapNgFileReaderDevice::open()
334
0
{
335
0
  m_NumOfPacketsRead = 0;
336
0
  m_NumOfPacketsNotParsed = 0;
337
338
0
  if (m_LightPcapNg != NULL)
339
0
  {
340
0
    PCPP_LOG_DEBUG("pcapng descriptor already opened. Nothing to do");
341
0
    return true;
342
0
  }
343
344
0
  m_LightPcapNg = light_pcapng_open_read(m_FileName.c_str(), LIGHT_FALSE);
345
0
  if (m_LightPcapNg == NULL)
346
0
  {
347
0
    PCPP_LOG_ERROR("Cannot open pcapng reader device for filename '" << m_FileName << "'");
348
0
    m_DeviceOpened = false;
349
0
    return false;
350
0
  }
351
352
0
  PCPP_LOG_DEBUG("Successfully opened pcapng reader device for filename '" << m_FileName << "'");
353
0
  m_DeviceOpened = true;
354
0
  return true;
355
0
}
356
357
bool PcapNgFileReaderDevice::getNextPacket(RawPacket& rawPacket, std::string& packetComment)
358
0
{
359
0
  rawPacket.clear();
360
0
  packetComment = "";
361
362
0
  if (m_LightPcapNg == NULL)
363
0
  {
364
0
    PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened");
365
0
    return false;
366
0
  }
367
368
0
  light_packet_header pktHeader;
369
0
  const uint8_t* pktData = NULL;
370
371
0
  if (!light_get_next_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, &pktData))
372
0
  {
373
0
    PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file");
374
0
    return false;
375
0
  }
376
377
0
  while (!m_BpfWrapper.matchPacketWithFilter(pktData, pktHeader.captured_length, pktHeader.timestamp, pktHeader.data_link))
378
0
  {
379
0
    if (!light_get_next_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, &pktData))
380
0
    {
381
0
      PCPP_LOG_DEBUG("Packet could not be read. Probably end-of-file");
382
0
      return false;
383
0
    }
384
0
  }
385
386
0
  uint8_t* myPacketData = new uint8_t[pktHeader.captured_length];
387
0
  memcpy(myPacketData, pktData, pktHeader.captured_length);
388
0
  if (!rawPacket.setRawData(myPacketData, pktHeader.captured_length, pktHeader.timestamp, static_cast<LinkLayerType>(pktHeader.data_link), pktHeader.original_length))
389
0
  {
390
0
    PCPP_LOG_ERROR("Couldn't set data to raw packet");
391
0
    return false;
392
0
  }
393
394
0
  if (pktHeader.comment != NULL && pktHeader.comment_length > 0)
395
0
    packetComment = std::string(pktHeader.comment, pktHeader.comment_length);
396
397
0
  m_NumOfPacketsRead++;
398
0
  return true;
399
0
}
400
401
bool PcapNgFileReaderDevice::getNextPacket(RawPacket& rawPacket)
402
0
{
403
0
  std::string temp;
404
0
  return getNextPacket(rawPacket, temp);
405
0
}
406
407
void PcapNgFileReaderDevice::getStatistics(PcapStats& stats) const
408
0
{
409
0
  stats.packetsRecv = m_NumOfPacketsRead;
410
0
  stats.packetsDrop = m_NumOfPacketsNotParsed;
411
0
  stats.packetsDropByInterface = 0;
412
0
  PCPP_LOG_DEBUG("Statistics received for pcapng reader device for filename '" << m_FileName << "'");
413
0
}
414
415
bool PcapNgFileReaderDevice::setFilter(std::string filterAsString)
416
0
{
417
0
  return m_BpfWrapper.setFilter(filterAsString);
418
0
}
419
420
void PcapNgFileReaderDevice::close()
421
0
{
422
0
  if (m_LightPcapNg == NULL)
423
0
    return;
424
425
0
  light_pcapng_close((light_pcapng_t*)m_LightPcapNg);
426
0
  m_LightPcapNg = NULL;
427
428
0
  m_DeviceOpened = false;
429
0
  PCPP_LOG_DEBUG("File reader closed for file '" << m_FileName << "'");
430
0
}
431
432
433
std::string PcapNgFileReaderDevice::getOS() const
434
0
{
435
0
  if (m_LightPcapNg == NULL)
436
0
  {
437
0
    PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened");
438
0
    return "";
439
0
  }
440
441
0
  light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg);
442
0
  char* res = fileInfo->os_desc;
443
0
  size_t len = fileInfo->os_desc_size;
444
0
  if (len == 0 || res == NULL)
445
0
    return "";
446
447
0
  return std::string(res, len);
448
0
}
449
450
std::string PcapNgFileReaderDevice::getHardware() const
451
0
{
452
0
  if (m_LightPcapNg == NULL)
453
0
  {
454
0
    PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened");
455
0
    return "";
456
0
  }
457
458
0
  light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg);
459
0
  char* res = fileInfo->hardware_desc;
460
0
  size_t len = fileInfo->hardware_desc_size;
461
0
  if (len == 0 || res == NULL)
462
0
    return "";
463
464
0
  return std::string(res, len);
465
0
}
466
467
std::string PcapNgFileReaderDevice::getCaptureApplication() const
468
0
{
469
0
  if (m_LightPcapNg == NULL)
470
0
  {
471
0
    PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened");
472
0
    return "";
473
0
  }
474
475
0
  light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg);
476
0
  char* res = fileInfo->user_app_desc;
477
0
  size_t len = fileInfo->user_app_desc_size;
478
0
  if (len == 0 || res == NULL)
479
0
    return "";
480
481
0
  return std::string(res, len);
482
0
}
483
484
std::string PcapNgFileReaderDevice::getCaptureFileComment() const
485
0
{
486
0
  if (m_LightPcapNg == NULL)
487
0
  {
488
0
    PCPP_LOG_ERROR("Pcapng file device '" << m_FileName << "' not opened");
489
0
    return "";
490
0
  }
491
492
0
  light_pcapng_file_info* fileInfo = light_pcang_get_file_info((light_pcapng_t*)m_LightPcapNg);
493
0
  char* res = fileInfo->file_comment;
494
0
  size_t len = fileInfo->file_comment_size;
495
0
  if (len == 0 || res == NULL)
496
0
    return "";
497
498
0
  return std::string(res, len);
499
0
}
500
501
502
// ~~~~~~~~~~~~~~~~~~~~~~~~~
503
// IFileWriterDevice members
504
// ~~~~~~~~~~~~~~~~~~~~~~~~~
505
506
IFileWriterDevice:: IFileWriterDevice(const std::string& fileName) : IFileDevice(fileName)
507
0
{
508
0
  m_NumOfPacketsNotWritten = 0;
509
0
  m_NumOfPacketsWritten = 0;
510
0
}
511
512
513
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
514
// PcapFileWriterDevice members
515
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
516
517
PcapFileWriterDevice::PcapFileWriterDevice(const std::string& fileName, LinkLayerType linkLayerType) : IFileWriterDevice(fileName)
518
0
{
519
0
  m_PcapDumpHandler = NULL;
520
0
  m_NumOfPacketsNotWritten = 0;
521
0
  m_NumOfPacketsWritten = 0;
522
0
  m_PcapLinkLayerType = linkLayerType;
523
0
  m_AppendMode = false;
524
0
  m_File = NULL;
525
0
}
526
527
void PcapFileWriterDevice::closeFile()
528
0
{
529
0
  if (m_AppendMode && m_File != NULL)
530
0
  {
531
0
    fclose(m_File);
532
0
    m_File = NULL;
533
0
  }
534
0
}
535
536
bool PcapFileWriterDevice::writePacket(RawPacket const& packet)
537
0
{
538
0
  if ((!m_AppendMode && m_PcapDescriptor == NULL) || (m_PcapDumpHandler == NULL))
539
0
  {
540
0
    PCPP_LOG_ERROR("Device not opened");
541
0
    m_NumOfPacketsNotWritten++;
542
0
    return false;
543
0
  }
544
545
0
  if (packet.getLinkLayerType() != m_PcapLinkLayerType)
546
0
  {
547
0
    PCPP_LOG_ERROR("Cannot write a packet with a different link layer type");
548
0
    m_NumOfPacketsNotWritten++;
549
0
    return false;
550
0
  }
551
552
0
  pcap_pkthdr pktHdr;
553
0
  pktHdr.caplen = ((RawPacket&)packet).getRawDataLen();
554
0
  pktHdr.len = ((RawPacket&)packet).getFrameLength();
555
0
  timespec packet_timestamp = ((RawPacket&)packet).getPacketTimeStamp();
556
0
  TIMESPEC_TO_TIMEVAL(&pktHdr.ts, &packet_timestamp);
557
0
  if (!m_AppendMode)
558
0
    pcap_dump((uint8_t*)m_PcapDumpHandler, &pktHdr, ((RawPacket&)packet).getRawData());
559
0
  else
560
0
  {
561
    // Below are actually the lines run by pcap_dump. The reason I had to put them instead pcap_dump is that on Windows using WinPcap/Npcap
562
    // you can't pass pointers between libraries compiled with different compilers. In this case - PcapPlusPlus and WinPcap/Npcap weren't
563
    // compiled with the same compiler so it's impossible to fopen a file in PcapPlusPlus, pass the pointer to WinPcap/Npcap and use the
564
    // FILE* pointer there. Doing this throws an exception. So the only option when implementing append to pcap is to write all relevant
565
    // WinPcap/Npcap code that handles opening/closing/writing to pcap files inside PcapPlusPlus code
566
567
    // the reason to create this packet_header struct is timeval has different sizes in 32-bit and 64-bit systems,
568
    // but pcap format uses the 32-bit timeval version, so we need to align timeval to that
569
0
    packet_header pktHdrTemp;
570
0
    pktHdrTemp.tv_sec = pktHdr.ts.tv_sec;
571
0
    pktHdrTemp.tv_usec = pktHdr.ts.tv_usec;
572
0
    pktHdrTemp.caplen = pktHdr.caplen;
573
0
    pktHdrTemp.len = pktHdr.len;
574
0
    fwrite(&pktHdrTemp, sizeof(pktHdrTemp), 1, m_File);
575
0
    fwrite(((RawPacket&)packet).getRawData(), pktHdrTemp.caplen, 1, m_File);
576
0
  }
577
0
  PCPP_LOG_DEBUG("Packet written successfully to '" << m_FileName << "'");
578
0
  m_NumOfPacketsWritten++;
579
0
  return true;
580
0
}
581
582
bool PcapFileWriterDevice::writePackets(const RawPacketVector& packets)
583
0
{
584
0
  for (RawPacketVector::ConstVectorIterator iter = packets.begin(); iter != packets.end(); iter++)
585
0
  {
586
0
    if (!writePacket(**iter))
587
0
      return false;
588
0
  }
589
590
0
  return true;
591
0
}
592
593
bool PcapFileWriterDevice::open()
594
0
{
595
0
  if (m_PcapDescriptor != NULL)
596
0
  {
597
0
    PCPP_LOG_DEBUG("Pcap descriptor already opened. Nothing to do");
598
0
    return true;
599
0
  }
600
601
0
  switch(m_PcapLinkLayerType)
602
0
  {
603
0
    case LINKTYPE_RAW:
604
0
    case LINKTYPE_DLT_RAW2:
605
0
      PCPP_LOG_ERROR("The only Raw IP link type supported in libpcap/WinPcap/Npcap is LINKTYPE_DLT_RAW1, please use that instead");
606
0
      return false;
607
0
    default:
608
0
      break;
609
0
  }
610
611
0
  m_NumOfPacketsNotWritten = 0;
612
0
  m_NumOfPacketsWritten = 0;
613
614
0
  m_PcapDescriptor = pcap_open_dead(m_PcapLinkLayerType, PCPP_MAX_PACKET_SIZE);
615
0
  if (m_PcapDescriptor == NULL)
616
0
  {
617
0
    PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': pcap_open_dead returned NULL");
618
0
    m_DeviceOpened = false;
619
0
    return false;
620
0
  }
621
622
623
0
  m_PcapDumpHandler = pcap_dump_open(m_PcapDescriptor, m_FileName.c_str());
624
0
  if (m_PcapDumpHandler == NULL)
625
0
  {
626
0
    PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': pcap_dump_open returned NULL with error: '" << pcap_geterr(m_PcapDescriptor) << "'");
627
0
    m_DeviceOpened = false;
628
0
    return false;
629
0
  }
630
631
0
  m_DeviceOpened = true;
632
0
  PCPP_LOG_DEBUG("File writer device for file '" << m_FileName << "' opened successfully");
633
0
  return true;
634
0
}
635
636
void PcapFileWriterDevice::flush()
637
0
{
638
0
  if (!m_DeviceOpened)
639
0
    return;
640
641
0
  if (!m_AppendMode && pcap_dump_flush(m_PcapDumpHandler) == -1)
642
0
  {
643
0
    PCPP_LOG_ERROR("Error while flushing the packets to file");
644
0
  }
645
  // in append mode it's impossible to use pcap_dump_flush, see comment above pcap_dump
646
0
  else if (m_AppendMode && fflush(m_File) == EOF)
647
0
  {
648
0
    PCPP_LOG_ERROR("Error while flushing the packets to file");
649
0
  }
650
651
0
}
652
653
void PcapFileWriterDevice::close()
654
0
{
655
0
  if (!m_DeviceOpened)
656
0
    return;
657
658
0
  flush();
659
660
0
  IFileDevice::close();
661
662
0
  if (!m_AppendMode && m_PcapDumpHandler != NULL)
663
0
  {
664
0
    pcap_dump_close(m_PcapDumpHandler);
665
0
  }
666
0
  else if (m_AppendMode && m_File != NULL)
667
0
  {
668
    // in append mode it's impossible to use pcap_dump_close, see comment above pcap_dump
669
0
    fclose(m_File);
670
0
  }
671
672
0
  m_PcapDumpHandler = NULL;
673
0
  m_File = NULL;
674
0
  PCPP_LOG_DEBUG("File writer closed for file '" << m_FileName << "'");
675
0
}
676
677
void PcapFileWriterDevice::getStatistics(PcapStats& stats) const
678
0
{
679
0
  stats.packetsRecv = m_NumOfPacketsWritten;
680
0
  stats.packetsDrop = m_NumOfPacketsNotWritten;
681
0
  stats.packetsDropByInterface = 0;
682
0
  PCPP_LOG_DEBUG("Statistics received for writer device for filename '" << m_FileName << "'");
683
0
}
684
685
bool PcapFileWriterDevice::open(bool appendMode)
686
0
{
687
0
  if (!appendMode)
688
0
    return open();
689
690
0
  m_AppendMode = appendMode;
691
692
0
#if !defined(_WIN32)
693
0
  m_File = fopen(m_FileName.c_str(), "r+");
694
#else
695
  m_File = fopen(m_FileName.c_str(), "rb+");
696
#endif
697
698
0
  if (m_File == NULL)
699
0
  {
700
0
    PCPP_LOG_ERROR("Cannot open '" << m_FileName << "' for reading and writing");
701
0
    return false;
702
0
  }
703
704
0
  pcap_file_header pcapFileHeader;
705
0
  int amountRead = fread(&pcapFileHeader, 1, sizeof(pcapFileHeader), m_File);
706
0
  if (amountRead != sizeof(pcap_file_header))
707
0
  {
708
0
    if (ferror(m_File))
709
0
      PCPP_LOG_ERROR("Cannot read pcap header from file '" << m_FileName << "', error was: " << errno);
710
0
    else
711
0
      PCPP_LOG_ERROR("Cannot read pcap header from file '" << m_FileName << "', unknown error");
712
713
0
    closeFile();
714
0
    return false;
715
0
  }
716
717
0
  LinkLayerType linkLayerType = static_cast<LinkLayerType>(pcapFileHeader.linktype);
718
0
  if (linkLayerType != m_PcapLinkLayerType)
719
0
  {
720
0
    PCPP_LOG_ERROR("Pcap file has a different link layer type than the one chosen in PcapFileWriterDevice c'tor, " << linkLayerType << ", " << m_PcapLinkLayerType);
721
0
    closeFile();
722
0
    return false;
723
0
  }
724
725
0
  if (fseek(m_File, 0, SEEK_END) == -1)
726
0
  {
727
0
    PCPP_LOG_ERROR("Cannot read pcap file '" << m_FileName << "' to it's end, error was: " << errno);
728
0
    closeFile();
729
0
    return false;
730
0
  }
731
732
0
  m_PcapDumpHandler = ((pcap_dumper_t *)m_File);
733
734
0
  m_DeviceOpened = true;
735
0
  PCPP_LOG_DEBUG("File writer device for file '" << m_FileName << "' opened successfully in append mode");
736
0
  return true;
737
0
}
738
739
740
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
741
// PcapNgFileWriterDevice members
742
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
743
744
PcapNgFileWriterDevice::PcapNgFileWriterDevice(const std::string& fileName, int compressionLevel) : IFileWriterDevice(fileName)
745
0
{
746
0
  m_LightPcapNg = NULL;
747
0
  m_CompressionLevel = compressionLevel;
748
0
}
749
750
bool PcapNgFileWriterDevice::open(const std::string& os, const std::string& hardware, const std::string& captureApp, const std::string& fileComment)
751
0
{
752
0
  if (m_LightPcapNg != NULL)
753
0
  {
754
0
    PCPP_LOG_DEBUG("Pcap-ng descriptor already opened. Nothing to do");
755
0
    return true;
756
0
  }
757
758
0
  m_NumOfPacketsNotWritten = 0;
759
0
  m_NumOfPacketsWritten = 0;
760
761
0
  light_pcapng_file_info* info = light_create_file_info(os.c_str(), hardware.c_str(), captureApp.c_str(), fileComment.c_str());
762
763
0
  m_LightPcapNg = light_pcapng_open_write(m_FileName.c_str(), info, m_CompressionLevel);
764
0
  if (m_LightPcapNg == NULL)
765
0
  {
766
0
    PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': light_pcapng_open_write returned NULL");
767
768
0
    light_free_file_info(info);
769
770
0
    m_DeviceOpened = false;
771
0
    return false;
772
0
  }
773
774
0
  m_DeviceOpened = true;
775
0
  PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully");
776
0
  return true;
777
0
}
778
779
bool PcapNgFileWriterDevice::writePacket(RawPacket const& packet, const std::string& comment)
780
0
{
781
0
  if (m_LightPcapNg == NULL)
782
0
  {
783
0
    PCPP_LOG_ERROR("Device not opened");
784
0
    m_NumOfPacketsNotWritten++;
785
0
    return false;
786
0
  }
787
788
0
  if (!m_BpfWrapper.matchPacketWithFilter(&packet))
789
0
  {
790
0
    return false;
791
0
  }
792
793
0
  light_packet_header pktHeader;
794
0
  pktHeader.captured_length = ((RawPacket&)packet).getRawDataLen();
795
0
  pktHeader.original_length = ((RawPacket&)packet).getFrameLength();
796
0
  pktHeader.timestamp = ((RawPacket&)packet).getPacketTimeStamp();
797
0
  pktHeader.data_link = (uint16_t)packet.getLinkLayerType();
798
0
  pktHeader.interface_id = 0;
799
0
  if (!comment.empty())
800
0
  {
801
0
    pktHeader.comment = (char*)comment.c_str();
802
0
    pktHeader.comment_length = static_cast<uint16_t>(comment.size());
803
0
  }
804
0
  else
805
0
  {
806
0
    pktHeader.comment = NULL;
807
0
    pktHeader.comment_length = 0;
808
0
  }
809
810
0
  const uint8_t* pktData = ((RawPacket&)packet).getRawData();
811
812
0
  light_write_packet((light_pcapng_t*)m_LightPcapNg, &pktHeader, pktData);
813
0
  m_NumOfPacketsWritten++;
814
0
  return true;
815
0
}
816
817
bool PcapNgFileWriterDevice::writePacket(RawPacket const& packet)
818
0
{
819
0
  return writePacket(packet, std::string());
820
0
}
821
822
bool PcapNgFileWriterDevice::writePackets(const RawPacketVector& packets)
823
0
{
824
0
  for (RawPacketVector::ConstVectorIterator iter = packets.begin(); iter != packets.end(); iter++)
825
0
  {
826
0
    if (!writePacket(**iter))
827
0
      return false;
828
0
  }
829
830
0
  return true;
831
0
}
832
833
bool PcapNgFileWriterDevice::open()
834
0
{
835
0
  if (m_LightPcapNg != NULL)
836
0
  {
837
0
    PCPP_LOG_DEBUG("Pcap-ng descriptor already opened. Nothing to do");
838
0
    return true;
839
0
  }
840
841
0
  m_NumOfPacketsNotWritten = 0;
842
0
  m_NumOfPacketsWritten = 0;
843
844
0
  light_pcapng_file_info* info = light_create_default_file_info();
845
846
0
  m_LightPcapNg = light_pcapng_open_write(m_FileName.c_str(), info, m_CompressionLevel);
847
0
  if (m_LightPcapNg == NULL)
848
0
  {
849
0
    PCPP_LOG_ERROR("Error opening file writer device for file '" << m_FileName << "': light_pcapng_open_write returned NULL");
850
851
0
    light_free_file_info(info);
852
853
0
    m_DeviceOpened = false;
854
0
    return false;
855
0
  }
856
857
0
  m_DeviceOpened = true;
858
0
  PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully");
859
0
  return true;
860
0
}
861
862
bool PcapNgFileWriterDevice::open(bool appendMode)
863
0
{
864
0
  if (!appendMode)
865
0
    return open();
866
867
0
  m_NumOfPacketsNotWritten = 0;
868
0
  m_NumOfPacketsWritten = 0;
869
870
0
  m_LightPcapNg = light_pcapng_open_append(m_FileName.c_str());
871
0
  if (m_LightPcapNg == NULL)
872
0
  {
873
0
    PCPP_LOG_ERROR("Error opening file writer device in append mode for file '" << m_FileName << "': light_pcapng_open_append returned NULL");
874
0
    m_DeviceOpened = false;
875
0
    return false;
876
0
  }
877
878
0
  m_DeviceOpened = true;
879
0
  PCPP_LOG_DEBUG("pcap-ng writer device for file '" << m_FileName << "' opened successfully");
880
0
  return true;
881
882
0
}
883
884
void PcapNgFileWriterDevice::flush()
885
0
{
886
0
  if (!m_DeviceOpened || m_LightPcapNg == NULL)
887
0
    return;
888
889
0
  light_pcapng_flush((light_pcapng_t*)m_LightPcapNg);
890
0
  PCPP_LOG_DEBUG("File writer flushed to file '" << m_FileName << "'");
891
0
}
892
893
void PcapNgFileWriterDevice::close()
894
0
{
895
0
  if (m_LightPcapNg == NULL)
896
0
    return;
897
898
0
  light_pcapng_close((light_pcapng_t*)m_LightPcapNg);
899
0
  m_LightPcapNg = NULL;
900
901
0
  m_DeviceOpened = false;
902
0
  PCPP_LOG_DEBUG("File writer closed for file '" << m_FileName << "'");
903
0
}
904
905
void PcapNgFileWriterDevice::getStatistics(PcapStats& stats) const
906
0
{
907
0
  stats.packetsRecv = m_NumOfPacketsWritten;
908
0
  stats.packetsDrop = m_NumOfPacketsNotWritten;
909
0
  stats.packetsDropByInterface = 0;
910
0
  PCPP_LOG_DEBUG("Statistics received for pcap-ng writer device for filename '" << m_FileName << "'");
911
0
}
912
913
bool PcapNgFileWriterDevice::setFilter(std::string filterAsString)
914
0
{
915
0
  return m_BpfWrapper.setFilter(filterAsString);
916
0
}
917
918
919
} // namespace pcpp