A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
pcap-file.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 University of Washington
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Craig Dowell (craigdo@ee.washington.edu)
18 */
19
20#include "pcap-file.h"
21
22#include "ns3/assert.h"
23#include "ns3/buffer.h"
24#include "ns3/build-profile.h"
25#include "ns3/fatal-error.h"
26#include "ns3/fatal-impl.h"
27#include "ns3/header.h"
28#include "ns3/log.h"
29#include "ns3/packet.h"
30
31#include <cstring>
32#include <iostream>
33
34//
35// This file is used as part of the ns-3 test framework, so please refrain from
36// adding any ns-3 specific constructs such as Packet to this file.
37//
38
39namespace ns3
40{
41
42NS_LOG_COMPONENT_DEFINE("PcapFile");
43
44const uint32_t MAGIC = 0xa1b2c3d4; /**< Magic number identifying standard pcap file format */
45const uint32_t SWAPPED_MAGIC = 0xd4c3b2a1; /**< Looks this way if byte swapping is required */
46
48 0xa1b23c4d; /**< Magic number identifying nanosec resolution pcap file format */
49const uint32_t NS_SWAPPED_MAGIC = 0x4d3cb2a1; /**< Looks this way if byte swapping is required */
50
51const uint16_t VERSION_MAJOR = 2; /**< Major version of supported pcap file format */
52const uint16_t VERSION_MINOR = 4; /**< Minor version of supported pcap file format */
53
55 : m_file(),
56 m_swapMode(false),
57 m_nanosecMode(false)
58{
59 NS_LOG_FUNCTION(this);
61}
62
64{
65 NS_LOG_FUNCTION(this);
67 Close();
68}
69
70bool
72{
73 NS_LOG_FUNCTION(this);
74 return m_file.fail();
75}
76
77bool
79{
80 NS_LOG_FUNCTION(this);
81 return m_file.eof();
82}
83
84void
86{
87 NS_LOG_FUNCTION(this);
88 m_file.clear();
89}
90
91void
93{
94 NS_LOG_FUNCTION(this);
95 m_file.close();
96}
97
100{
101 NS_LOG_FUNCTION(this);
103}
104
105uint16_t
107{
108 NS_LOG_FUNCTION(this);
110}
111
112uint16_t
114{
115 NS_LOG_FUNCTION(this);
117}
118
121{
122 NS_LOG_FUNCTION(this);
123 return m_fileHeader.m_zone;
124}
125
128{
129 NS_LOG_FUNCTION(this);
130 return m_fileHeader.m_sigFigs;
131}
132
135{
136 NS_LOG_FUNCTION(this);
137 return m_fileHeader.m_snapLen;
138}
139
142{
143 NS_LOG_FUNCTION(this);
144 return m_fileHeader.m_type;
145}
146
147bool
149{
150 NS_LOG_FUNCTION(this);
151 return m_swapMode;
152}
153
154bool
156{
157 NS_LOG_FUNCTION(this);
158 return m_nanosecMode;
159}
160
161uint8_t
162PcapFile::Swap(uint8_t val)
163{
164 NS_LOG_FUNCTION(this << static_cast<uint32_t>(val));
165 return val;
166}
167
168uint16_t
169PcapFile::Swap(uint16_t val)
170{
171 NS_LOG_FUNCTION(this << val);
172 return ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00);
173}
174
177{
178 NS_LOG_FUNCTION(this << val);
179 return ((val >> 24) & 0x000000ff) | ((val >> 8) & 0x0000ff00) | ((val << 8) & 0x00ff0000) |
180 ((val << 24) & 0xff000000);
181}
182
183void
185{
186 NS_LOG_FUNCTION(this << from << to);
187 to->m_magicNumber = Swap(from->m_magicNumber);
190 to->m_zone = Swap(uint32_t(from->m_zone));
191 to->m_sigFigs = Swap(from->m_sigFigs);
192 to->m_snapLen = Swap(from->m_snapLen);
193 to->m_type = Swap(from->m_type);
194}
195
196void
198{
199 NS_LOG_FUNCTION(this << from << to);
200 to->m_tsSec = Swap(from->m_tsSec);
201 to->m_tsUsec = Swap(from->m_tsUsec);
202 to->m_inclLen = Swap(from->m_inclLen);
203 to->m_origLen = Swap(from->m_origLen);
204}
205
206void
208{
209 NS_LOG_FUNCTION(this);
210 //
211 // If we're initializing the file, we need to write the pcap file header
212 // at the start of the file.
213 //
214 m_file.seekp(0, std::ios::beg);
215
216 //
217 // We have the ability to write out the pcap file header in a foreign endian
218 // format, so we need a temp place to swap on the way out.
219 //
220 PcapFileHeader header;
221
222 //
223 // the pointer headerOut selects either the swapped or non-swapped version of
224 // the pcap file header.
225 //
226 PcapFileHeader* headerOut = nullptr;
227
228 if (!m_swapMode)
229 {
230 headerOut = &m_fileHeader;
231 }
232 else
233 {
234 Swap(&m_fileHeader, &header);
235 headerOut = &header;
236 }
237
238 //
239 // Watch out for memory alignment differences between machines, so write
240 // them all individually.
241 //
242 m_file.write((const char*)&headerOut->m_magicNumber, sizeof(headerOut->m_magicNumber));
243 m_file.write((const char*)&headerOut->m_versionMajor, sizeof(headerOut->m_versionMajor));
244 m_file.write((const char*)&headerOut->m_versionMinor, sizeof(headerOut->m_versionMinor));
245 m_file.write((const char*)&headerOut->m_zone, sizeof(headerOut->m_zone));
246 m_file.write((const char*)&headerOut->m_sigFigs, sizeof(headerOut->m_sigFigs));
247 m_file.write((const char*)&headerOut->m_snapLen, sizeof(headerOut->m_snapLen));
248 m_file.write((const char*)&headerOut->m_type, sizeof(headerOut->m_type));
249}
250
251void
253{
254 NS_LOG_FUNCTION(this);
255 //
256 // Pcap file header is always at the start of the file
257 //
258 m_file.seekg(0, std::ios::beg);
259
260 //
261 // Watch out for memory alignment differences between machines, so read
262 // them all individually.
263 //
267 m_file.read((char*)&m_fileHeader.m_zone, sizeof(m_fileHeader.m_zone));
268 m_file.read((char*)&m_fileHeader.m_sigFigs, sizeof(m_fileHeader.m_sigFigs));
269 m_file.read((char*)&m_fileHeader.m_snapLen, sizeof(m_fileHeader.m_snapLen));
270 m_file.read((char*)&m_fileHeader.m_type, sizeof(m_fileHeader.m_type));
271
272 if (m_file.fail())
273 {
274 return;
275 }
276
277 //
278 // There are four possible magic numbers that can be there. Normal and byte
279 // swapped versions of the standard magic number, and normal and byte swapped
280 // versions of the magic number indicating nanosecond resolution timestamps.
281 //
284 {
285 m_file.setstate(std::ios::failbit);
286 }
287
288 //
289 // If the magic number is swapped, then we can assume that everything else we read
290 // is swapped.
291 //
294
295 if (m_swapMode)
296 {
298 }
299
300 //
301 // Timestamps can either be microsecond or nanosecond
302 //
305
306 //
307 // We only deal with one version of the pcap file format.
308 //
311 {
312 m_file.setstate(std::ios::failbit);
313 }
314
315 //
316 // A quick test of reasonablness for the time zone offset corresponding to
317 // a real place on the planet.
318 //
319 if (m_fileHeader.m_zone < -12 || m_fileHeader.m_zone > 12)
320 {
321 m_file.setstate(std::ios::failbit);
322 }
323
324 if (m_file.fail())
325 {
326 m_file.close();
327 }
328}
329
330void
331PcapFile::Open(const std::string& filename, std::ios::openmode mode)
332{
333 NS_LOG_FUNCTION(this << filename << mode);
334 NS_ASSERT((mode & std::ios::app) == 0);
335 NS_ASSERT(!m_file.fail());
336 //
337 // All pcap files are binary files, so we just do this automatically.
338 //
339 mode |= std::ios::binary;
340
341 m_filename = filename;
342 m_file.open(filename, mode);
343 if (mode & std::ios::in)
344 {
345 // will set the fail bit if file header is invalid.
347 }
348}
349
350void
352 uint32_t snapLen,
353 int32_t timeZoneCorrection,
354 bool swapMode,
355 bool nanosecMode)
356{
357 NS_LOG_FUNCTION(this << dataLinkType << snapLen << timeZoneCorrection << swapMode);
358
359 //
360 // Initialize the magic number and nanosecond mode flag
361 //
362 m_nanosecMode = nanosecMode;
363 if (nanosecMode)
364 {
366 }
367 else
368 {
370 }
371
372 //
373 // Initialize remainder of the in-memory file header.
374 //
377 m_fileHeader.m_zone = timeZoneCorrection;
379 m_fileHeader.m_snapLen = snapLen;
380 m_fileHeader.m_type = dataLinkType;
381
382 //
383 // We use pcap files for regression testing. We do byte-for-byte comparisons
384 // in those tests to determine pass or fail. If we allow big endian systems
385 // to write big endian headers, they will end up byte-swapped and the
386 // regression tests will fail. Until we get rid of the regression tests, we
387 // have to pick an endianness and stick with it. The precedent is little
388 // endian, so we set swap mode if required to pick little endian.
389 //
390 // We do want to allow a user or test suite to enable swapmode irrespective
391 // of what we decide here, so we allow setting swapmode from formal parameter
392 // as well.
393 //
394 // So, determine the endianness of the running system.
395 //
396 union {
397 uint32_t a;
398 uint8_t b[4];
399 } u;
400
401 u.a = 1;
402 bool bigEndian = u.b[3];
403
404 //
405 // And set swap mode if requested or we are on a big-endian system.
406 //
407 m_swapMode = swapMode || bigEndian;
408
410}
411
414{
415 NS_LOG_FUNCTION(this << tsSec << tsUsec << totalLen);
416 NS_ASSERT(m_file.good());
417
418 uint32_t inclLen = totalLen > m_fileHeader.m_snapLen ? m_fileHeader.m_snapLen : totalLen;
419
420 PcapRecordHeader header;
421 header.m_tsSec = tsSec;
422 header.m_tsUsec = tsUsec;
423 header.m_inclLen = inclLen;
424 header.m_origLen = totalLen;
425
426 if (m_swapMode)
427 {
428 Swap(&header, &header);
429 }
430
431 //
432 // Watch out for memory alignment differences between machines, so write
433 // them all individually.
434 //
435 m_file.write((const char*)&header.m_tsSec, sizeof(header.m_tsSec));
436 m_file.write((const char*)&header.m_tsUsec, sizeof(header.m_tsUsec));
437 m_file.write((const char*)&header.m_inclLen, sizeof(header.m_inclLen));
438 m_file.write((const char*)&header.m_origLen, sizeof(header.m_origLen));
439 NS_BUILD_DEBUG(m_file.flush());
440 return inclLen;
441}
442
443void
444PcapFile::Write(uint32_t tsSec, uint32_t tsUsec, const uint8_t* const data, uint32_t totalLen)
445{
446 NS_LOG_FUNCTION(this << tsSec << tsUsec << &data << totalLen);
447 uint32_t inclLen = WritePacketHeader(tsSec, tsUsec, totalLen);
448 m_file.write((const char*)data, inclLen);
449 NS_BUILD_DEBUG(m_file.flush());
450}
451
452void
454{
455 NS_LOG_FUNCTION(this << tsSec << tsUsec << p);
456 uint32_t inclLen = WritePacketHeader(tsSec, tsUsec, p->GetSize());
457 p->CopyData(&m_file, inclLen);
458 NS_BUILD_DEBUG(m_file.flush());
459}
460
461void
463{
464 NS_LOG_FUNCTION(this << tsSec << tsUsec << &header << p);
465 uint32_t headerSize = header.GetSerializedSize();
466 uint32_t totalSize = headerSize + p->GetSize();
467 uint32_t inclLen = WritePacketHeader(tsSec, tsUsec, totalSize);
468
469 Buffer headerBuffer;
470 headerBuffer.AddAtStart(headerSize);
471 header.Serialize(headerBuffer.Begin());
472 uint32_t toCopy = std::min(headerSize, inclLen);
473 headerBuffer.CopyData(&m_file, toCopy);
474 inclLen -= toCopy;
475 p->CopyData(&m_file, inclLen);
476}
477
478void
479PcapFile::Read(uint8_t* const data,
480 uint32_t maxBytes,
481 uint32_t& tsSec,
482 uint32_t& tsUsec,
483 uint32_t& inclLen,
484 uint32_t& origLen,
485 uint32_t& readLen)
486{
487 NS_LOG_FUNCTION(this << &data << maxBytes << tsSec << tsUsec << inclLen << origLen << readLen);
488 NS_ASSERT(m_file.good());
489
490 PcapRecordHeader header;
491
492 //
493 // Watch out for memory alignment differences between machines, so read
494 // them all individually.
495 //
496 m_file.read((char*)&header.m_tsSec, sizeof(header.m_tsSec));
497 m_file.read((char*)&header.m_tsUsec, sizeof(header.m_tsUsec));
498 m_file.read((char*)&header.m_inclLen, sizeof(header.m_inclLen));
499 m_file.read((char*)&header.m_origLen, sizeof(header.m_origLen));
500
501 if (m_file.fail())
502 {
503 return;
504 }
505
506 if (m_swapMode)
507 {
508 Swap(&header, &header);
509 }
510
511 tsSec = header.m_tsSec;
512 tsUsec = header.m_tsUsec;
513 inclLen = header.m_inclLen;
514 origLen = header.m_origLen;
515
516 //
517 // We don't always want to force the client to keep a maximum length buffer
518 // around so we allow her to specify a minimum number of bytes to read.
519 // Usually 64 bytes is enough information to print all of the headers, so
520 // it isn't typically necessary to read all thousand bytes of an echo packet,
521 // for example, to figure out what is going on.
522 //
523 readLen = maxBytes < header.m_inclLen ? maxBytes : header.m_inclLen;
524 m_file.read((char*)data, readLen);
525
526 //
527 // To keep the file pointer pointed in the right place, however, we always
528 // need to account for the entire packet as stored originally.
529 //
530 if (readLen < header.m_inclLen)
531 {
532 m_file.seekg(header.m_inclLen - readLen, std::ios::cur);
533 }
534}
535
536bool
537PcapFile::Diff(const std::string& f1,
538 const std::string& f2,
539 uint32_t& sec,
540 uint32_t& usec,
541 uint32_t& packets,
542 uint32_t snapLen)
543{
544 NS_LOG_FUNCTION(f1 << f2 << sec << usec << snapLen);
545 PcapFile pcap1;
546 PcapFile pcap2;
547 pcap1.Open(f1, std::ios::in);
548 pcap2.Open(f2, std::ios::in);
549 bool bad = pcap1.Fail() || pcap2.Fail();
550 if (bad)
551 {
552 return true;
553 }
554
555 auto data1 = new uint8_t[snapLen]();
556 auto data2 = new uint8_t[snapLen]();
557 uint32_t tsSec1 = 0;
558 uint32_t tsSec2 = 0;
559 uint32_t tsUsec1 = 0;
560 uint32_t tsUsec2 = 0;
561 uint32_t inclLen1 = 0;
562 uint32_t inclLen2 = 0;
563 uint32_t origLen1 = 0;
564 uint32_t origLen2 = 0;
565 uint32_t readLen1 = 0;
566 uint32_t readLen2 = 0;
567 bool diff = false;
568
569 while (!pcap1.Eof() && !pcap2.Eof())
570 {
571 pcap1.Read(data1, snapLen, tsSec1, tsUsec1, inclLen1, origLen1, readLen1);
572 pcap2.Read(data2, snapLen, tsSec2, tsUsec2, inclLen2, origLen2, readLen2);
573
574 bool same = pcap1.Fail() == pcap2.Fail();
575 if (!same)
576 {
577 diff = true;
578 break;
579 }
580 if (pcap1.Eof())
581 {
582 break;
583 }
584
585 ++packets;
586
587 if (tsSec1 != tsSec2 || tsUsec1 != tsUsec2)
588 {
589 diff = true; // Next packet timestamps do not match
590 break;
591 }
592
593 if (readLen1 != readLen2)
594 {
595 diff = true; // Packet lengths do not match
596 break;
597 }
598
599 if (std::memcmp(data1, data2, readLen1) != 0)
600 {
601 diff = true; // Packet data do not match
602 break;
603 }
604 }
605 sec = tsSec1;
606 usec = tsUsec1;
607
608 bad = pcap1.Fail() || pcap2.Fail();
609 bool eof = pcap1.Eof() && pcap2.Eof();
610 if (bad && !eof)
611 {
612 diff = true;
613 }
614
615 delete[] data1;
616 delete[] data2;
617
618 return diff;
619}
620
621} // namespace ns3
automatically resized byte buffer
Definition: buffer.h:94
void CopyData(std::ostream *os, uint32_t size) const
Copy the specified amount of data from the buffer to the given output stream.
Definition: buffer.cc:713
void AddAtStart(uint32_t start)
Definition: buffer.cc:314
Buffer::Iterator Begin() const
Definition: buffer.h:1074
Protocol header serialization and deserialization.
Definition: header.h:44
virtual uint32_t GetSerializedSize() const =0
virtual void Serialize(Buffer::Iterator start) const =0
A class representing a pcap file.
Definition: pcap-file.h:43
bool IsNanoSecMode()
Get the nanosecond mode of the file.
Definition: pcap-file.cc:155
void Close()
Close the underlying file.
Definition: pcap-file.cc:92
static bool Diff(const std::string &f1, const std::string &f2, uint32_t &sec, uint32_t &usec, uint32_t &packets, uint32_t snapLen=SNAPLEN_DEFAULT)
Compare two PCAP files packet-by-packet.
Definition: pcap-file.cc:537
void Open(const std::string &filename, std::ios::openmode mode)
Create a new pcap file or open an existing pcap file.
Definition: pcap-file.cc:331
uint32_t GetDataLinkType()
Returns the data link type field of the pcap file as defined by the network field in the pcap global ...
Definition: pcap-file.cc:141
bool m_swapMode
swap mode
Definition: pcap-file.h:379
void Read(uint8_t *const data, uint32_t maxBytes, uint32_t &tsSec, uint32_t &tsUsec, uint32_t &inclLen, uint32_t &origLen, uint32_t &readLen)
Read next packet from file.
Definition: pcap-file.cc:479
uint32_t GetMagic()
Returns the magic number of the pcap file as defined by the magic_number field in the pcap global hea...
Definition: pcap-file.cc:99
uint16_t GetVersionMajor()
Returns the major version of the pcap file as defined by the version_major field in the pcap global h...
Definition: pcap-file.cc:106
std::string m_filename
file name
Definition: pcap-file.h:376
uint16_t GetVersionMinor()
Returns the minor version of the pcap file as defined by the version_minor field in the pcap global h...
Definition: pcap-file.cc:113
PcapFileHeader m_fileHeader
file header
Definition: pcap-file.h:378
void Clear()
Clear all state bits of the underlying iostream.
Definition: pcap-file.cc:85
uint32_t WritePacketHeader(uint32_t tsSec, uint32_t tsUsec, uint32_t totalLen)
Write a Pcap packet header.
Definition: pcap-file.cc:413
void Init(uint32_t dataLinkType, uint32_t snapLen=SNAPLEN_DEFAULT, int32_t timeZoneCorrection=ZONE_DEFAULT, bool swapMode=false, bool nanosecMode=false)
Initialize the pcap file associated with this object.
Definition: pcap-file.cc:351
void Write(uint32_t tsSec, uint32_t tsUsec, const uint8_t *const data, uint32_t totalLen)
Write next packet to file.
Definition: pcap-file.cc:444
bool Eof() const
Definition: pcap-file.cc:78
bool Fail() const
Definition: pcap-file.cc:71
uint32_t GetSnapLen()
Returns the max length of saved packets field of the pcap file as defined by the snaplen field in the...
Definition: pcap-file.cc:134
bool GetSwapMode()
Get the swap mode of the file.
Definition: pcap-file.cc:148
bool m_nanosecMode
nanosecond timestamp mode
Definition: pcap-file.h:380
int32_t GetTimeZoneOffset()
Returns the time zone offset of the pcap file as defined by the thiszone field in the pcap global hea...
Definition: pcap-file.cc:120
std::fstream m_file
file stream
Definition: pcap-file.h:377
void ReadAndVerifyFileHeader()
Read and verify a Pcap file header.
Definition: pcap-file.cc:252
void WriteFileHeader()
Write a Pcap file header.
Definition: pcap-file.cc:207
uint32_t GetSigFigs()
Returns the accuracy of timestamps field of the pcap file as defined by the sigfigs field in the pcap...
Definition: pcap-file.cc:127
uint8_t Swap(uint8_t val)
Swap a value byte order.
Definition: pcap-file.cc:162
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_BUILD_DEBUG(code)
Execute a code snippet in debug builds.
Definition: build-profile.h:60
void UnregisterStream(std::ostream *stream)
Unregister a stream for flushing on abnormal exit.
Definition: fatal-impl.cc:143
void RegisterStream(std::ostream *stream)
Register a stream to be flushed on abnormal exit.
Definition: fatal-impl.cc:136
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
const uint32_t MAGIC
Magic number identifying standard pcap file format.
Definition: pcap-file.cc:44
const uint32_t NS_SWAPPED_MAGIC
Looks this way if byte swapping is required.
Definition: pcap-file.cc:49
const uint32_t SWAPPED_MAGIC
Looks this way if byte swapping is required.
Definition: pcap-file.cc:45
const uint16_t VERSION_MINOR
Minor version of supported pcap file format.
Definition: pcap-file.cc:52
const uint32_t NS_MAGIC
Magic number identifying nanosec resolution pcap file format.
Definition: pcap-file.cc:47
const uint16_t VERSION_MAJOR
Major version of supported pcap file format.
Definition: pcap-file.cc:51
uint8_t data[writeSize]
uint32_t m_magicNumber
Magic number identifying this as a pcap file.
Definition: pcap-file.h:301
uint32_t m_sigFigs
Unused by pretty much everybody.
Definition: pcap-file.h:307
int32_t m_zone
Time zone correction to be applied to timestamps of packets.
Definition: pcap-file.h:306
uint16_t m_versionMajor
Major version identifying the version of pcap used in this file.
Definition: pcap-file.h:303
uint32_t m_type
Data link type of packet data.
Definition: pcap-file.h:309
uint32_t m_snapLen
Maximum length of packet data stored in records.
Definition: pcap-file.h:308
uint16_t m_versionMinor
Minor version identifying the version of pcap used in this file.
Definition: pcap-file.h:305
Pcap record header.
Definition: pcap-file.h:316
uint32_t m_inclLen
number of octets of packet saved in file
Definition: pcap-file.h:319
uint32_t m_tsUsec
microseconds part of timestamp (nsecs for PCAP_NSEC_MAGIC)
Definition: pcap-file.h:318
uint32_t m_tsSec
seconds part of timestamp
Definition: pcap-file.h:317
uint32_t m_origLen
actual length of original packet
Definition: pcap-file.h:320