1"use strict";(globalThis.webpackChunkpcapplusplus_github_io=globalThis.webpackChunkpcapplusplus_github_io||[]).push([[1578],{5962(e,t,n){n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"tutorials/read-write-pcap","title":"Part 2: Read/Write Pcap Files","description":"Introduction","source":"@site/versioned_docs/version-v24.09/tutorials/read-write-pcap.mdx","sourceDirName":"tutorials","slug":"/tutorials/read-write-pcap","permalink":"/docs/v24.09/tutorials/read-write-pcap","draft":false,"unlisted":false,"editUrl":"https://github.com/PcapPlusPlus/pcapplusplus.github.io/edit/master/versioned_docs/version-v24.09/tutorials/read-write-pcap.mdx","tags":[],"version":"v24.09","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"title":"Part 2: Read/Write Pcap Files"},"sidebar":"docs","previous":{"title":"Part 1: Introduction And Basics","permalink":"/docs/v24.09/tutorials/intro"},"next":{"title":"Part 3: Capture/Send Packets","permalink":"/docs/v24.09/tutorials/capture-packets"}}');var a=n(4848),r=n(8453),s=n(3967);const c={sidebar_position:2,title:"Part 2: Read/Write Pcap Files"},l="Part 2: Reading And Writing Pcap Files",p={},o=[{value:"Introduction",id:"introduction",level:2},{value:"Reading and writing packets",id:"reading-and-writing-packets",level:2},{value:"Appending packets to existing files",id:"appending-packets-to-existing-files",level:2},{value:"Running the code",id:"running-the-code",level:2},{value:"Option 1: Install a pre-compiled version of PcapPlusPlus",id:"option-1-install-a-pre-compiled-version-of-pcapplusplus",level:3},{value:"Option 2: build the tutorials with PcapPlusPlus",id:"option-2-build-the-tutorials-with-pcapplusplus",level:3}];function d(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.header,{children:(0,a.jsx)(t.h1,{id:"part-2-reading-and-writing-pcap-files",children:"Part 2: Reading And Writing Pcap Files"})}),"\n",(0,a.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,a.jsx)(t.p,{children:"PcapPlusPlus supports 2 packet capture file formats: pcap and pcap-ng. Using an easy-to-use interface you can easily read and write packets from/to those file types"}),"\n",(0,a.jsx)(t.p,{children:"Essentially there are 4 classes and 2 interfaces for that:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"PcapFileReaderDevice"})," - read packets from pcap files"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"PcapNgFileReaderDevice"})," - read packets from pcap-ng files"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"PcapFileWriterDevice"})," - write packets to a pcap file"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"PcapNgFileWriterDevice"})," - write packets to a pcap-ng file"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"IFileReaderDevice"})," - a reader interface, implemented by both PcapFileReaderDevice and PcapNgFileReaderDevice"]}),"\n",(0,a.jsxs)(t.li,{children:[(0,a.jsx)(t.code,{children:"IFileWriterDevice"})," - a writer interface, implemented by both PcapFileWriterDevice and PcapNgFileWriterDevice"]}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"In this tutorial we'll write a simple application that reads and writes packets from/to pcap and pcap-ng file."}),"\n",(0,a.jsx)(t.h2,{id:"reading-and-writing-packets",children:"Reading and writing packets"}),"\n",(0,a.jsx)(t.p,{children:'So let\'s start our application with a "main" method and a single include to "PcapFileDevice.h" which contains all the API for reading and writing packets from/to files'}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'#include <memory>\n#include <iostream>\n#include "stdlib.h"\n#include "PcapFileDevice.h"\n\n/**\n* main method of the application\n*/\nint main(int argc, char* argv[])\n{\n // write your co
1de here\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["Next thing would be to open a pcap file for reading. We'll assume we have a pcap file named \"input.pcap\" and we want to open it for reading. If we know it's a pcap file we can use the pcap reader class ",(0,a.jsx)(t.code,{children:"PcapFileReaderDevice"}),", and same for pcap-ng files we can use ",(0,a.jsx)(t.code,{children:"PcapNgFileReaderDevice"})," class."]}),"\n",(0,a.jsxs)(t.p,{children:["But PcapPlusPlus also contains an interface class that automatically identifies the file type by its extension and creates an interface instance which both classes implement, so you can use it without really knowing which class hides behind it. This interface is called ",(0,a.jsx)(t.code,{children:"IFileReaderDevice"}),". Let's use it in our application:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// use the IFileReaderDevice interface to automatically identify file type (pcap/pcap-ng)\n// and create an interface instance that both readers implement\nstd::unique_ptr<pcpp::IFileReaderDevice> reader(pcpp::IFileReaderDevice::getReader("input.pcap"));\n\n// verify that a reader interface was indeed created\nif (reader == nullptr)\n{\n std::cerr << "Cannot determine reader for file type" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsxs)(t.p,{children:["As you can see we used the static method ",(0,a.jsx)(t.code,{children:"pcpp::IFileReaderDevice::getReader()"})," to create the interface."]}),"\n",(0,a.jsx)(t.p,{children:"Now let's open the reader for reading:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// open the reader for reading\nif (!reader->open())\n{\n std::cerr << "Cannot open input.pcap for reading" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsx)(t.p,{children:"Now we are ready to start reading packets from the file. But before we do that let's demonstrate using file writers as well. We'll open 2 file writers: one pcap writer and one pcap-ng writer. We'll write the packets we read from the reader to both writers."}),"\n",(0,a.jsx)(t.p,{children:"Let's start by creating the pcap writer and open it for writing:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// create a pcap file writer. Specify file name and link type of all packets that\n// will be written to it\npcpp::PcapFileWriterDevice pcapWriter("output.pcap", pcpp::LINKTYPE_ETHERNET);\n\n// try to open the file for writing\nif (!pcapWriter.open())\n{\n std::cerr << "Cannot open output.pcap for writing" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsx)(t.p,{children:'As you can see we need to specify in the constructor the file name ("output.pcap") and the link type of all packets that will be written to it. That\'s because the pcap file format can contain single link type per file.'}),"\n",(0,a.jsx)(t.p,{children:"Now let's open the second writer that writes pcap-ng files:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// create a pcap-ng file writer. Specify file name. Link type is not necessary because\n// pcap-ng files can store multiple link types in the same file\npcpp::PcapNgFileWriterDevice pcapNgWriter("output.pcapng");\n\n// try to open the file for writing\nif (!pcapNgWriter.open())\n{\n std::cerr << "Cannot open output.pcapng for writing" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsx)(t.p,{children:"You can notice that in this constructor there's no need to specify the link type. That's because pcap-ng files can store multiple link types in the same file."}),"\n",(0,a.jsx)(t.p,{children:'Another cool feature in file readers is setting a BPF filter so only packets that match the filter will be read and the others will be ignored. Let\'s set a filter that will catch only packets with source or dest IP of "98.138.19.88":'}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// set a BPF filter for the reader - only packets that match the filter will be read\nif (!reader->setFilter("net 98.138.19.88"))\n{\n std::cerr << "Cannot set filter for file reader" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsx)(t.p,{children:"Now let's start a while loop where we'll read all the packets (that match the BPF filter) and write them to both writers:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:"// the packet container\npcpp::RawPacket rawPacket;\n\n// a while loop that will continue as long as there are packets in the input file\n// matching the BPF filter\nwhile (reader->getNextPacket(rawPacket))\n{\n // write each packet to both writers\n pcapWriter.writePacket(rawPacket);\n pcapNgWriter.writePacket(rawPacket);\n}\n"})}),"\n",(0,a.jsx)(t.p,{children:"We're done reading all packets that match the BPF filter and writing them to both writers."}),"\n",(0,a.jsx)(t.p,{children:"Another feature I'd like to demonstrate is getting reader/writer statistics. These are basic stats that only count packets that were read/written successfully and those who weren't. Let's get stats from reader and both writers and print them:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// Use lambda to simplify statistics output\nauto printStats = [](const std::string& writerName, const pcpp::IPcapDevice::PcapStats& stats) {\n std::cout << "Written " << stats.packetsRecv << " packets successfully to " << writerName\n << " and " << stats.packetsDrop << " packets could not be written" << std::endl;\n};\n\n// create the stats object\npcpp::IPcapDevice::PcapStats stats;\n\n// read stats from reader and print them\nreader->getStatistics(stats);\nstd::cout << "Read " << stats.packetsRecv << " packets successfully and " << stats.packetsDrop << " packets could not be read" << std::endl;\n\n// read stats from pcap writer and print them\npcapWriter.getStatistics(stats);\nprintStats("pcap writer", stats);\n\n// read stats from pcap-ng writer and print them\npcapNgWriter.getStatistics(stats);\nprintStats("pcap-ng writer", stats);\n'})}),"\n",(0,a.jsxs)(t.p,{children:["We're done reading and writing packets. The only thing left is closing the reader and writers. We also need to free the reader because it was created by the ",(0,a.jsx)(t.code,{children:"pcpp::IFileReaderDevice::getReader()"})," static method."]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:"// close reader\nreader->close();\n\n// close writers\npcapWriter.close();\npcapNgWriter.close();\n"})}),"\n",(0,a.jsx)(t.p,{children:"When running the application with the input.pcap file attached below, here is the output (on Windows):"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"C:\\PcapPlusPlus\\Examples\\Tutorials\\Part2-PcapFiles>Part2-PcapFiles.exe\nRead 10 packets successfully and 0 packets could not be read\nWritten 10 packets successfully to pcap writer and 0 packets could not be written\nWritten 10 packets successfully to pcap-ng writer and 0 packets could not be written\n"})}),"\n",(0,a.jsx)(t.p,{children:'As you can see 10 packets were read successfully from the reader and written to both writers. Notice the original "input.pcap" file contains 28 packets, the reason not all of them were read is the BPF filter we set: only 10 out of the 28 packets matched the filter.'}),"\n",(0,a.jsx)(t.h2,{id:"appending-packets-to-existing-files",children:"Appending packets to existing files"}),"\n",(0,a.jsxs)(t.p,{children:["PcapPlusPlus enables appending packets to existing pcap/pcap-ng files. This means that packets that you write won't overwrite the file but will be apppended to the existing packets in the file. This is a unique feature for PcapPlusPlus that is not supported in libpcap/WinPcap and required specific implementation outside of libpcap/WinPcap APIs. If you want to open a file writer in append mode all you need to do it to use the ",(0,a.jsx)(t.code,{children:"open(bool)"}),' method overload and set it to "true", let\'s see an example:']}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-cpp",children:'// try to open the file for writing in append mode\nif (!pcapWriter.open(true))\n{\n std::cerr << "Cannot open output.pcap for writing in append mode" << std::endl;\n return 1;\n}\n'})}),"\n",(0,a.jsx)(t.p,{children:"That's it! file is now opened in append mode and will not be overridden."}),"\n",(0,a.jsx)(t.h2,{id:"running-the-code",children:"Running the code"}),"\n","\n",(0,a.jsxs)(t.p,{children:["All code that was covered in this tutorial can be found ",(0,a.jsx)(s.A,{relativePath:"/Examples/Tutorials/Tutorial-PcapFiles",children:"here"}),". In order to compile and run the code please choose one of these options:"]}),"\n",(0,a.jsx)(t.h3,{id:"option-1-install-a-pre-compiled-version-of-pcapplusplus",children:"Option 1: Install a pre-compiled version of PcapPlusPlus"}),"\n",(0,a.jsxs)(t.p,{children:["You can download and install PcapPlusPlus using one of the options mentioned in the ",(0,a.jsx)(t.a,{href:"../install",children:"installation page"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["Once installed, download all of the files in the ",(0,a.jsx)(s.A,{relativePath:"/Examples/Tutorials/Tutorial-PcapFiles",children:"tutorial folder"})," and run CMake:"]}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"cmake -S . -B build\ncmake --build build\n"})}),"\n",(0,a.jsx)(t.p,{children:"The executable will be created in the same directory."}),"\n",(0,a.jsx)(t.admonition,{title:"Notes:",type:"tip",children:(0,a.jsxs)(t.ol,{children:["\n",(0,a.jsxs)(t.li,{children:["If you're running on Windows with MinGW you need to run cmake with ",(0,a.jsx)(t.code,{children:'-G "MinGW Makefiles"'})]}),"\n",(0,a.jsxs)(t.li,{children:["If PcapPlusPlus is ",(0,a.jsx)(t.strong,{children:"NOT"}
1)," installed in the default directory you may need to specify ",(0,a.jsx)(t.code,{children:"CMAKE_PREFIX_PATH"}),", for example:","\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"CMAKE_PREFIX_PATH=/my/pcapplusplus/path cmake -S . -B build\n"})}),"\n","Or on Windows:","\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"set CMAKE_PREFIX_PATH=C:\\my\\pcapplusplus\\path\ncmake -S . -B build\n"})}),"\n"]}),"\n",(0,a.jsxs)(t.li,{children:["On Windows you may also need to specify Npcap/WinPcap path in ",(0,a.jsx)(t.code,{children:"CMAKE_PREFIX_PATH"}),", for example:","\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-shell",children:"set CMAKE_PREFIX_PATH=C:\\my\\pcapplusplus\\path;C:\\my\\npcap\\path\ncmake -S . -B build\n"})}),"\n"]}),"\n"]})}),"\n",(0,a.jsx)(t.h3,{id:"option-2-build-the-tutorials-with-pcapplusplus",children:"Option 2: build the tutorials with PcapPlusPlus"}),"\n",(0,a.jsxs)(t.p,{children:["If you're building PcapPlusPlus from source and would like to build the tutorials as well you can use the ",(0,a.jsx)(t.code,{children:"-DPCAPPP_BUILD_TUTORIALS=ON"})," option.\nPlease refer to the ",(0,a.jsx)(t.a,{href:"../install#build-from-source",children:"build from source page"})," for more details (choose your platform page)."]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},3967(e,t,n){n.d(t,{A:()=>r});n(6540);var i=n(5329),a=n(4848);const r=function({relativePath:e,children:t}){return(0,a.jsx)("a",{href:(0,i.t_)()+e,children:t})}},5329(e,t,n){n.d(t,{ZA:()=>p,bX:()=>c,iI:()=>d,i_:()=>o,jA:()=>u,k9:()=>r,kF:()=>s,l:()=>l,t_:()=>h,zk:()=>f});var i=n(4070);const a="https://github.com/seladb/PcapPlusPlus";function r(){return a}function s(){const e=(0,i.r7)(),t=(0,i.ir)();return"Next"===t.label?e.label:t.label}function c(){return s().replace(/^v/,"")}function l(e){return`${a}/releases/tag/${e}`}function p(){return l(s())}function o(){return`${a}/archive/${s()}.zip`}function d(){return`${a}/archive/${s()}.tar.gz`}function h(){const e=(0,i.ir)(),t="Next"===e.label?"master":e.label;return`${a}/tree/${t}`}function u(){return`${a}/archive/master.zip`}function f(){return`${a}/archive/master.tar.gz`}},8453(e,t,n){n.d(t,{R:()=>s,x:()=>c});var i=n(6540);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.