bool PcapFileWriterDevice::writePacket(RawPacket const& packet) { if ((!m_AppendMode && m_PcapDescriptor == NULL) || (m_PcapDumpHandler == NULL)) { LOG_ERROR("Device not opened"); m_NumOfPacketsNotWritten++; return false; } if (packet.getLinkLayerType() != m_PcapLinkLayerType) { LOG_ERROR("Cannot write a packet with a different link layer type"); m_NumOfPacketsNotWritten++; return false; } pcap_pkthdr pktHdr; pktHdr.caplen = ((RawPacket&)packet).getRawDataLen(); pktHdr.len = ((RawPacket&)packet).getRawDataLen(); pktHdr.ts = ((RawPacket&)packet).getPacketTimeStamp(); if (!m_AppendMode) pcap_dump((uint8_t*)m_PcapDumpHandler, &pktHdr, ((RawPacket&)packet).getRawData()); else { // 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 // you can't pass pointers between libraries compiled with different compilers. In this case - PcapPlusPlus and WinPcap weren't // compiled with the same compiler so it's impossible to fopen a file in PcapPlusPlus, pass the pointer to WinPcap and use the // FILE* pointer there. Doing this throws an exception. So the only option when implementing append to pcap is to write all relevant // WinPcap code that handles opening/closing/writing to pcap files inside PcapPlusPlus code fwrite(&pktHdr, sizeof(pktHdr), 1, m_File); fwrite(((RawPacket&)packet).getRawData(), pktHdr.caplen, 1, m_File); } LOG_DEBUG("Packet written successfully to '%s'", m_FileName); m_NumOfPacketsWritten++; return true; }
/** * main method of this utility */ int main(int argc, char* argv[]) { AppName::init(argc, argv); std::string inputPcapFileName = ""; std::string outputPcapDir = ""; std::string filter = ""; std::string method = ""; char param[1000]; memset(param, 0, 1000); bool paramWasSet = false; int optionIndex = 0; char opt = 0; while((opt = getopt_long (argc, argv, "f:o:m:p:i:vh", PcapSplitterOptions, &optionIndex)) != -1) { switch (opt) { case 0: break; case 'f': inputPcapFileName = optarg; break; case 'o': outputPcapDir = optarg; break; case 'm': method = optarg; break; case 'p': strncpy(param, optarg, 999); paramWasSet = true; break; case 'i': filter = optarg; break; case 'h': printUsage(); break; case 'v': printAppVersion(); break; default: printUsage(); exit(-1); } } if (inputPcapFileName == "") { EXIT_WITH_ERROR("Input file name was not given"); } if (outputPcapDir == "") { EXIT_WITH_ERROR("Output directory name was not given"); } if (!pcpp::directoryExists(outputPcapDir)) { EXIT_WITH_ERROR("Output directory doesn't exist"); } if (method == "") { EXIT_WITH_ERROR("Split method was not given"); } Splitter* splitter = NULL; // decide of the splitter to use, according to the user's choice if (method == SPLIT_BY_FILE_SIZE) { uint64_t paramAsUint64 = (paramWasSet ? strtoull(param, NULL, 10) : 0); splitter = new FileSizeSplitter(paramAsUint64); } else if (method == SPLIT_BY_PACKET_COUNT) { int paramAsInt = (paramWasSet ? atoi(param) : 0); splitter = new PacketCountSplitter(paramAsInt); } else if (method == SPLIT_BY_IP_CLIENT) { int paramAsInt = (paramWasSet ? atoi(param) : SplitterWithMaxFiles::UNLIMITED_FILES_MAGIC_NUMBER); splitter = new ClientIPSplitter(paramAsInt); } else if (method == SPLIT_BY_IP_SERVER) { int paramAsInt = (paramWasSet ? atoi(param) : SplitterWithMaxFiles::UNLIMITED_FILES_MAGIC_NUMBER); splitter = new ServerIPSplitter(paramAsInt); } else if (method == SPLIT_BY_SERVER_PORT) { int paramAsInt = (paramWasSet ? atoi(param) : SplitterWithMaxFiles::UNLIMITED_FILES_MAGIC_NUMBER); splitter = new ServerPortSplitter(paramAsInt); } else if (method == SPLIT_BY_2_TUPLE) { int paramAsInt = (paramWasSet ? atoi(param) : SplitterWithMaxFiles::UNLIMITED_FILES_MAGIC_NUMBER); splitter = new TwoTupleSplitter(paramAsInt); } else if (method == SPLIT_BY_5_TUPLE) { int paramAsInt = (paramWasSet ? atoi(param) : SplitterWithMaxFiles::UNLIMITED_FILES_MAGIC_NUMBER); splitter = new FiveTupleSplitter(paramAsInt); } else if (method == SPLIT_BY_BPF_FILTER) { splitter = new BpfCriteriaSplitter(std::string(param)); } else if (method == SPLIT_BY_ROUND_ROBIN) { int paramAsInt = (paramWasSet ? atoi(param) : 0); splitter = new RoundRobinSplitter(paramAsInt); } else EXIT_WITH_ERROR("Unknown method '%s'", method.c_str()); // verify splitter param is legal, otherwise return an error std::string errorStr; if (!splitter->isSplitterParamLegal(errorStr)) { EXIT_WITH_ERROR("%s", errorStr.c_str()); } // prepare the output file format: /requested-path/original-file-name-[4-digit-number-starting-at-0000].pcap std::string outputPcapFileName = outputPcapDir + std::string(1, SEPARATOR) + getFileNameWithoutExtension(inputPcapFileName) + "-"; // open a pcap file for reading IFileReaderDevice* reader = IFileReaderDevice::getReader(inputPcapFileName.c_str()); bool isReaderPcapng = (dynamic_cast<PcapNgFileReaderDevice*>(reader) != NULL); if (reader == NULL || !reader->open()) { EXIT_WITH_ERROR("Error opening input pcap file\n"); } // set a filter if provided if (filter != "") { if (!reader->setFilter(filter)) EXIT_WITH_ERROR("Couldn't set filter '%s'", filter.c_str()); } printf("Started...\n"); // determine output file extension std::string outputFileExtenison = (isReaderPcapng ? ".pcapng" : ".pcap"); int packetCountSoFar = 0; int numOfFiles = 0; RawPacket rawPacket; // prepare a map of file number to IFileWriterDevice std::map<int, IFileWriterDevice*> outputFiles; // read all packets from input file, for each packet do: while (reader->getNextPacket(rawPacket)) { // parse the raw packet into a parsed packet Packet parsedPacket(&rawPacket); std::vector<int> filesToClose; // call the splitter to get the file number to write the current packet to int fileNum = splitter->getFileNumber(parsedPacket, filesToClose); // if file number is seen for the first time (meaning it's the first packet written to it) if (outputFiles.find(fileNum) == outputFiles.end()) { // get file name from the splitter and add the .pcap extension std::string fileName = splitter->getFileName(parsedPacket, outputPcapFileName, fileNum) + outputFileExtenison; // create a new IFileWriterDevice for this file if (isReaderPcapng) { // if reader is pcapng, create a pcapng writer outputFiles[fileNum] = new PcapNgFileWriterDevice(fileName.c_str()); } else { // if reader is pcap, create a pcap writer outputFiles[fileNum] = new PcapFileWriterDevice(fileName.c_str(), rawPacket.getLinkLayerType()); } // open the writer if (!outputFiles[fileNum]->open()) break; numOfFiles++; } // if file number exists in the map but PcapFileWriterDevice is null it means this file was open once and // then closed. In this case we need to re-open the PcapFileWriterDevice in append mode else if (outputFiles[fileNum] == NULL) { // get file name from the splitter and add the .pcap extension std::string fileName = splitter->getFileName(parsedPacket, outputPcapFileName, fileNum) + outputFileExtenison; // re-create the IFileWriterDevice object if (isReaderPcapng) { // if reader is pcapng, create a pcapng writer outputFiles[fileNum] = new PcapNgFileWriterDevice(fileName.c_str()); } else { // if reader is pcap, create a pcap writer outputFiles[fileNum] = new PcapFileWriterDevice(fileName.c_str(), rawPacket.getLinkLayerType()); } // open the writer in __append__ mode if (!outputFiles[fileNum]->open(true)) break; } // write the packet to the writer outputFiles[fileNum]->writePacket(*parsedPacket.getRawPacket()); // if splitter wants us to close files - go over the file numbers and close them for (std::vector<int>::iterator it = filesToClose.begin(); it != filesToClose.end(); it++) { // check if that file number is in the map if (outputFiles.find(*it) != outputFiles.end()) { // close the writer outputFiles[*it]->close(); // free the writer memory and put null in the map record delete outputFiles[*it]; outputFiles[*it] = NULL; } } packetCountSoFar++; } std::cout << "Finished. Read and written " << packetCountSoFar << " packets to " << numOfFiles << " files" << std::endl; // close the reader file reader->close(); // free reader memory delete reader; // close the writer files which are still open for(std::map<int, IFileWriterDevice*>::iterator it = outputFiles.begin(); it != outputFiles.end(); ++it) { if (it->second != NULL) it->second->close(); } return 0; }