L2TPv2 - Layer Two Tunnelling Protocol version 2

pcapkit.protocols.link.l2tpv2 contains L2TPv2 only, which implements extractor for the Layer Two Tunnelling Protocol version 2 (L2TPv2) [*] as specified by RFC 2661 – a 16-bit tunnel ID and a 16-bit session ID, with the version nibble reading 2. It is dispatched from UDP.__proto__ at port 1701. Its 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.version

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)

Note

The parsed datagram appears under l2tp, not l2tpv2: info_name is declared on the version-agnostic base so that a consumer finds the data at the same key whichever version was on the wire. The version is reported by alias instead.

IANA protocol number 115 (L2TP) is deliberately left unbound: it references RFC 3931, i.e. L2TPv3, whose headers have a different shape, so the binding waits on an L2TPv3 class rather than this one. See pcapkit.protocols.link.l2tp.

class pcapkit.protocols.link.l2tpv2.L2TPv2(file=None, length=None, **kwargs)[source]

Bases: L2TP[L2TP, L2TP]

This class implements Layer Two Tunnelling Protocol version 2.

The protocol is dispatched from UDP.__proto__ at port 1701.

Only the RFC 2661 framing is read: read() refuses a datagram whose version nibble is not 2, so a v3 datagram arriving on port 1701 (RFC 3931 §4.1.2 shares the port) degrades to Raw instead of being reported as v2.

Added in version 1.5.0: Takes over the version-2 parsing that L2TP carried, and refuses a version nibble other than 2 (#548).

Note

IANA protocol number 115 (L2TP) is deliberately left unbound. It references RFC 3931, i.e. L2TPv3, whose session and control message headers are a different shape – so the binding waits on an L2TPv3 class rather than on this one. Binding this class there does not work (#548): over IP the v3 session header carries no version nibble at all, so this class cannot recognise that the datagram is not its own. See L2TP for the measurement.

The class subclasses Link and so reports layer == 'Link' even though it is carried inside UDP: a tunnelling protocol is placed by what it carries. See Protocol Layer Placement.

property name: Literal['Layer 2 Tunnelling Protocol version 2']

Name of current protocol.

property alias: Literal['L2TPv2']

Acronym of current protocol.

property version: Literal[2]

Version of current protocol.

Always 2: RFC 2661 fixes the version nibble, and a datagram carrying any other value is a different protocol reached through a different class. c.f. L2TP.

This is enforced rather than merely asserted – read() refuses a datagram whose nibble is not 2, so this hard-coded answer cannot disagree with info.version on the same octets.

property length: int

Header length of current protocol.

property type: Literal['control', 'data']

L2TP type.

classmethod id()[source]

Index ID of the protocol.

Return type:

tuple[Literal['L2TP'], Literal['L2TPv2']]

Returns:

Index ID of the protocol – the canonical family name first, then this version’s own label, as HTTPv1.id does. Element zero is what callers treat as canonical, so both protocol='L2TP' and protocol='L2TPv2' select this class.

read(length=None, **kwargs)[source]

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)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Parameters:
  • length (int | None) – Length of packet data.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

L2TP

Returns:

Parsed packet data.

make(version=2, type=<Type.Data: 0>, type_default=None, type_namespace=None, type_reversed=False, priority=False, reserved=0, total_length=None, length_flag=None, tunnel_id=0, session_id=0, ns=None, nr=None, offset=None, padding=None, payload=b'', trailer=b'', **kwargs)[source]

Make (construct) packet data.

Parameters:
  • version (Literal[2]) – L2TP version.

  • type (Type | IntEnum | IntEnum | str | int) – L2TP type.

  • type_default (int | None) – Default value of type.

  • type_namespace (dict[str, int] | dict[int, str] | Type[IntEnum] | Type[IntEnum] | None) – Namespace of type.

  • type_reversed (bool) – Reversed namespace of type.

  • priority (bool) – Priority flag.

  • reserved (int) – Reserved bits of the flags word, in their on-wire positions (bits 2, 3, 5 and 8-11, i.e. within 0x34F0).

  • total_length (int | None) – Length of the datagram, header included, written as given; the real header-plus-payload length when None and the Length field is present.

  • length_flag (bool | None) – Whether the Length field and its L flag are present. When None, they are present if total_length is given, or for a control message, which RFC 2661 §3.1 requires to set L.

  • tunnel_id (int) – Tunnel ID.

  • session_id (int) – Session ID.

  • ns (int | None) – Sequence number.

  • nr (int | None) – Acknowledgement number.

  • offset (int | None) – Offset size.

  • padding (bytes | None) – Offset pad, zero-filled or truncated to offset octets; all zeros when None.

  • payload (bytes | ProtocolBase | Schema) – Payload data.

  • trailer (bytes) – Octets after the datagram, outside the Length field; written as is.

  • **kwargs (Any) – Arbitrary keyword arguments.

Return type:

L2TP

Returns:

Constructed packet data.

Raises:

ProtocolError – If total_length is given with length_flag set to False, if only one of ns and nr is given, or if reserved sets a bit outside 0x34F0.

classmethod _make_data(data)[source]

Create key-value pairs from data for protocol construction.

Parameters:

data (L2TP) – protocol data

Return type:

dict[str, Any]

Returns:

Key-value pairs for protocol construction.

classmethod __index__()[source]

Numeral registry index of the protocol.

Raises:

UnsupportedCall – This protocol has no registry entry.

Note

L2TPv2 is reached through UDP port 1701, and a port is not an __index__ value anywhere in this package – every non-raising __index__ returns a TransType, EtherType or LinkType, bar the PCAP frame and PCAP-NG block instances that return their own index number, and Application.__index__ raises for exactly this reason. So there is no index to return here. L2TPv3 will be the first class in this family with one, IANA protocol number 115.

Return type:

NoReturn

Header Schemas

class pcapkit.protocols.schema.link.l2tp.L2TP(*args: _VT, **kwargs: _VT)[source]

Bases: Schema

Header schema for L2TP packet.

flags: FlagsType = <BitField flags>

Flags and version of L2TP packet.

length: int = <ConditionalField length>

Length of L2TP packet.

tunnel_id: int = <UInt16Field tunnel_id>

Tunnel ID of L2TP packet.

session_id: int = <UInt16Field session_id>

Session ID of L2TP packet.

ns: int = <ConditionalField ns>

Sequence number of L2TP packet.

nr: int = <ConditionalField nr>

Next sequence number of L2TP packet.

offset: int = <ConditionalField offset>

Offset size of L2TP packet.

padding: bytes = <ConditionalField padding>

Padding of L2TP packet.

payload: bytes = <PayloadField payload>

Payload of L2TP packet.

trailer: bytes = <PayloadField trailer>

Octets captured past the Length field, c.f. IPv4.trailer. Always empty when the L flag is clear, since the payload then takes the rest of the datagram.

Type Stubs

class pcapkit.protocols.schema.link.l2tp.FlagsType[source]

Bases: TypedDict

Flags of L2TP packet.

type: int

Type of L2TP packet.

len: int

Length of L2TP packet.

seq: int

Sequence number of L2TP packet.

offset: int

Offset size of L2TP packet.

prio: int

Priority of L2TP packet.

reserved_1: int

Reserved bits 2 and 3 of L2TP packet.

reserved_2: int

Reserved bit 5 of L2TP packet.

reserved_3: int

Reserved bits 8 to 11 of L2TP packet.

version: Literal[2]

Version of L2TP packet.

Data Models

class pcapkit.protocols.data.link.l2tp.L2TP(*args: VT, **kwargs: VT)[source]

Bases: Protocol

Data model for L2TP packet.

flags: Flags

Flags; the version nibble is version.

version: int

Version.

length: int | None

Length.

tunnelid: int

Tunnel ID.

sessionid: int

Session ID.

ns: int | None

Sequence Number.

nr: int | None

Next Sequence Number.

offset: int | None

Offset Size.

hdr_len: int

Header length.

padding: bytes | None

Offset pad (None unless flags.offset is set).

trailer: bytes

Octets captured past the Length field, present only when there are any.

class pcapkit.protocols.data.link.l2tp.Flags(*args: VT, **kwargs: VT)[source]

Bases: Data

Data model for L2TP flags.

type: Type

Type.

len: bool

Length.

seq: bool

Sequence.

offset: bool

Offset.

prio: bool

Priority.

reserved: int

Reserved bits 2, 3, 5 and 8-11 of the flags word, in their on-wire positions (i.e. masked by 0x34F0). RFC 2661 §3.1 has them “set to 0 on outgoing messages and ignored on incoming messages”; they are carried verbatim so that a rebuild reproduces the word as it arrived.

Footnotes