Source code for pathspider.chains.tfo
"""
.. module:: pathspider.chains.tcp
:synopsis: A flow analysis chain for TCP Fast Open
This module contains the TFOChain flow analysis chain which can be used by
PATHspider's Observer for recording TCP Fast Open [RFC7413]_ details.
.. warning: The names of fields used in this chain may be changed soon to
more closely align with the field names used in other chains.
.. codeauthor:: Iain R. Learmonth <irl@fsfe.org>
.. codeauthor:: Piet De Vaere <piet@devae.re>
"""
from pathspider.chains.base import Chain
from pathspider.chains.tcp import tcp_options
from pathspider.chains.tcp import TO_FASTOPEN
from pathspider.chains.tcp import TO_EXID_FASTOPEN
from pathspider.chains.tcp import TO_EXPA
from pathspider.chains.tcp import TO_EXPB
[docs]class TFOChain(Chain):
"""
This flow analysis chain records details of TCP Fast Open use in
the flow record. It will determine whether the IANA assigned TCP option
kind or the TCP Option Experiment ID [RFC6994]_ was used to identify the
option, and whether the data sent on the SYN was acknowledged.
+------------------+--------+-----------------------------------------------------------------+
| Field Name | Type | Meaning |
+==================+========+=================================================================+
| ``tfo_synkind`` | int | Identified by ``pathspider.chains.tcp.TO_{FASTOPEN,EXPA,EXPB}`` |
+------------------+--------+-----------------------------------------------------------------+
| ``tfo_ackkind`` | int | Identified by ``pathspider.chains.tcp.TO_{FASTOPEN,EXPA,EXPB}`` |
+------------------+--------+-----------------------------------------------------------------+
| ``tfo_synclen`` | int | TFO cookie length in the forward direction |
+------------------+--------+-----------------------------------------------------------------+
| ``tfo_ackclen`` | int | TFO cookie length in the reverse direction |
+------------------+--------+-----------------------------------------------------------------+
| ``tfo_dlen`` | int | Length of SYN payload in the forward direction |
+------------------+--------+-----------------------------------------------------------------+
| ``tfo_ack`` | int | Bytes acknowledged on the SYN in the reverse direction |
+------------------+--------+-----------------------------------------------------------------+
"""
def _cookie(self, tcp):
opts = tcp_options(tcp)
if TO_FASTOPEN in opts:
return (TO_FASTOPEN, bytes(opts[TO_FASTOPEN]))
elif TO_EXPA in opts and opts[TO_EXPA][0:2] == bytearray(TO_EXID_FASTOPEN):
return (TO_EXPA, bytes(opts[TO_EXPA][2:]))
elif TO_EXPB in opts and opts[TO_EXPB][0:2] == bytearray(TO_EXID_FASTOPEN):
return (TO_EXPB, tuple(opts[TO_EXPB][2:]))
else:
return (None, None)
[docs] def new_flow(self, rec, ip):
"""
For a new flow, all fields will be initialised to ``int(0)``.
:param rec: the flow record
:type rec: dict
:param ip: the IP or IPv6 packet that triggered the creation of a new
flow record
:type ip: plt.ip or plt.ip6
:return: Always ``True``
:rtype: bool
"""
rec['tfo_synkind'] = 0
rec['tfo_ackkind'] = 0
rec['tfo_synclen'] = 0
rec['tfo_ackclen'] = 0
rec['tfo_seq'] = 0
rec['tfo_dlen'] = 0
rec['tfo_ack'] = 0
return True
[docs] def tcp(self, rec, tcp, rev): # pylint: disable=unused-argument
"""
Records TCP Fast Open details.
TCP Option Used
The TCP options will be parsed for options that use either the
IANA assigned TCP option number or one of the TCP Option Experiment
option numbers with the TCP Option Experiment ID used by TCP Fast
Open early in its standardisiation. If an option is found, the
method by which it was identified will be recorded in the
``tfo_synkind`` field for the forward direction and ``tfo_ackkind``
field for the reverse direction.
TCP Fast Open Cookie Length
The length of the cookies observed on TCP options will be recorded
in the ``tfo_synclen`` field for the forward direction and
``tfo_ackclen`` for the reverse direction. If no Fast Open option
is found, this will remain at 0 when the flow is complete.
Acknowledgement of SYN data
The length of the data on the SYN in the forward direction will be
recorded in the ``tfo_dlen`` field. The TCP sequence number for the
SYN in the forward direction will be recorded in ``tfo_seq`` field
and the TCP acknowledgement number for the SYN in the reverse
direction will be recorded in the ``tfo_ack`` field.
:param rec: the flow record
:type rec: dict
:param tcp: the TCP segment that was observed to be part of this flow
:type ip: plt.tcp
:param rev: True if the packet was in the reverse direction, False if
in the forward direction
:type rev: bool
:return: Always True
:rtype: bool
"""
# Shortcut non-SYN
if not tcp.syn_flag:
return True
# Check for TFO cookie and data on SYN
if tcp.syn_flag and not tcp.ack_flag:
(tfo_kind, tfo_cookie) = self._cookie(tcp)
if tfo_kind is not None:
rec['tfo_synkind'] = tfo_kind
rec['tfo_synclen'] = len(tfo_cookie)
rec['tfo_seq'] = tcp.seq_nbr
rec['tfo_dlen'] = len(tcp.data) - tcp.doff*4
rec['tfo_ack'] = 0
# Look for ACK of TFO data (and cookie)
elif tcp.syn_flag and tcp.ack_flag and rec['tfo_synkind']:
rec['tfo_ack'] = tcp.ack_nbr
(tfo_kind, tfo_cookie) = self._cookie(tcp)
if tfo_kind is not None:
rec['tfo_ackkind'] = tfo_kind
rec['tfo_ackclen'] = len(tfo_cookie)
# tell observer to keep going
return True