A Session that reconstructs TCP streams. NOTE: this has the same effect as wrapping a real socket.socket into StreamSocket, but for all concurrent TCP streams (can be used on pcaps or sniffed sessions). NOTE: only protocols that implement a ``tcp_reassemble`` function will be processed
| 177 | |
| 178 | |
| 179 | class TCPSession(IPSession): |
| 180 | """A Session that reconstructs TCP streams. |
| 181 | |
| 182 | NOTE: this has the same effect as wrapping a real socket.socket into StreamSocket, |
| 183 | but for all concurrent TCP streams (can be used on pcaps or sniffed sessions). |
| 184 | |
| 185 | NOTE: only protocols that implement a ``tcp_reassemble`` function will be processed |
| 186 | by this session. Other protocols will not be reconstructed. |
| 187 | |
| 188 | DEV: implement a class-function `tcp_reassemble` in your Packet class:: |
| 189 | |
| 190 | @classmethod |
| 191 | def tcp_reassemble(cls, data, metadata, session): |
| 192 | # data = the reassembled data from the same request/flow |
| 193 | # metadata = empty dictionary, that can be used to store data |
| 194 | # during TCP reassembly |
| 195 | # session = a dictionary proper to the bidirectional TCP session, |
| 196 | # that can be used to store anything |
| 197 | [...] |
| 198 | # If the packet is available, return it. Otherwise don't. |
| 199 | # Whenever you return a packet, the buffer will be discarded. |
| 200 | return pkt |
| 201 | # Otherwise, maybe store stuff in metadata, and return None, |
| 202 | # as you need additional data. |
| 203 | return None |
| 204 | |
| 205 | For more details and a real example, see: |
| 206 | https://scapy.readthedocs.io/en/latest/usage.html#how-to-use-tcpsession-to-defragment-tcp-packets |
| 207 | |
| 208 | :param app: Whether the socket is on application layer = has no TCP |
| 209 | layer. This is identical to StreamSocket so only use this if your |
| 210 | underlying source of data isn't a socket.socket. |
| 211 | """ |
| 212 | |
| 213 | def __init__(self, app=False, *args, **kwargs): |
| 214 | # type: (bool, *Any, **Any) -> None |
| 215 | super(TCPSession, self).__init__(*args, **kwargs) |
| 216 | self.app = app |
| 217 | if app: |
| 218 | self.data = StringBuffer() |
| 219 | self.metadata = {} # type: Dict[str, Any] |
| 220 | self.session = {} # type: Dict[str, Any] |
| 221 | else: |
| 222 | # The StringBuffer() is used to build a global |
| 223 | # string from fragments and their seq nulber |
| 224 | self.tcp_frags = defaultdict( |
| 225 | lambda: (StringBuffer(), {}) |
| 226 | ) # type: DefaultDict[bytes, Tuple[StringBuffer, Dict[str, Any]]] |
| 227 | self.tcp_sessions = defaultdict( |
| 228 | dict |
| 229 | ) # type: DefaultDict[bytes, Dict[str, Any]] |
| 230 | # Setup stopping dissection condition |
| 231 | from scapy.layers.inet import TCP |
| 232 | self.stop_dissection_after = TCP |
| 233 | |
| 234 | def _get_ident(self, pkt, session=False): |
| 235 | # type: (Packet, bool) -> bytes |
| 236 | underlayer = pkt["TCP"].underlayer |
no outgoing calls
no test coverage detected
searching dependent graphs…