L2TPv2 - Layer Two Tunnelling Protocol Version 2

pcapkit.protocols.link.l2tpv2.protocol contains L2TPv2 only, which implements the 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:

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)

0

4

l2tp.flags.seq

Sequence

0

5

Reserved (must be zero)

0

6

l2tp.flags.offset

Offset

0

7

l2tp.flags.prio

Priority

1

8

Reserved (must be zero)

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.

class pcapkit.protocols.link.l2tpv2.protocol.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.7.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).

Changed in version 1.6.0: type of make() takes a member or an int code, resolved with the enumeration’s get; a name, or a code the one-bit field cannot carry, raises ProtocolError, rather than resolving against an enumeration inferred from the caller’s frame (#2594).

Removed in version 1.6.0: The type_default, type_namespace and type_reversed arguments of make(); resolve a name with resolve_index() first (#2594).

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 pcapkit.protocols.link.l2tp.protocol for the versions not implemented.

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. See 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.

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.

Raises:

ProtocolError – If the version nibble is not 2.

make(version=2, type=Type.Data, 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 | int) – L2TP 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 type is a name, or a member or code its one-bit field cannot carry; 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 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. Element zero is what callers treat as canonical, so both protocol='L2TP' and protocol='L2TPv2' select this class.

classmethod __index__()[source]

Numeral registry index of the protocol.

Return type:

int

Returns:

Numeral registry index of the protocol in IANA service names and port numbers: UDP port 1701, the port of UDP.l2tp as an int, which UDP.__proto__ dispatches here (The Registry Index). TransType 115 names L2TPv3 over IP instead.

Changed in version 1.6.0: Returns UDP port 1701, where it raised UnsupportedCall (#2627).

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.

Header Schemas

Removed in version 1.6.0: pcapkit.protocols.schema.link.l2tp, with no alias: the module moved here (#2534).

class pcapkit.protocols.link.l2tp.schema.L2TP(flags=NO_VALUE, length=NO_VALUE, tunnel_id=NO_VALUE, session_id=NO_VALUE, ns=NO_VALUE, nr=NO_VALUE, offset=NO_VALUE, padding=NO_VALUE, payload=NO_VALUE, trailer=NO_VALUE, *, __packet__=None, **kwargs)[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, see 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.link.l2tp.schema.FlagsType[source]

Bases: TypedDict

Flags of L2TP packet.

type: int

Type flag (T).

len: int

Length flag (L).

seq: int

Sequence flag (S).

offset: int

Offset flag (O).

prio: int

Priority flag (P).

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.

Auxiliary Functions

pcapkit.protocols.link.l2tp.schema.l2tp_payload_length(pkt)[source]

Length of the L2TP.payload field.

Parameters:

pkt (dict[str, Any]) – Packet data.

Return type:

int

Returns:

The Length field less the header, when the L flag is set; otherwise -1, so that the payload takes the rest of the datagram.

Data Models

Removed in version 1.6.0: pcapkit.protocols.data.link.l2tp, with no alias: the module moved here (#2534).

class pcapkit.protocols.link.l2tp.data.L2TP(flags, version, length, tunnelid, sessionid, ns, nr, offset)[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.link.l2tp.data.Flags(type, len, seq, offset, prio, reserved)[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