1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7L2TP (Layer 2 Tunneling Protocol) for VPNs.
8
9[RFC 2661]
10"""
11
12import struct
13
14from scapy.packet import Packet, bind_layers, bind_bottom_up
15from scapy.fields import BitEnumField, ConditionalField, FlagsField, \
16 PadField, ShortField
17from scapy.layers.inet import UDP
18from scapy.layers.ppp import PPP
19
20
21class L2TP(Packet):
22 name = "L2TP"
23 fields_desc = [
24 FlagsField("hdr", 0, 12, ['res00', 'res01', 'res02', 'res03', 'priority', 'offset', # noqa: E501
25 'res06', 'sequence', 'res08', 'res09', 'length', 'control']), # noqa: E501
26 BitEnumField("version", 2, 4, {2: 'L2TPv2'}),
27
28 ConditionalField(ShortField("len", None),
29 lambda pkt: pkt.hdr & 'control+length'),
30 ShortField("tunnel_id", 0),
31 ShortField("session_id", 0),
32 ConditionalField(ShortField("ns", 0),
33 lambda pkt: pkt.hdr & 'sequence+control'),
34 ConditionalField(ShortField("nr", 0),
35 lambda pkt: pkt.hdr & 'sequence+control'),
36 ConditionalField(
37 PadField(ShortField("offset", 0), 4, b"\x00"),
38 lambda pkt: not (pkt.hdr & 'control') and pkt.hdr & 'offset'
39 )
40 ]
41
42 def post_build(self, pkt, pay):
43 if self.len is None and self.hdr & 'control+length':
44 tmp_len = len(pkt) + len(pay)
45 pkt = pkt[:2] + struct.pack("!H", tmp_len) + pkt[4:]
46 return pkt + pay
47
48
49bind_bottom_up(UDP, L2TP, dport=1701)
50bind_bottom_up(UDP, L2TP, sport=1701)
51bind_layers(UDP, L2TP, dport=1701, sport=1701)
52bind_layers(L2TP, PPP,)