From 959369d5935db40ad0eaa7247043ae0ecb6b412b Mon Sep 17 00:00:00 2001 From: MCredbear <40625974+MCredbear@users.noreply.github.com> Date: Wed, 26 Jun 2024 05:02:43 +0800 Subject: [PATCH] Check size of tcpFragmentList before delete fragment (#1346) --- Packet++/header/TcpReassembly.h | 21 +++ Packet++/src/TcpReassembly.cpp | 88 ++++++------ ..._missing_date_with_manual_close_output.txt | 37 +++++ ..._out_of_order_with_manual_close_output.txt | 37 +++++ Tests/Pcap++Test/TestDefinition.h | 1 + Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp | 129 ++++++++++++++++++ Tests/Pcap++Test/main.cpp | 1 + 7 files changed, 267 insertions(+), 47 deletions(-) create mode 100644 Tests/Pcap++Test/PcapExamples/one_tcp_stream_missing_date_with_manual_close_output.txt create mode 100644 Tests/Pcap++Test/PcapExamples/one_tcp_stream_out_of_order_with_manual_close_output.txt diff --git a/Packet++/header/TcpReassembly.h b/Packet++/header/TcpReassembly.h index c6e4e5824b..78b4d2a6f5 100644 --- a/Packet++/header/TcpReassembly.h +++ b/Packet++/header/TcpReassembly.h @@ -429,6 +429,26 @@ class TcpReassembly TcpReassemblyData() : closed(false), numOfSides(0), prevSide(-1) {} }; + class OutOfOrderProcessingGuard + { + private: + bool& m_Flag; + public: + explicit OutOfOrderProcessingGuard(bool& flag) : m_Flag(flag) + { + m_Flag = true; + } + + ~OutOfOrderProcessingGuard() + { + m_Flag = false; + } + + // Disable copy and move operations + OutOfOrderProcessingGuard(const OutOfOrderProcessingGuard&) = delete; + OutOfOrderProcessingGuard& operator=(const OutOfOrderProcessingGuard&) = delete; + }; + typedef std::unordered_map ConnectionList; typedef std::map > CleanupList; @@ -445,6 +465,7 @@ class TcpReassembly size_t m_MaxOutOfOrderFragments; time_t m_PurgeTimepoint; bool m_EnableBaseBufferClearCondition; + bool m_ProcessingOutOfOrder = false; void checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyData, int8_t sideIndex, bool cleanWholeFragList); diff --git a/Packet++/src/TcpReassembly.cpp b/Packet++/src/TcpReassembly.cpp index 307e8859b4..21c9aeedf9 100644 --- a/Packet++/src/TcpReassembly.cpp +++ b/Packet++/src/TcpReassembly.cpp @@ -226,7 +226,7 @@ TcpReassembly::ReassemblyStatus TcpReassembly::reassemblePacket(Packet& tcpData) // if this side already got FIN or RST packet before, ignore this packet as this side is considered closed if (tcpReassemblyData->twoSides[sideIndex].gotFinOrRst) { - PCPP_LOG_DEBUG("Got a packet after FIN or RST were already seen on this side (" << sideIndex << "). Ignoring this packet"); + PCPP_LOG_DEBUG("Got a packet after FIN or RST were already seen on this side (" << static_cast(sideIndex) << "). Ignoring this packet"); return Ignore_PacketOfClosedFlow; } @@ -256,7 +256,7 @@ TcpReassembly::ReassemblyStatus TcpReassembly::reassemblePacket(Packet& tcpData) if (m_EnableBaseBufferClearCondition && !first && tcpPayloadSize > 0 && tcpReassemblyData->prevSide != -1 && tcpReassemblyData->prevSide != sideIndex && tcpReassemblyData->twoSides[tcpReassemblyData->prevSide].tcpFragmentList.size() > 0) { - PCPP_LOG_DEBUG("Seeing a first data packet from a different side. Previous side was " << tcpReassemblyData->prevSide << ", current side is " << sideIndex); + PCPP_LOG_DEBUG("Seeing a first data packet from a different side. Previous side was " << static_cast(tcpReassemblyData->prevSide) << ", current side is " << static_cast(sideIndex)); checkOutOfOrderFragments(tcpReassemblyData, tcpReassemblyData->prevSide, true); } tcpReassemblyData->prevSide = sideIndex; @@ -412,7 +412,7 @@ TcpReassembly::ReassemblyStatus TcpReassembly::reassemblePacket(Packet& tcpData) memcpy(newTcpFrag->data, tcpLayer->getLayerPayload(), tcpPayloadSize); tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.pushBack(newTcpFrag); - PCPP_LOG_DEBUG("Found out-of-order packet and added a new TCP fragment with size " << tcpPayloadSize << " to the out-of-order list of side " << sideIndex); + PCPP_LOG_DEBUG("Found out-of-order packet and added a new TCP fragment with size " << tcpPayloadSize << " to the out-of-order list of side " << static_cast(sideIndex)); status = OutOfOrderTcpMessageBuffered; // check if we've stored too many out-of-order fragments; if so, consider missing packets lost and @@ -451,7 +451,7 @@ void TcpReassembly::handleFinOrRst(TcpReassemblyData* tcpReassemblyData, int8_t if (tcpReassemblyData->twoSides[sideIndex].gotFinOrRst) return; - PCPP_LOG_DEBUG("Handling FIN or RST packet on side " << sideIndex); + PCPP_LOG_DEBUG("Handling FIN or RST packet on side " << static_cast(sideIndex)); // set FIN/RST flag for this side tcpReassemblyData->twoSides[sideIndex].gotFinOrRst = true; @@ -473,34 +473,42 @@ void TcpReassembly::handleFinOrRst(TcpReassemblyData* tcpReassemblyData, int8_t void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyData, int8_t sideIndex, bool cleanWholeFragList) { + if (m_ProcessingOutOfOrder) + { + return; + } + + OutOfOrderProcessingGuard guard(m_ProcessingOutOfOrder); + bool foundSomething = false; + auto& curSideData = tcpReassemblyData->twoSides[sideIndex]; + do { PCPP_LOG_DEBUG("Starting first iteration of checkOutOfOrderFragments - looking for fragments that match the current sequence or have smaller sequence"); - int index = 0; foundSomething = false; do { - index = 0; + auto tcpFragIter = curSideData.tcpFragmentList.begin(); foundSomething = false; // first fragment list iteration - go over the whole fragment list and see if can find fragments that match the current sequence // or have smaller sequence but have big enough payload to get new data - while (index < (int)tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.size()) + while (tcpFragIter != curSideData.tcpFragmentList.end()) { - TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(index); - // if fragment sequence matches the current sequence - if (curTcpFrag->sequence == tcpReassemblyData->twoSides[sideIndex].sequence) + if ((*tcpFragIter)->sequence == curSideData.sequence) { + // pop the fragment from fragment list + auto curTcpFrag = std::unique_ptr(curSideData.tcpFragmentList.getAndRemoveFromVector(tcpFragIter)); // update sequence - tcpReassemblyData->twoSides[sideIndex].sequence += curTcpFrag->dataLength; + curSideData.sequence += curTcpFrag->dataLength; if (curTcpFrag->data != nullptr) { - PCPP_LOG_DEBUG("Found an out-of-order packet matching to the current sequence with size " << curTcpFrag->dataLength << " on side " << sideIndex << ". Pulling it out of the list and sending the data to the callback"); + PCPP_LOG_DEBUG("Found an out-of-order packet matching to the current sequence with size " << curTcpFrag->dataLength << " on side " << static_cast(sideIndex) << ". Pulling it out of the list and sending the data to the callback"); // send new data to callback @@ -511,32 +519,30 @@ void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyDat } } - - // remove fragment from list - tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + index); - foundSomething = true; continue; } // if fragment sequence has lower sequence than the current sequence - if (SEQ_LT(curTcpFrag->sequence, tcpReassemblyData->twoSides[sideIndex].sequence)) + if (SEQ_LT((*tcpFragIter)->sequence, curSideData.sequence)) { + // pop the fragment from fragment list + auto curTcpFrag = std::unique_ptr(curSideData.tcpFragmentList.getAndRemoveFromVector(tcpFragIter)); // check if it still has new data uint32_t newSequence = curTcpFrag->sequence + curTcpFrag->dataLength; // it has new data - if (SEQ_GT(newSequence, tcpReassemblyData->twoSides[sideIndex].sequence)) + if (SEQ_GT(newSequence, curSideData.sequence)) { // calculate the delta new data size - uint32_t newLength = tcpReassemblyData->twoSides[sideIndex].sequence - curTcpFrag->sequence; + uint32_t newLength = curSideData.sequence - curTcpFrag->sequence; PCPP_LOG_DEBUG("Found a fragment in the out-of-order list which its sequence is lower than expected but its payload is long enough to contain new data. " - "Calling the callback with the new data. Fragment size is " << curTcpFrag->dataLength << " on side " << sideIndex << ", new data size is " << (int)(curTcpFrag->dataLength - newLength)); + "Calling the callback with the new data. Fragment size is " << curTcpFrag->dataLength << " on side " << static_cast(sideIndex) << ", new data size is " << static_cast(curTcpFrag->dataLength - newLength)); // update current sequence with the delta new data size - tcpReassemblyData->twoSides[sideIndex].sequence += curTcpFrag->dataLength - newLength; + curSideData.sequence += curTcpFrag->dataLength - newLength; // send only the new data to the callback if (m_OnMessageReadyCallback != nullptr) @@ -549,17 +555,14 @@ void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyDat } else { - PCPP_LOG_DEBUG("Found a fragment in the out-of-order list which doesn't contain any new data, ignoring it. Fragment size is " << curTcpFrag->dataLength << " on side " << sideIndex); + PCPP_LOG_DEBUG("Found a fragment in the out-of-order list which doesn't contain any new data, ignoring it. Fragment size is " << curTcpFrag->dataLength << " on side " << static_cast(sideIndex)); } - // delete fragment from list - tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + index); - continue; } - //if got to here it means the fragment has higher sequence than current sequence, increment index and continue - index++; + //if got to here it means the fragment has higher sequence than current sequence, increment it and continue + tcpFragIter++; } // if managed to find new segment, do the search all over again @@ -569,7 +572,7 @@ void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyDat // if got here it means we're left only with fragments that have higher sequence than current sequence. This means out-of-order packets or // missing data. If we don't want to clear the frag list yet and the number of out of order fragments isn't above the configured limit, // assume it's out-of-order and return - if (!cleanWholeFragList && (m_MaxOutOfOrderFragments == 0 || tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.size() <= m_MaxOutOfOrderFragments)) + if (!cleanWholeFragList && (m_MaxOutOfOrderFragments == 0 || curSideData.tcpFragmentList.size() <= m_MaxOutOfOrderFragments)) { return; } @@ -581,36 +584,30 @@ void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyDat uint32_t closestSequence = 0xffffffff; bool closestSequenceDefined = false; - int closestSequenceFragIndex = -1; - index = 0; + auto closestSequenceFragIt = curSideData.tcpFragmentList.end(); - while (index < (int)tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.size()) + for (auto tcpFragIter = curSideData.tcpFragmentList.begin(); tcpFragIter != curSideData.tcpFragmentList.end(); tcpFragIter++) { - // extract segment at current index - TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(index); - // check if its sequence is closer than current closest sequence - if (!closestSequenceDefined || SEQ_LT(curTcpFrag->sequence, closestSequence)) + if (!closestSequenceDefined || SEQ_LT((*tcpFragIter)->sequence, closestSequence)) { - closestSequence = curTcpFrag->sequence; - closestSequenceFragIndex = index; + closestSequence = (*tcpFragIter)->sequence; + closestSequenceFragIt = tcpFragIter; closestSequenceDefined = true; } - - index++; } // this means fragment list is not empty at this stage - if (closestSequenceFragIndex > -1) + if (closestSequenceFragIt != curSideData.tcpFragmentList.end()) { // get the fragment with the closest sequence - TcpFragment* curTcpFrag = tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.at(closestSequenceFragIndex); + auto curTcpFrag = std::unique_ptr(curSideData.tcpFragmentList.getAndRemoveFromVector(closestSequenceFragIt)); // calculate number of missing bytes - uint32_t missingDataLen = curTcpFrag->sequence - tcpReassemblyData->twoSides[sideIndex].sequence; + uint32_t missingDataLen = curTcpFrag->sequence - curSideData.sequence; // update sequence - tcpReassemblyData->twoSides[sideIndex].sequence = curTcpFrag->sequence + curTcpFrag->dataLength; + curSideData.sequence = curTcpFrag->sequence + curTcpFrag->dataLength; if (curTcpFrag->data != nullptr) { // send new data to callback @@ -630,13 +627,10 @@ void TcpReassembly::checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyDat TcpStreamData streamData(&dataWithMissingDataText[0], dataWithMissingDataText.size(), missingDataLen, tcpReassemblyData->connData, curTcpFrag->timestamp); m_OnMessageReadyCallback(sideIndex, streamData, m_UserCookie); - PCPP_LOG_DEBUG("Found missing data on side " << sideIndex << ": " << missingDataLen << " byte are missing. Sending the closest fragment which is in size " << curTcpFrag->dataLength << " + missing text message which size is " << missingDataTextStr.length()); + PCPP_LOG_DEBUG("Found missing data on side " << static_cast(sideIndex) << ": " << missingDataLen << " byte are missing. Sending the closest fragment which is in size " << curTcpFrag->dataLength << " + missing text message which size is " << missingDataTextStr.length()); } } - // remove fragment from list - tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.erase(tcpReassemblyData->twoSides[sideIndex].tcpFragmentList.begin() + closestSequenceFragIndex); - PCPP_LOG_DEBUG("Calling checkOutOfOrderFragments again from the start"); // call the method again from the start to do the whole search again (both iterations). diff --git a/Tests/Pcap++Test/PcapExamples/one_tcp_stream_missing_date_with_manual_close_output.txt b/Tests/Pcap++Test/PcapExamples/one_tcp_stream_missing_date_with_manual_close_output.txt new file mode 100644 index 0000000000..bc2397c12b --- /dev/null +++ b/Tests/Pcap++Test/PcapExamples/one_tcp_stream_missing_date_with_manual_close_output.txt @@ -0,0 +1,37 @@ +POST /GetSearchMultipleSuggestions.ashx HTTP/1.1 +Host: service.zap.co.il +User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0 +Accept: application/json, text/javascript, */*; q=0.01 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/x-www-form-urlencoded +Referer: http://www.zap.co.il/ +Content-Length: 2428 +Origin: http://www.zap.co.il +DNT: 1 +Connection: keep-alive + +{"keyword":"Welcome To PcapPlusPlus Web-site PcapPlusPlus is a multiplatform C++ network sniffing and packet parsing and manipulation framework. Its meant to be lightweight, efficient and easy to use What makes PcapPlusPlus different from similar C++ wrappers for libpcap/WinPcap? Designed to be lightweight and efficient (see benchmark results) Support for DPDK fast packet processing engine which enables packet capturing and transmition in line rate using kernel bypass Support for ntops PF_RING packet capturing engine that dramatically improves the packet capture speed Support for parsing and editing of many protocols, including L7 protocols like HTTP and SSL/TLS Support for Remote Capture capabilities on Windows (using RPCAP protocol supported in WinPcap) Support for reading and writing PCAPNG files (a lot more more than currently supported in WinPcap/libpcap) Vast object-oriented filtering mechanism that makes libpcap filters a lot more user-friendly (no need to know the exact filter string to use) PcapPlusPlus is multi-platform! PcapPlusPlus is currently supported on Windows, Linux and Mac OS X. It was tested on the follwoing platforms: Windows Microsoft Visual Studio 2015 - x86 (32-bit) & x64 (64-bit) configurations MinGW32 - x86 (32-bit) configuration only MinGW-w64 - x86 (32-bit) configuration only Linux Ubuntu (12.04 LTS, 14.04 LTS, 16.04 LTS, 14.10) Fedora CentOS It should work on other Linux distributions as well Mac OS X Yosemite (10.10) El Capitan (10.11) Sierra (10.12) Supported packet capture engines PcapPlusPlus currently works with the following packet capture engines: libpcap live capture (on Linux and Mac OS X) WinPcap live capture (on Windows) ntops Vanilla PF_RING engine (on Linux) Intel DPDK engine (on Linux) WinPcap Remote live capture (on Windows) PCAP and PCAPNG file devices (reading and writing) Supported protocols The Packet++ library currently supports parsing, editing and creation of packets of the following protocols: Ethernet SLL (Linux cooked capture) Null/Loopback IPv4 IPv6 ARP VLAN MPLS PPPoE GRE TCP UDP ICMP IGMP (IGMPv1, IGMPv2 and IGMPv3 are supported) DNS DHCP HTTP headers (request & response) SSL/TLS - parsing only (no editing capabilities) Generic payload","cookies":[]}HTTP/1.1 200 OK +Cache-Control: private +Content-Type: application/json; charset=windows-1255 +Server: Microsoft-IIS/7.5 +Access-Control-Allow-Origin: * +X-AspNet-Version: 4.0.30319 +X-Powered-By: ASP.NET +Date: Thu, 06 Apr 2017 22:05:35 GMT +Content-Length: 5261 + +{"result":[{"Url":null,"ExtraDescription":null,"Order":2,"Description":"הצעות חיפוש","DisplayOrderList":-1,"Image":null,"ModelId":0},{"Url":"/search.aspx?keyword=welcome+to+pcapplusplus+web-site++pcapplusplus+is+a+multiplatform+c%2b%2b+network+sniffing+and+packet+parsing+and+manipulation+framework.+its+meant+to+be+lightweight%2c+efficient+and+easy+to+use+what+makes+pcapplusplus+different+from+similar+c%2b%2b+wrappers+for+libpcap%2fwinpcap%3f++++++designed+to+be+lightweight+and+efficient+(see+benchmark+results)+++++support+for+dpdk+fast+packet+processing+engine+which+enables+packet+capturing+and+transmition+in+line+rate+using+kernel+bypass+++++support+for+ntops+pf_ring+packet+capturing+engine+that+dramatically+improves+the+packet+capture+speed+++++support+for+parsing+and+editing+of+many+protocols%2c+including+l7+protocols+like+http+and+ssl%2ftls+++++support+for+remote+capture+capabilities+on+windows+(using+rpcap+protocol+supported+in+winpcap)+++++support+for+reading+and+writing+pcapng+files+(a+lot+more+more+than+currently+supported+in+winpcap%2flibpcap)+++++vast+object-oriented+filtering+mechanism+that+makes+libpcap+filters+a+lot+more+user-friendly+(no+need+to+know+the+exact+filter+string+to+use)++pcapplusplus+is+multi-platform!++pcapplusplus+is+currently+supported+on+windows%2c+linux+and+mac+os+x.+it+was+tested+on+the+follwoing+platforms%3a+windows++++++microsoft+visual+studio+2015+-+x86+(32-bit)+%26+x64+(64-bit)+configurations+++++mingw32+-+x86+(32-bit)+configuration+only+++++mingw-w64+-+x86+(32-bit)+configuration+only++linux++++++ubuntu+(12.04+lts%2c+14.04+lts%2c+16.04+lts%2c+14.10)+++++fedora+++++centos+++++it+should+work+on+other+linux+distributions+as+well++mac+os+x++++++yosemite+(10.10)+++++el+capitan+(10.11)+++++sierra+(10.12)++supported+packet+capture+engines++pcapplusplus+currently+works+with+the+following+packet+capture+engines%3a++++++libpcap+live+capture+(on+linux+and+mac+os+x)+++++winpcap+live+capture+(on+windows)+++++ntops+vanilla+pf_ring+engine+(on+linux)+++++intel+dpdk+engine+(on+linux)+++++winpcap+remote+live+capture+(on+windows)+++++pcap+and+pcapng+file+devices+(reading+and+writing)++supported+protocols++the+packet%2b%2b+library+currently+supports+parsing%2c+editing+and+creation+of+packets+of+the+following+protocols%3a++++++ethernet+++++sll+(linux+cooked+capture)+++++null%2floopback+++++ipv4+++++ipv6+++++arp+++++vlan+++++mpls+++++pppoe+++++gre+++++tcp+++++udp+++++icmp+++++igmp+(igmpv1%2c+igmpv2+and+igmpv3+are+supported)+++++dns+++++dhcp+++++http+headers+(request+%26+response)+++++ssl%2ftls+-+parsing+only+(no+editing+capabilities)+++++generic+payload","ExtraDescription":null,"Order":1,"Description":"welcome to pcapplusplus web-site pcapplusplus is a multiplatform c++ network sniffing and packet parsing and manipulation framework. its meant to be lightweight, efficient and easy to use what makes pcapplusplus different from similar c++ wrappers for libpcap/winpcap? designed to be lightweight and efficient (see benchmark results) support for dpdk fast packet processing engine which enables packet capturing and transmition in line rate using kernel bypass support for ntops pf_ring packet capturing engine that dramatically improves the packet capture speed support for parsing and editing of many protocols, including l7 protocols like http and ssl/tls support for remote capture capabilities on windows (using rpcap protocol supported in winpcap) support for reading and writing pcapng files (a lot more more than currently supported in winpcap/libpcap) vast object-oriented filtering mechanism that makes libpcap filters a lot more user-friendly (no need to know the exact filter string to use) pcapplusplus is multi-platform! pcapplusplus is currently supported on windows, linux and mac os x. it was tested [1360 bytes missing]Description":"","DisplayOrderList":-1,"Image":"קו הפרדה עבור טקסט שהוקלד","ModelId":0}]}POST /GetSearchMultipleSuggestions.ashx HTTP/1.1 +Host: service.zap.co.il +User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0 +Accept: application/json, text/javascript, */*; q=0.01 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/x-www-form-urlencoded +Referer: http://www.zap.co.il/ +Content-Length: 6634 +Origin: http://www.zap.co.il +DNT: 1 +Connection: keep-alive + +{"keyword":"In the field of computer network administration, pcap (packet capture) consists of an application programming interface (API) for capturing network traffic. Unix-like systems implement pcap in the libpcap library; Windows uses a port of libpcap known as WinPcap. Monitoring software may use libpcap and/or WinPcap to capture packets travelling over a network and, in newer versions, to transmit packets on a network at the link layer, as well as to get a list of network interfaces for possible use with libpcap or WinPcap. The pcap API is written in C, so other languages such as Java, .NET languages, and scripting languages generally use a wrapper; no such wrappers are provided by libpcap or WinPcap itself. C++ programs may link directly to the C API or use an object-oriented wrapper. Features libpcap and WinPcap provide the packet-capture and filtering engines of many open source and commercial network tools, including protocol analyzers (packet sniffers), network monitors, network intrusion detection systems, traffic-generators and network-testers. libpcap and WinPcap also support saving captured packets to a file, and reading files containing saved packets; applications can be written, using libpcap or WinPcap, to be able to capture network traffic and analyze it, or to read a saved capture and analyze it, using the same analysis code. A capture file saved in the format that libpcap and WinPcap use can be read by applications that understand that format, such as tcpdump, Wireshark, CA NetMaster, or Microsoft Network Monitor 3.x. The MIME type for the file format created and read by libpcap and WinPcap is application/vnd.tcpdump.pcap. The typical file extension is .pcap, although .cap and .dmp are also in common use.[4] libpcap libpcap was originally developed by the tcpdump developers in the Network Research Group at Lawrence Berkeley Laboratory. The low-level packet capture, capture file reading, and capture file writing code of tcpdump was extracted and made into a library, with which tcpdump was linked.[5] It is now developed by the same tcpdump.org group that develops tcpdump.[6] WinPcap WinPcap consists of:[7] x86 and x86-64 drivers for the Windows NT family (Windows NT 4.0, 2000, XP, Server 2003, Vista, 7, 8, and 10), which use NDIS 5.x to read packets directly from a network adapter; implementations of a lower-level library for the listed operating systems, to communicate with those drivers; a port of libpcap that uses the API offered by the low-level library implementations. Programmers at the Politecnico di Torino wrote the original code; as of 2008 CACE Technologies, a company set up by some of the WinPcap developers, develops and maintains the product. CACE Technologies was acquired by Riverbed Technology on October 21, 2010.[8] Because WinPcap uses the older NDIS 5.x APIs, it does not work on some builds of Windows 10, which have deprecated or removed those APIs in favor of the newer NDIS 6.x APIs. It also forces some limitations such as being unable to capture 802.1Q VLAN tags in Ethernet headers.","cookies":["welcome%20to%20pcapplusplus%20web-site%20%20pcapplusplus%20is%20a%20multiplatform%20c++%20network%20sniffing%20and%20packet%20parsing%20and%20manipulation%20framework.%20its%20meant%20to%20be%20lightweight%2C%20efficient%20and%20easy%20to%20use%20what%20makes%20pcapplusplus%20different%20from%20similar%20c++%20wrappers%20for%20libpcap/winpcap%3F%20%20%20%20%20%20designed%20to%20be%20lightweight%20and%20efficient%20%28see%20benchmark%20results%29%20%20%20%20%20support%20for%20dpdk%20fast%20packet%20processing%20engine%20which%20enables%20packet%20capturing%20and%20transmition%20in%20line%20rate%20using%20kernel%20bypass%20%20%20%20%20support%20for%20ntops%20pf_ring%20packet%20capturing%20engine%20that%20dramatically% \ No newline at end of file diff --git a/Tests/Pcap++Test/PcapExamples/one_tcp_stream_out_of_order_with_manual_close_output.txt b/Tests/Pcap++Test/PcapExamples/one_tcp_stream_out_of_order_with_manual_close_output.txt new file mode 100644 index 0000000000..6ba2cf91c1 --- /dev/null +++ b/Tests/Pcap++Test/PcapExamples/one_tcp_stream_out_of_order_with_manual_close_output.txt @@ -0,0 +1,37 @@ +POST /GetSearchMultipleSuggestions.ashx HTTP/1.1 +Host: service.zap.co.il +User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0 +Accept: application/json, text/javascript, */*; q=0.01 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/x-www-form-urlencoded +Referer: http://www.zap.co.il/ +Content-Length: 2428 +Origin: http://www.zap.co.il +DNT: 1 +Connection: keep-alive + +{"keyword":"Welcome To PcapPlusPlus Web-site PcapPlusPlus is a multiplatform C++ network sniffing and packet parsing and manipulation framework. Its meant to be lightweight, efficient and easy to use What makes PcapPlusPlus different from similar C++ wrappers for libpcap/WinPcap? Designed to be lightweight and efficient (see benchmark results) Support for DPDK fast packet processing engine which enables packet capturing and transmition in line rate using kernel bypass Support for ntops PF_RING packet capturing engine that dramatically improves the packet capture speed Support for parsing and editing of many protocols, including L7 protocols like HTTP and SSL/TLS Support for Remote Capture capabilities on Windows (using RPCAP protocol supported in WinPcap) Support for reading and writing PCAPNG files (a lot more more than currently supported in WinPcap/libpcap) Vast object-oriented filtering mechanism that makes libpcap filters a lot more user-friendly (no need to know the exact filter string to use) PcapPlusPlus is multi-platform! PcapPlusPlus is currently supported on Windows, Linux and Mac OS X. It was tested on the follwoing platforms: Windows Microsoft Visual Studio 2015 - x86 (32-bit) & x64 (64-bit) configurations MinGW32 - x86 (32-bit) configuration only MinGW-w64 - x86 (32-bit) configuration only Linux Ubuntu (12.04 LTS, 14.04 LTS, 16.04 LTS, 14.10) Fedora CentOS It should work on other Linux distributions as well Mac OS X Yosemite (10.10) El Capitan (10.11) Sierra (10.12) Supported packet capture engines PcapPlusPlus currently works with the following packet capture engines: libpcap live capture (on Linux and Mac OS X) WinPcap live capture (on Windows) ntops Vanilla PF_RING engine (on Linux) Intel DPDK engine (on Linux) WinPcap Remote live capture (on Windows) PCAP and PCAPNG file devices (reading and writing) Supported protocols The Packet++ library currently supports parsing, editing and creation of packets of the following protocols: Ethernet SLL (Linux cooked capture) Null/Loopback IPv4 IPv6 ARP VLAN MPLS PPPoE GRE TCP UDP ICMP IGMP (IGMPv1, IGMPv2 and IGMPv3 are supported) DNS DHCP HTTP headers (request & response) SSL/TLS - parsing only (no editing capabilities) Generic payload","cookies":[]}HTTP/1.1 200 OK +Cache-Control: private +Content-Type: application/json; charset=windows-1255 +Server: Microsoft-IIS/7.5 +Access-Control-Allow-Origin: * +X-AspNet-Version: 4.0.30319 +X-Powered-By: ASP.NET +Date: Thu, 06 Apr 2017 22:05:35 GMT +Content-Length: 5261 + +{"result":[{"Url":null,"ExtraDescription":null,"Order":2,"Description":"הצעות חיפוש","DisplayOrderList":-1,"Image":null,"ModelId":0},{"Url":"/search.aspx?keyword=welcome+to+pcapplusplus+web-site++pcapplusplus+is+a+multiplatform+c%2b%2b+network+sniffing+and+packet+parsing+and+manipulation+framework.+its+meant+to+be+lightweight%2c+efficient+and+easy+to+use+what+makes+pcapplusplus+different+from+similar+c%2b%2b+wrappers+for+libpcap%2fwinpcap%3f++++++designed+to+be+lightweight+and+efficient+(see+benchmark+results)+++++support+for+dpdk+fast+packet+processing+engine+which+enables+packet+capturing+and+transmition+in+line+rate+using+kernel+bypass+++++support+for+ntops+pf_ring+packet+capturing+engine+that+dramatically+improves+the+packet+capture+speed+++++support+for+parsing+and+editing+of+many+protocols%2c+including+l7+protocols+like+http+and+ssl%2ftls+++++support+for+remote+capture+capabilities+on+windows+(using+rpcap+protocol+supported+in+winpcap)+++++support+for+reading+and+writing+pcapng+files+(a+lot+more+more+than+currently+supported+in+winpcap%2flibpcap)+++++vast+object-oriented+filtering+mechanism+that+makes+libpcap+filters+a+lot+more+user-friendly+(no+need+to+know+the+exact+filter+string+to+use)++pcapplusplus+is+multi-platform!++pcapplusplus+is+currently+supported+on+windows%2c+linux+and+mac+os+x.+it+was+tested+on+the+follwoing+platforms%3a+windows++++++microsoft+visual+studio+2015+-+x86+(32-bit)+%26+x64+(64-bit)+configurations+++++mingw32+-+x86+(32-bit)+configuration+only+++++mingw-w64+-+x86+(32-bit)+configuration+only++linux++++++ubuntu+(12.04+lts%2c+14.04+lts%2c+16.04+lts%2c+14.10)+++++fedora+++++centos+++++it+should+work+on+other+linux+distributions+as+well++mac+os+x++++++yosemite+(10.10)+++++el+capitan+(10.11)+++++sierra+(10.12)++supported+packet+capture+engines++pcapplusplus+currently+works+with+the+following+packet+capture+engines%3a++++++libpcap+live+capture+(on+linux+and+mac+os+x)+++++winpcap+live+capture+(on+windows)+++++ntops+vanilla+pf_ring+engine+(on+linux)+++++intel+dpdk+engine+(on+linux)+++++winpcap+remote+live+capture+(on+windows)+++++pcap+and+pcapng+file+devices+(reading+and+writing)++supported+protocols++the+packet%2b%2b+library+currently+supports+parsing%2c+editing+and+creation+of+packets+of+the+following+protocols%3a++++++ethernet+++++sll+(linux+cooked+capture)+++++null%2floopback+++++ipv4+++++ipv6+++++arp+++++vlan+++++mpls+++++pppoe+++++gre+++++tcp+++++udp+++++icmp+++++igmp+(igmpv1%2c+igmpv2+and+igmpv3+are+supported)+++++dns+++++dhcp+++++http+headers+(request+%26+response)+++++ssl%2ftls+-+parsing+only+(no+editing+capabilities)+++++generic+payload","ExtraDescription":null,"Order":1,"Description":"welcome to pcapplusplus web-site pcapplusplus is a multiplatform c++ network sniffing and packet parsing and manipulation framework. its meant to be lightweight, efficient and easy to use what makes pcapplusplus different from similar c++ wrappers for libpcap/winpcap? designed to be lightweight and efficient (see benchmark results) support for dpdk fast packet processing engine which enables packet capturing and transmition in line rate using kernel bypass support for ntops pf_ring packet capturing engine that dramatically improves the packet capture speed support for parsing and editing of many protocols, including l7 protocols like http and ssl/tls support for remote capture capabilities on windows (using rpcap protocol supported in winpcap) support for reading and writing pcapng files (a lot more more than currently supported in winpcap/libpcap) vast object-oriented filtering mechanism that makes libpcap filters a lot more user-friendly (no need to know the exact filter string to use) pcapplusplus is multi-platform! pcapplusplus is currently supported on windows, linux and mac os x. it was tested on the follwoing platforms: windows microsoft visual studio 2015 - x86 (32-bit) \u0026 x64 (64-bit) configurations mingw32 - x86 (32-bit) configuration only mingw-w64 - x86 (32-bit) configuration only linux ubuntu (12.04 lts, 14.04 lts, 16.04 lts, 14.10) fedora centos it should work on other linux distributions as well mac os x yosemite (10.10) el capitan (10.11) sierra (10.12) supported packet capture engines pcapplusplus currently works with the following packet capture engines: libpcap live capture (on linux and mac os x) winpcap live capture (on windows) ntops vanilla pf_ring engine (on linux) intel dpdk engine (on linux) winpcap remote live capture (on windows) pcap and pcapng file devices (reading and writing) supported protocols the packet++ library currently supports parsing, editing and creation of packets of the following protocols: ethernet sll (linux cooked capture) null/loopback ipv4 ipv6 arp vlan mpls pppoe gre tcp udp icmp igmp (igmpv1, igmpv2 and igmpv3 are supported) dns dhcp http headers (request \u0026 response) ssl/tls - parsing only (no editing capabilities) generic payload","DisplayOrderList":-1,"Image":null,"ModelId":0},{"Url":null,"ExtraDescription":null,"Order":-1,"Description":"","DisplayOrderList":-1,"Image":"קו הפרדה עבור טקסט שהוקלד","ModelId":0}]}POST /GetSearchMultipleSuggestions.ashx HTTP/1.1 +Host: service.zap.co.il +User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:52.0) Gecko/20100101 Firefox/52.0 +Accept: application/json, text/javascript, */*; q=0.01 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/x-www-form-urlencoded +Referer: http://www.zap.co.il/ +Content-Length: 6634 +Origin: http://www.zap.co.il +DNT: 1 +Connection: keep-alive + +{"keyword":"In the field of computer network administration, pcap (packet capture) consists of an application programming interface (API) for capturing network traffic. Unix-like systems implement pcap in the libpcap library; Windows uses a port of libpcap known as WinPcap. Monitoring software may use libpcap and/or WinPcap to capture packets travelling over a network and, in newer versions, to transmit packets on a network at the link layer, as well as to get a list of network interfaces for possible use with libpcap or WinPcap. The pcap API is written in C, so other languages such as Java, .NET languages, and scripting languages generally use a wrapper; no such wrappers are provided by libpcap or WinPcap itself. C++ programs may link directly to the C API or use an object-oriented wrapper. Features libpcap and WinPcap provide the packet-capture and filtering engines of many open source and commercial network tools, including protocol analyzers (packet sniffers), network monitors, network intrusion detection systems, traffic-generators and network-testers. libpcap and WinPcap also support saving captured packets to a file, and reading files containing saved packets; applications can be written, using libpcap or WinPcap, to be able to capture network traffic and analyze it, or to read a saved capture and analyze it, using the same analysis code. A capture file saved in the format that libpcap and WinPcap use can be read by applications that understand that format, such as tcpdump, Wireshark, CA NetMaster, or Microsoft Network Monitor 3.x. The MIME type for the file format created and read by libpcap and WinPcap is application/vnd.tcpdump.pcap. The typical file extension is .pcap, although .cap and .dmp are also in common use.[4] libpcap libpcap was originally developed by the tcpdump developers in the Network Research Group at Lawrence Berkeley Laboratory. The low-level packet capture, capture file reading, and capture file writing code of tcpdump was extracted and made into a library, with which tcpdump was linked.[5] It is now developed by the same tcpdump.org group that develops tcpdump.[6] WinPcap WinPcap consists of:[7] x86 and x86-64 drivers for the Windows NT family (Windows NT 4.0, 2000, XP, Server 2003, Vista, 7, 8, and 10), which use NDIS 5.x to read packets directly from a network adapter; implementations of a lower-level library for the listed operating systems, to communicate with those drivers; a port of libpcap that uses the API offered by the low-level library implementations. Programmers at the Politecnico di Torino wrote the original code; as of 2008 CACE Technologies, a company set up by some of the WinPcap developers, develops and maintains the product. CACE Technologies was acquired by Riverbed Technology on October 21, 2010.[8] Because WinPcap uses the older NDIS 5.x APIs, it does not work on some builds of Windows 10, which have deprecated or removed those APIs in favor of the newer NDIS 6.x APIs. It also forces some limitations such as being unable to capture 802.1Q VLAN tags in Ethernet headers.","cookies":["welcome%20to%20pcapplusplus%20web-site%20%20pcapplusplus%20is%20a%20multiplatform%20c++%20network%20sniffing%20and%20packet%20parsing%20and%20manipulation%20framework.%20its%20meant%20to%20be%20lightweight%2C%20efficient%20and%20easy%20to%20use%20what%20makes%20pcapplusplus%20different%20from%20similar%20c++%20wrappers%20for%20libpcap/winpcap%3F%20%20%20%20%20%20designed%20to%20be%20lightweight%20and%20efficient%20%28see%20benchmark%20results%29%20%20%20%20%20support%20for%20dpdk%20fast%20packet%20processing%20engine%20which%20enables%20packet%20capturing%20and%20transmition%20in%20line%20rate%20using%20kernel%20bypass%20%20%20%20%20support%20for%20ntops%20pf_ring%20packet%20capturing%20engine%20that%20dramatically%20improves%20the%20packet%20capture%20speed%20%20%20%20%20support%20for%20parsing%20and%20editing%20of%20many%20protocols%2C%20including%20l7%20protocols%20like%20http%20and%20ssl/tls%20%20%20%20%20support%20for%20remote%20capture%20capabilities%20on%20windows%20%28using%20rpcap%20protocol%20supported%20in%20winpcap%29%20%20%20%20%20support%20for%20reading%20and%20writing%20pcapng%20files%20%28a%20lot%20more%20more%20than%20currently%20supported%20in%20winpcap/libpcap%29%20%20%20%20%20vast%20object-oriented%20filtering%20mechanism%20that%20makes%20libpcap%20filters%20a%20lot%20more%20user-friendly%20%28no%20need%20to%20know%20the%20exact%20filter%20string%20to%20use%29%20%20pcapplusplus%20is%20multi-platform%21%20%20pcapplusplus%20is%20currently%20supported%20on%20windows%2C%20linux%20and%20mac%20os%20x.%20it%20was%20tested%20on%20the%20follwoing%20platforms%3A%20windows%20%20%20%20%20%20microsoft%20visual%20studio%202015%20-%20x86%20%2832-bit%29%20%26%20x64%20%2864-bit%29%20configurations%20%20%20%20%20mingw32%20-%20x86%20%2832-bit%29%20configuration%20only%20%20%20%20%20mingw-w64%20-%20x86%20%2832-bit%29%20configuration%20only%20%20linux%20%20%20%20%20%20ubuntu%20%2812.04%20lts%2C%2014.04%20lts%2C%2016.04%20lts%2C%2014.10%29%20%20%20%20%20fedora%20%20%20%20%20centos%20%20%20%20%20it%20should%20work%20on%20other%20linux%20distributions%20as%20well%20%20mac%20os%20x%20%20%20%20%20%20yosemite%20%2810.10%29%20%20%20%20%20el%20capitan%20%2810.11%29%20%20%20%20%20sierra%20%2810.12%29%20%20supported%20packet%20capture%20engines%20%20pcapplusplus%20currently%20works%20with%20the%20following%20packet%20capture%20engines%3A%20%20%20%20%20%20libpcap%20live%20capture%20%28on%20linux%20and%20mac%20os%20x%29%20%20%20%20%20winpcap%20live%20capture%20%28on%20windows%29%20%20%20%20%20ntops%20vanilla%20pf_ring%20engine%20%28on%20linux%29%20%20%20%20%20intel%20dpdk%20engine%20%28on%20linux%29%20%20%20%20%20winpcap%20remote%20live%20capture%20%28on%20windows%29%20%20%20%20%20pcap%20and%20pcapng%20file%20devices%20%28reading%20and%20writing%29%20%20supported%20protocols%20%20the%20packet++%20library%20currently%20supports%20parsing%2C%20editing%20and%20creation%20of%20packets%20of%20the%20following%20protocols%3A%20%20%20%20%20%20ethernet%20%20%20%20%20sll%20%28linux%20cooked%20capture%29%20%20%20%20%20null/loopback%20%20%20%20%20ipv4%20%20%20%20%20ipv6%20%20%20%20%20arp%20%20%20%20%20vlan%20%20%20%20%20mpls%20%20%20%20%20pppoe%20%20%20%20%20gre%20%20%20%20%20tcp%20%20%20%20%20udp%20%20%20%20%20icmp%20%20%20%20%20igmp%20%28igmpv1%2C%20igmpv2%20and%20igmpv3%20are%20supported%29%20%20%20%20%20dns%20%20%20%20%20dhcp%20%20%20%20%20http%20headers%20%28request%20%26%20response%29%20%20%20%20%20ssl/tls%20-%20parsing%20only%20%28no%20editing%20capabilities%29%20%20%20%20%20generic%20payload"]} \ No newline at end of file diff --git a/Tests/Pcap++Test/TestDefinition.h b/Tests/Pcap++Test/TestDefinition.h index b61c5b9969..29dbb1298f 100644 --- a/Tests/Pcap++Test/TestDefinition.h +++ b/Tests/Pcap++Test/TestDefinition.h @@ -65,6 +65,7 @@ PTF_TEST_CASE(TestTcpReassemblySanity); PTF_TEST_CASE(TestTcpReassemblyRetran); PTF_TEST_CASE(TestTcpReassemblyMissingData); PTF_TEST_CASE(TestTcpReassemblyOutOfOrder); +PTF_TEST_CASE(TestTcpReassemblyOOOWithManualClose); PTF_TEST_CASE(TestTcpReassemblyWithFIN_RST); PTF_TEST_CASE(TestTcpReassemblyMalformedPkts); PTF_TEST_CASE(TestTcpReassemblyMultipleConns); diff --git a/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp b/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp index 224375e2f5..be663e0084 100644 --- a/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp +++ b/Tests/Pcap++Test/Tests/TcpReassemblyTests.cpp @@ -53,6 +53,7 @@ struct TcpReassemblyMultipleConnStats flowKeysList.clear(); } + pcpp::TcpReassembly *tcpReassmbly = nullptr; }; @@ -120,6 +121,40 @@ static void tcpReassemblyMsgReadyCallback(int8_t sideIndex, const pcpp::TcpStrea } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// tcpReassemblyManuallyCloseConnMsgReadyCallback() +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +static void tcpReassemblyManuallyCloseConnMsgReadyCallback(int8_t sideIndex, const pcpp::TcpStreamData& tcpData, void* userCookie) +{ + TcpReassemblyMultipleConnStats::Stats &stats = static_cast(userCookie)->stats; + + auto iter = stats.find(tcpData.getConnectionData().flowKey); + if (iter == stats.end()) + { + stats.insert(std::make_pair(tcpData.getConnectionData().flowKey, TcpReassemblyStats())); + iter = stats.find(tcpData.getConnectionData().flowKey); + } + + iter->second.totalMissingBytes += tcpData.getMissingByteCount(); + + if (sideIndex != iter->second.curSide) + { + iter->second.numOfMessagesFromSide[sideIndex]++; + iter->second.curSide = sideIndex; + } + + static_cast(userCookie)->timestamps.push_back(tcpData.getTimeStamp()); + iter->second.numOfDataPackets++; + iter->second.reassembledData += std::string((char*)tcpData.getData(), tcpData.getDataLength()); + + // if numOfDataPackets hits 10, close the connection manually + if (iter->second.numOfDataPackets >= 10) + { + static_cast(userCookie)->tcpReassmbly->closeConnection(tcpData.getConnectionData().flowKey); + } +} + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // tcpReassemblyConnectionStartCallback() // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -211,6 +246,28 @@ static bool tcpReassemblyTest(const std::vector& packetStream, } +// ~~~~~~~~~~~~~~~~~~~ +// tcpReassemblyTestManuallyCloseConnOnMsgReady() +// ~~~~~~~~~~~~~~~~~~~ + +static bool tcpReassemblyTestManuallyCloseConnOnMsgReady(const std::vector& packetStream, TcpReassemblyMultipleConnStats& results) +{ + results.tcpReassmbly = new pcpp::TcpReassembly(tcpReassemblyManuallyCloseConnMsgReadyCallback, &results, tcpReassemblyConnectionStartCallback, tcpReassemblyConnectionEndCallback); + + for (auto iter : packetStream) + { + pcpp::Packet packet(&iter); + results.tcpReassmbly->reassemblePacket(packet); + } + + results.tcpReassmbly->closeAllConnections(); + + delete results.tcpReassmbly; + + return true; +} + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // tcpReassemblyAddRetransmissions() // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -485,6 +542,78 @@ PTF_TEST_CASE(TestTcpReassemblyOutOfOrder) +PTF_TEST_CASE(TestTcpReassemblyOOOWithManualClose) +{ + // out-of-order packets + { + std::string errMsg; + std::vector packetStream; + PTF_ASSERT_TRUE(readPcapIntoPacketVec("PcapExamples/one_tcp_stream.pcap", packetStream, errMsg)); + + // swap 2 consequent packets + std::swap(packetStream[9], packetStream[10]); + + // swap 2 non-consequent packets + pcpp::RawPacket oooPacket1 = packetStream[18]; + packetStream.erase(packetStream.begin() + 18); + packetStream.insert(packetStream.begin() + 23, oooPacket1); + + // reverse order of all packets in message + for (int i = 0; i < 12; i++) + { + pcpp::RawPacket oooPacketTemp = packetStream[35]; + packetStream.erase(packetStream.begin() + 35); + packetStream.insert(packetStream.begin() + 24 + i, oooPacketTemp); + } + + TcpReassemblyMultipleConnStats tcpReassemblyResults; + tcpReassemblyTestManuallyCloseConnOnMsgReady(packetStream, tcpReassemblyResults); + + TcpReassemblyMultipleConnStats::Stats &stats = tcpReassemblyResults.stats; + PTF_ASSERT_EQUAL(stats.size(), 1); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfDataPackets, 13); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfMessagesFromSide[0], 2); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfMessagesFromSide[1], 1); + PTF_ASSERT_TRUE(stats.begin()->second.connectionsStarted); + PTF_ASSERT_FALSE(stats.begin()->second.connectionsEnded); + PTF_ASSERT_TRUE(stats.begin()->second.connectionsEndedManually); + + std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_tcp_stream_out_of_order_with_manual_close_output.txt")); + PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); + } + + // out-of-order + missing data + { + std::string errMsg; + std::vector packetStream; + PTF_ASSERT_TRUE(readPcapIntoPacketVec("PcapExamples/one_tcp_stream.pcap", packetStream, errMsg)); + + // swap 2 consequent packets + std::swap(packetStream[9], packetStream[10]); + + // remove one packet + packetStream.erase(packetStream.begin() + 13); + + TcpReassemblyMultipleConnStats tcpReassemblyResults; + tcpReassemblyTestManuallyCloseConnOnMsgReady(packetStream, tcpReassemblyResults); + TcpReassemblyMultipleConnStats::Stats &stats = tcpReassemblyResults.stats; + + PTF_ASSERT_EQUAL(stats.size(), 1); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfDataPackets, 10); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfMessagesFromSide[0], 2); + PTF_ASSERT_EQUAL(stats.begin()->second.numOfMessagesFromSide[1], 1); + PTF_ASSERT_TRUE(stats.begin()->second.connectionsStarted); + PTF_ASSERT_FALSE(stats.begin()->second.connectionsEnded); + PTF_ASSERT_TRUE(stats.begin()->second.connectionsEndedManually); + + std::string expectedReassemblyData = readFileIntoString(std::string("PcapExamples/one_tcp_stream_missing_date_with_manual_close_output.txt")); + + PTF_ASSERT_EQUAL(expectedReassemblyData, stats.begin()->second.reassembledData); + } +} // TestTcpReassemblyOOOWithManualClose + + + PTF_TEST_CASE(TestTcpReassemblyWithFIN_RST) { std::string errMsg; diff --git a/Tests/Pcap++Test/main.cpp b/Tests/Pcap++Test/main.cpp index 98c9cda74a..4c38c16223 100644 --- a/Tests/Pcap++Test/main.cpp +++ b/Tests/Pcap++Test/main.cpp @@ -273,6 +273,7 @@ int main(int argc, char* argv[]) PTF_RUN_TEST(TestTcpReassemblyRetran, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyMissingData, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyOutOfOrder, "no_network;tcp_reassembly"); + PTF_RUN_TEST(TestTcpReassemblyOOOWithManualClose, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyWithFIN_RST, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyMalformedPkts, "no_network;tcp_reassembly"); PTF_RUN_TEST(TestTcpReassemblyMultipleConns, "no_network;tcp_reassembly");