Rebuild the data string from the current list of data packets For each packet, the TCP sequence number is checked. If overlapping or padding is disallowed, it will raise a SequenceNumberError exception if a respective event occurs. Args: allow_p
(self, allow_padding=True, allow_overlap=True, padding=b'\x00')
| 1730 | # TODO: Merge this in with the add_packet() logic, however I am unsure how using acknowledge numbers |
| 1731 | # works if we are only looking at one side. |
| 1732 | def reassemble(self, allow_padding=True, allow_overlap=True, padding=b'\x00'): |
| 1733 | """ |
| 1734 | Rebuild the data string from the current list of data packets |
| 1735 | For each packet, the TCP sequence number is checked. |
| 1736 | |
| 1737 | If overlapping or padding is disallowed, it will raise a |
| 1738 | SequenceNumberError exception if a respective event occurs. |
| 1739 | |
| 1740 | Args: |
| 1741 | allow_padding (bool): If data is missing and allow_padding = True |
| 1742 | (default: True), then the padding argument |
| 1743 | will be used to fill the gaps. |
| 1744 | allow_overlap (bool): If data is overlapping, the new data is |
| 1745 | used if the allow_overlap argument is True |
| 1746 | (default). Otherwise, the earliest data is |
| 1747 | kept. |
| 1748 | padding: Byte character(s) to use to fill in missing data. Used |
| 1749 | in conjunction with allow_padding (default: b'\\\\x00') |
| 1750 | """ |
| 1751 | data = b"" |
| 1752 | unacknowledged_data = [] |
| 1753 | acknowledged_data = {} |
| 1754 | for pkt in self.packets: |
| 1755 | if not pkt.sequence_number: |
| 1756 | # if there are no sequence numbers (i.e. not TCP), just rebuild |
| 1757 | # in chronological order |
| 1758 | data += pkt.data |
| 1759 | continue |
| 1760 | |
| 1761 | if pkt.data: |
| 1762 | if pkt.sequence_number in acknowledged_data: |
| 1763 | continue |
| 1764 | unacknowledged_data.append(pkt) |
| 1765 | |
| 1766 | elif pkt.tcp_flags and pkt.tcp_flags & tcp.TH_ACK: |
| 1767 | ackpkt = pkt |
| 1768 | for i, datapkt in enumerate(unacknowledged_data): |
| 1769 | if (datapkt.ack_number == ackpkt.sequence_number |
| 1770 | and ackpkt.ack_number == (datapkt.sequence_number + len(datapkt.data))): |
| 1771 | # if the seq/ack numbers align, this is the data packet |
| 1772 | # we want |
| 1773 | # TODO confirm this logic is correct |
| 1774 | acknowledged_data[datapkt.sequence_number] = datapkt.data |
| 1775 | unacknowledged_data.pop(i) |
| 1776 | break |
| 1777 | |
| 1778 | if not acknowledged_data and not unacknowledged_data: |
| 1779 | # For non-sequential protocols, just return what we have |
| 1780 | self.__data_bytes = data |
| 1781 | |
| 1782 | else: |
| 1783 | # Create a list of each segment of the complete data. Use |
| 1784 | # acknowledged data first, and then try to fill in the blanks with |
| 1785 | # unacknowledged data. |
| 1786 | segments = acknowledged_data.copy() |
| 1787 | for pkt in reversed(unacknowledged_data): |
| 1788 | if pkt.sequence_number in segments: continue |
| 1789 | segments[pkt.sequence_number] = pkt.data |
no test coverage detected