Source code for pcapkit.protocols.link.l2tp

# -*- coding: utf-8 -*-
"""layer two tunnelling protocol

:mod:`pcapkit.protocols.link.l2tp` contains
:class:`~pcapkit.protocols.link.l2tp.L2TP` only,
which implements extractor for Layer Two Tunnelling
Protocol (L2TP) [*]_, whose structure is described
as below:

+========+=======+=======================+============================================+
| Octets | Bits  | Name                  | Description                                |
+========+=======+=======================+============================================+
| 0      |     0 | ``l2tp.flags``        | Flags and Version Info                     |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     0 | ``l2tp.flags.type``   | Type (control / data)                      |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     1 | ``l2tp.flags.len``    | Length                                     |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     2 |                       | Reserved (must be zero ``\\x00``)          |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     4 | ``l2tp.flags.seq``    | Sequence                                   |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     5 |                       | Reserved (must be zero ``\\x00``)          |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     6 | ``l2tp.flags.offset`` | Offset                                     |
+--------+-------+-----------------------+--------------------------------------------+
| 0      |     7 | ``l2tp.flags.prio``   | Priority                                   |
+--------+-------+-----------------------+--------------------------------------------+
| 1      |     8 |                       | Reserved (must be zero ``\\x00``)          |
+--------+-------+-----------------------+--------------------------------------------+
| 1      |    12 | ``l2tp.ver``          | Version (``2``)                            |
+--------+-------+-----------------------+--------------------------------------------+
| 2      |    16 | ``l2tp.length``       | Length (optional by ``len``)               |
+--------+-------+-----------------------+--------------------------------------------+
| 4      |    32 | ``l2tp.tunnelid``     | Tunnel ID                                  |
+--------+-------+-----------------------+--------------------------------------------+
| 6      |    48 | ``l2tp.sessionid``    | Session ID                                 |
+--------+-------+-----------------------+--------------------------------------------+
| 8      |    64 | ``l2tp.ns``           | Sequence Number (optional by ``seq``)      |
+--------+-------+-----------------------+--------------------------------------------+
| 10     |    80 | ``l2tp.nr``           | Next Sequence Number (optional by ``seq``) |
+--------+-------+-----------------------+--------------------------------------------+
| 12     |    96 | ``l2tp.offset``       | Offset Size (optional by ``offset``)       |
+========+=======+=======================+============================================+

.. [*] https://en.wikipedia.org/wiki/Layer_2_Tunneling_Protocol

"""
from pcapkit.protocols.link.link import Link
from pcapkit.utilities.exceptions import UnsupportedCall

__all__ = ['L2TP']


[docs]class L2TP(Link): """This class implements Layer Two Tunnelling Protocol.""" ########################################################################## # Properties. ########################################################################## @property def name(self): """Name of current protocol. :rtype: Literal['Layer 2 Tunnelling Protocol'] """ return 'Layer 2 Tunnelling Protocol' @property def length(self): """Header length of current protocol. :rtype: int """ return self._info.hdr_len # pylint: disable=E1101 @property def type(self): """L2TP type. :rtype: Literal['Control', 'Data'] """ return self._info.flags.type # pylint: disable=E1101 ########################################################################## # Methods. ##########################################################################
[docs] def read(self, length=None, **kwargs): # pylint: disable=unused-argument """Read Layer Two Tunnelling Protocol. Structure of L2TP header [:rfc:`2661`]:: 0 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Tunnel ID | Session ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Ns (opt) | Nr (opt) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Offset Size (opt) | Offset pad... (opt) +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Args: length (Optional[int]): Length of packet data. Keyword Args: **kwargs: Arbitrary keyword arguments. Returns: DataType_L2TP: Parsed packet data. """ if length is None: length = len(self) _flag = self._read_binary(1) _vers = self._read_fileng(1).hex()[1] _hlen = self._read_unpack(2) if int(_flag[1]) else None _tnnl = self._read_unpack(2) _sssn = self._read_unpack(2) _nseq = self._read_unpack(2) if int(_flag[4]) else None _nrec = self._read_unpack(2) if int(_flag[4]) else None _size = self._read_unpack(2) if int(_flag[6]) else 0 l2tp = dict( flags=dict( type='Control' if int(_flag[0]) else 'Data', len=bool(int(_flag[1])), seq=bool(int(_flag[4])), offset=bool(int(_flag[6])), prio=bool(int(_flag[7])), ), ver=int(_vers, base=16), length=_hlen, tunnelid=_tnnl, sessionid=_sssn, ns=_nseq, nr=_nrec, offset=8*_size or None, ) hdr_len = _hlen or (6 + 2*(int(_flag[1]) + 2*int(_flag[4]) + int(_flag[6]))) l2tp['hdr_len'] = hdr_len + _size * 8 # if _size: # l2tp['padding'] = self._read_fileng(_size * 8) length -= l2tp['hdr_len'] l2tp['packet'] = self._read_packet(header=l2tp['hdr_len'], payload=length) return self._decode_next_layer(l2tp, length)
[docs] def make(self, **kwargs): """Make (construct) packet data. Keyword Args: **kwargs: Arbitrary keyword arguments. Returns: bytes: Constructed packet data. """ raise NotImplementedError
########################################################################## # Data models. ##########################################################################
[docs] def __length_hint__(self): """Return an estimated length for the object. :rtype: Literal[16] """ return 16
[docs] @classmethod def __index__(cls): # pylint: disable=invalid-index-returned """Numeral registry index of the protocol. Raises: UnsupportedCall: This protocol has no registry entry. """ raise UnsupportedCall(f'{cls.__name__!r} object cannot be interpreted as an integer')