def _read_mptcp_prio(self, bits, size, kind): """Read Change Subflow Priority option. Structure of ``MP_PRIO`` [RFC 6824]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----+-+--------------+ | Kind | Length |Subtype| |B| AddrID (opt) | +---------------+---------------+-------+-----+-+--------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_REMOVE_ADDR: extracted Change Subflow Priority (``MP_PRIO``) option """ temp = self._read_unpack(1) if size else None data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(4), prio=dict( backup=bool(int(bits[3])), addr_id=temp, ), ) return data
def _read_mptcp_join(self, bits, size, kind): """Read Join Connection option. Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_JOIN: extracted Join Connection (``MP_JOIN``) option """ if self._syn and self._ack: # MP_JOIN-SYN/ACK return self._read_join_synack(bits, size, kind) if self._syn and not self._ack: # MP_JOIN-SYN return self._read_join_syn(bits, size, kind) if not self._syn and self._ack: # MP_JOIN-ACK return self._read_join_ack(bits, size, kind) temp = self._read_fileng(size) # illegal MP_JOIN occurred data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(1), connection=None, join=dict( data=bytes(chr(int(bits[:4], base=2)), encoding='utf-8') + temp, ), ) return data
def _read_mptcp_remove(self, bits, size, kind): # pylint: disable=unused-argument """Read Remove Address option. Structure of ``REMOVE_ADDR`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-------+---------------+ | Kind | Length = 3+n |Subtype|(resvd)| Address ID | ... +---------------+---------------+-------+-------+---------------+ (followed by n-1 Address IDs, if required) Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_REMOVE_ADDR: extracted Remove Address (``REMOVE_ADDR``) option """ adid = [] for _ in size: adid.append(self._read_unpack(1)) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(4), removeaddr=dict( addr_id=tuple(adid), ), ) return data
def _read_mptcp_fastclose(self, bits, size, kind): # pylint: disable=unused-argument """Read Fast Close option. Structure of ``MP_FASTCLOSE`` [RFC 6824]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----------------------+ | Kind | Length |Subtype| (reserved) | +---------------+---------------+-------+-----------------------+ | Option Receiver's Key | | (64 bits) | | | +---------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_FAIL: extracted Fast Close (``MP_FASTCLOSE``) option """ resv = self._read_fileng(1) # pylint: disable=unused-variable rkey = self._read_fileng(8) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(7), fastclose=dict(rkey=rkey, ), ) return data
def _read_mptcp_fail(self, bits, size, kind): # pylint: disable=unused-argument """Read Fallback option. Structure of ``MP_FAIL`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+----------------------+ | Kind | Length=12 |Subtype| (reserved) | +---------------+---------------+-------+----------------------+ | | | Data Sequence Number (8 octets) | | | +--------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_FAIL: extracted Fallback (``MP_FAIL``) option """ resv = self._read_fileng(1) # pylint: disable=unused-variable dsn_ = self._read_unpack(8) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(6), fail=dict(dsn=dsn_, ), ) return data
def _read_mptcp_add(self, bits, size, kind): """Read Add Address option. Structure of ``ADD_ADDR`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-------+---------------+ | Kind | Length |Subtype| IPVer | Address ID | +---------------+---------------+-------+-------+---------------+ | Address (IPv4 - 4 octets / IPv6 - 16 octets) | +-------------------------------+-------------------------------+ | Port (2 octets, optional) | +-------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_ADD_ADDR: extracted Add Address (``ADD_ADDR``) option Raises: ProtocolError: If the option is malformed. """ vers = int(bits, base=2) if vers == 4: ip_l = 4 elif vers == 6: ip_l = 16 else: raise ProtocolError('[MP_TCP ADD_ADDR] malformed option') adid = self._read_unpack(1) ipad = self._read_fileng(ip_l) pt_l = size - 1 - ip_l port = self._read_unpack(2) if pt_l else None data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(3), add_addr=dict( ip_ver=vers, addrid=adid, addr=ipaddress.ip_address(ipad), port=port, ), ) return data
def _read_mptcp_capable(self, bits, size, kind): """Read Multipath Capable option. Structure of ``MP_CAPABLE`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-------+---------------+ | Kind | Length |Subtype|Version|A|B|C|D|E|F|G|H| +---------------+---------------+-------+-------+---------------+ | Option Sender's Key (64 bits) | | | | | +---------------------------------------------------------------+ | Option Receiver's Key (64 bits) | | (if option Length == 20) | | | +---------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_CAPABLE: extracted Multipath Capable (``MP_CAPABLE``) option """ vers = int(bits, base=2) bins = self._read_binary(1) skey = self._read_unpack(8) rkey = self._read_unpack(8) if size == 17 else None data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(0), capable=dict( version=vers, flags=dict( req=bool(int(bins[0])), ext=bool(int(bins[1])), res=tuple(bool(int(bit)) for bit in bits[2:7]), hsa=bool(int(bins[7])), ), skey=skey, rkey=rkey, ), ) return data
def _read_join_synack(self, bits, size, kind): """Read Join Connection option for Responding SYN/ACK. Structure of ``MP_JOIN-SYN/ACK`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----+-+---------------+ | Kind | Length = 16 |Subtype| |B| Address ID | +---------------+---------------+-------+-----+-+---------------+ | | | Sender's Truncated HMAC (64 bits) | | | +---------------------------------------------------------------+ | Sender's Random Number (32 bits) | +---------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_JOIN_SYNACK: extracted Join Connection (``MP_JOIN-SYN/ACK``) option for Responding SYN/ACK """ adid = self._read_unpack(1) hmac = self._read_fileng(8) srno = self._read_unpack(4) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(1), connection='SYN/ACK', join=dict( synack=dict( backup=bool(int(bits[3])), addr_id=adid, hmac=hmac, rand_num=srno, ), ), ) return data
def _read_join_syn(self, bits, size, kind): """Read Join Connection option for Initial SYN. Structure of ``MP_JOIN-SYN`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----+-+---------------+ | Kind | Length = 12 |Subtype| |B| Address ID | +---------------+---------------+-------+-----+-+---------------+ | Receiver's Token (32 bits) | +---------------------------------------------------------------+ | Sender's Random Number (32 bits) | +---------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_JOIN_SYN: extracted Join Connection (``MP_JOIN-SYN``) option for Initial SYN """ adid = self._read_unpack(1) rtkn = self._read_unpack(4) srno = self._read_unpack(4) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(1), connection='SYN', join=dict( syn=dict( backup=bool(int(bits[3])), addr_id=adid, token=rtkn, rand_num=srno, ), ), ) return data
def _read_join_ack(self, bits, size, kind): # pylint: disable=unused-argument """Read Join Connection option for Third ACK. Structure of ``MP_JOIN-ACK`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----------------------+ | Kind | Length = 24 |Subtype| (reserved) | +---------------+---------------+-------+-----------------------+ | | | | | Sender's HMAC (160 bits) | | | | | +---------------------------------------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MP_JOIN_ACK: extracted Join Connection (``MP_JOIN-ACK``) option for Third ACK """ temp = self._read_fileng(20) data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(1), connection='ACK', join=dict( ack=dict( hmac=temp, ), ), ) return data
def _read_mode_mptcp(self, size, kind): """Read Multipath TCP option. Structure of ``MP-TCP`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+-----------------------+ | Kind | Length |Subtype| | +---------------+---------------+-------+ | | Subtype-specific data | | (variable length) | +---------------------------------------------------------------+ Arguments: size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_MPTCP: extracted Multipath TCP (``MP-TCP``) option """ bins = self._read_binary(1) subt = int(bins[:4], base=2) # subtype number bits = bins[4:] # 4-bit data dlen = size - 1 # length of remaining data # fetch subtype-specific data func = mptcp_opt.get(subt) if func is None: # if subtype not exist, directly read all data temp = self._read_fileng(dlen) data = dict( kind=kind, length=size, subtype=MPTCPOption.get(subt), data=bytes(chr(int(bits[:4], base=2)), encoding='utf-8') + temp, ) else: # fetch corresponding subtype data dict data = func(self, bits, dlen, kind) return data
def _read_mptcp_dss(self, bits, size, kind): """Read Data Sequence Signal (Data ACK and Data Sequence Mapping) option. Structure of ``DSS`` [:rfc:`6824`]:: 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +---------------+---------------+-------+----------------------+ | Kind | Length |Subtype| (reserved) |F|m|M|a|A| +---------------+---------------+-------+----------------------+ | | | Data ACK (4 or 8 octets, depending on flags) | | | +--------------------------------------------------------------+ | | | Data sequence number (4 or 8 octets, depending on flags) | | | +--------------------------------------------------------------+ | Subflow Sequence Number (4 octets) | +-------------------------------+------------------------------+ | Data-Level Length (2 octets) | Checksum (2 octets) | +-------------------------------+------------------------------+ Arguments: bits (str): 4-bit data (after subtype) size (int): length of option kind (Literal[30]): option kind value (Multipath TCP) Returns: DataType_TCP_Opt_DSS: extracted Data Sequence Signal (``DSS``) option """ bits = self._read_binary(1) mflg = 8 if int(bits[4]) else 4 Mflg = bool(int(bits[5])) aflg = 8 if int(bits[6]) else 4 Aflg = bool(int(bits[7])) ack_ = self._read_unpack(aflg) if Aflg else None dsn_ = self._read_unpack(mflg) if Mflg else None ssn_ = self._read_unpack(4) if Mflg else None dll_ = self._read_unpack(2) if Mflg else None chk_ = self._read_fileng(2) if Mflg else None data = dict( kind=kind, length=size + 1, subtype=MPTCPOption(2), dss=dict( flags=dict( fin=bool(int(bits[3])), dsn_len=mflg, data_pre=Mflg, ack_len=aflg, ack_pre=Aflg, ), ack=ack_, dsn=dsn_, ssn=ssn_, dl_len=dll_, checksum=chk_, ), ) return data