网络应用层之(6)L2TP协议详解

网络应用层之(6)L2TP协议


Author: Once Day Date: 2024年5月1日

一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…

漫漫长路,有人对你微笑过嘛…

全系列文档可参考专栏:通信网络技术_Once-Day的博客-CSDN博客。

参考文章:

  • L2TP技术介绍-新华三集团-H3C
  • L2TP基本原理-CSDN博客
  • L2TP基本概述_l2tp协议-CSDN博客
  • L2TP协议简介-CSDN博客
  • VPN技术:L2TP 介绍-CSDN博客
  • L2tp协议简单解析 - XuepengZ - 博客园 (cnblogs.com)
  • RFC2661 中文翻译 中文RFC RFC文档 RFC翻译 RFC中文版 (rfc2cn.com)
  • RFC3931 中文翻译 中文RFC RFC文档 RFC翻译 RFC中文版 (rfc2cn.com)
  • L2TP基本原理 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)
  • 第二层隧道协议 - 维基百科,自由的百科全书 (wikipedia.org)
  • L2TP VPN基本原理 | 曹世宏的博客 (cshihong.github.io)
  • Document Search (ietf.org)
  • GitHub - xelerance/xl2tpd: Official Xelerance fork of L2TPd
  • xl2tpd.conf详细介绍 - thammer - 博客园 (cnblogs.com)
  • 【原创】xl2tpd极简配置部署 - 晓木生 - 博客园 (cnblogs.com)

文章目录

  • 网络应用层之(6)L2TP协议
        • 1. 概述
          • 1.1 L2TP介绍
          • 1.2 L2TP和VPDN的关系
          • 1.3 应用场景
          • 1.4 RFC协议
        • 2. 报文格式
          • 2.1 L2TP协议格式
          • 2.2 L2TP报文格式
          • 2.3 L2TP控制消息
          • 2.4 L2TP报文与MTU
          • 2.5 L2TPv3协议介绍
          • 2.6 L2TPv3 over IP报文格式
          • 2.7 L2TPv3 over UDP报文格式
        • 3. 工作流程
          • 3.1 Client-Initiated场景流程
          • 3.2 NAS-Initiated场景流程
          • 3.3 L2TP Client-Initiated场景流程
        • 4. ubuntu实践
          • 4.1 内核对L2TP的支持
          • 4.2 L2TPv2使用xl2tpd来搭建LNS和LAC
          • 4.3 L2TPv2隧道交互流程
          • 4.4 L2TPv3隧道口配置(over IP)
          • 4.5 L2TPv3(over UDP)
        • 5. 总结

1. 概述
1.1 L2TP介绍

第二层隧道(L2TP)协议,即Layer 2 Tunneling Protocol,是一种常见的网络通讯协议,用于支持虚拟私人网络(VPN)的功能。它允许用户通过一个公共网络(如互联网)创建一个安全的虚拟专用通道来连接到远程网络,这种方式在远程工作和数据保密方面非常重要。

L2TP是在1999年由因特网工程任务组(IETF)公布的,它结合了微软的PPTP(Point-to-Point Tunneling Protocol)和思科系统的L2F(Layer 2 Forwarding)技术的特点

L2TP本身并不提供加密服务,但它通常与IPsec(Internet Protocol Security)协议一起使用,以确保数据包的加密和安全传输。在这种组合使用中,L2TP负责建立隧道,而IPsec负责对通过隧道传输的数据进行加密。这一结合使得L2TP/IPsec成为一种广泛采用的VPN解决方案,尤其是在需要高安全级别的企业环境中。

L2TP协议通常用于企业远程访问场景,允许远程员工安全地连接到公司的内网,访问内部资源。它也适用于个人用户,作为一种安全上网的手段,可以保护个人隐私免受监听和跟踪。

下面是L2TP典型组网图,来自L2TP基本原理 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)。

在这里插入图片描述

L2TP中常见的技术名词如下:

名词描述
PPP终端L2TP应用中,PPP终端指发起拨号,将数据封装为PPP类型的设备,如远程用户PC、企业分支网关等均可作为PPP终端。
NASNAS网络接入服务器(Network Access Server)主要由ISP维护,用于连接拨号网络,是距离PPP终端地理位置最近的接入点。
NAS用于传统的拨号网络中,ISP在NAS上部署LAC,可为远程拨号用户提供L2TP服务,和企业总部建立隧道连接。
LACL2TP访问集中器LAC是交换网络上具有PPP和L2TP协议处理能力的设备。
LAC根据PPP报文中所携带的用户名或者域名信息,和LNS建立L2TP隧道连接,将PPP协商延展到LNS。
LNSL2TP网络服务器LNS是终止PPP会话的一端,通过LNS的认证,PPP会话协商成功,远程用户可以访问企业总部的资源。
对L2TP协商,LNS是LAC的对端设备,即LAC和LNS建立了L2TP隧道。
对PPP,LNS是PPP会话的逻辑终止端点,即PPP终端和LNS建立了一条点到点的虚拟链路。
隧道隧道(Tunnel)连接,L2TP隧道在LAC和LNS之间建立,一对LAC和LNS可以建立多个L2TP隧道,一个L2TP隧道可以包含多个L2TP会话。
会话L2TP会话发生在隧道连接成功之后,L2TP会话承载在L2TP隧道之上,每个L2TP会话对应一个PPP会话,PPP会话的数据帧通过L2TP会话所在的L2TP隧道传输。
1.2 L2TP和VPDN的关系

VPDN是指利用公共网络(如ISDN或PSTN)的拨号功能接入公共网络,实现虚拟专用网,从而为企业、小型ISP、移动办公人员等提供接入服务。即,VPDN为远端用户与私有企业网之间提供了一种经济而有效的点到点连接方式。

L2TP(Layer 2 Tunneling Protocol,二层隧道协议)是VPDN(Virtual Private Dial-up Network,虚拟私有拨号网)隧道协议的一种。

VPDN采用专用的网络通信协议,在公共网络上为企业建立安全的虚拟专网,以下两种实现方式:

  • 接入服务器发起VPDN连接,NAS(Network Access Server,网络接入服务器)通过使用VPDN隧道协议,将客户的PPP连接直接连到企业的VPDN网关上,从而与VPDN网关建立隧道。这些对于用户是透明的,用户只需要登录一次就可以接入企业网络,由企业网进行用户认证和地址分配,而不占用公共地址。
  • 用户发起VPDN连接,客户端与VPDN网关建立隧道。这种方式由客户端先建立与Internet的连接,再通过专用的客户软件(如Windows系统支持的L2TP客户端)与VPDN网关建立隧道连接。用户上网的方式和地点没有限制,不需ISP介入。

VPDN隧道协议主要包括以下三种,目前使用最广泛的是L2TP:

  • PPTP(Point-to-Point Tunneling Protocol,点到点隧道协议)
  • L2F(Layer 2 Forwarding,二层转发)
  • L2TP(Layer 2 Tunneling Protocol,二层隧道协议)

L2TP与VPDN网络的关系如下:

  1. L2TP是VPDN隧道协议的一种,用于在公共网络上建立安全的虚拟专用网络。

  2. VPDN采用隧道协议在公共网络上建立企业虚拟专网,使得远程用户能够安全地接入企业内部网络。L2TP作为主流的VPDN隧道协议之一,在VPDN的实现中发挥重要作用。

  3. VPDN有两种实现方式:NAS发起和用户发起,在用户发起的方式中,客户端通常使用L2TP协议与VPDN网关建立隧道连接。

  4. 相比PPTP和L2F,L2TP目前是使用最广泛的VPDN隧道协议。

1.3 应用场景

本节图片和内容来自华为产品文档:L2TP基本概念 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)

L2TP有三种常见的应用场景,如下所示:

(1) Client-Initiated场景,移动办公用户在访问企业总部服务器之前,需要先通过L2TP VPN软件与LNS建立L2TP隧道

在这里插入图片描述

用户直接使用以太网方式介入Internet,通过手机、笔记本和PC等终端直接使用VPN软件与企业总部的LNS服务器建立L2TP隧道连接,无需再经过一个单独的NAS设备。

L2TP具有很好的用户认证功能,但没有加密功能,不够安全。为了确保用户数据不被窃取,实际应用中建议使用IPSec技术对L2TP提供加密保护,避免数据被截取或攻击。

该场景中,每个接入用户和LNS之间均建立一条隧道;每条隧道中仅承载一台L2TP会话和PPP连接

(2) NAS-Initiated场景,拨号用户在向企业内网发送业务数据以前,要先协商好传输数据所需的隧道信息

在这里插入图片描述

企业分支用户访问企业总部时,运营商会配合企业在NAS和LNS间部署L2TP隧道,借助NAS,企业分支的拨号用户可以拨号访问总部网络,实现分支企业访问总部网络的需求。

L2TP同样支持PPPoE拨号用户远程访问企业总部。拨号用户发出的PPPoE报文会被NAS处理成PPP报文以后,再通过L2TP隧道进行传输。当有多个拨号用户需要远程访问企业总部内网资源时,可以配置拨号用户之间使用不同的L2TP隧道,获取不同网段的IP地址。

该场景中,一对LAC和LNS的链接可以存在多条隧道,一条隧道中也可承载多条会话

(3) L2TP Client-Initiated场景,L2TP Client和LNS配置完L2TP以后,L2TP Client会主动向LNS发起隧道协商请求。常用于分部和总部网络之间进行组网。

在这里插入图片描述

企业分支用户访问企业总部时,会部署L2TP Client自动向LNS发起拨号,建立L2TP隧道和会话,此时不需要分支机构用户拨号来触发。对于分支机构用户来说,访问总部网络就跟访问自己所在的分支机构网络一样,完全感觉不到自己是在远程接入。

L2TP Client设备会主动向LNS发起L2TP隧道建立请求,隧道建立完成后,分支用户访问总部的流量直接通过L2TP隧道传输到对端,并且隧道对于用户是透明的

该场景中,LAC和LNS建立永久的隧道。且仅承载一条永久的L2TP会话和PPP连接

1.4 RFC协议

以下是与L2TP协议相关的RFC文档及其简要描述:

  1. RFC 2661 - Layer Two Tunneling Protocol 'L2TP'。这是L2TP协议的核心文档,详细定义了L2TP的工作原理、消息格式、隧道和会话的建立与维护,以及与PPP协议的交互。

  2. RFC 3931 - L2TP Extensions for Virtual Private Network (VPN) Service。此文档描述了L2TP的扩展,这些扩展用于支持VPN服务。

  3. RFC 4667 - L2TP Mechanism for Data-Plane Multicast。该文档提出了一种L2TP机制,用于在L2TP隧道中传输数据平面多播流量。

  4. RFC 5193 - L2TP Compliance Requirements。此RFC文档定义了L2TP的合规性要求,为实现L2TP协议的设备提供了标准化的测试和验证方法。

  5. RFC 6333 - L2TP over IPsec for BGP VPN。该文档描述了如何在BGP VPN中使用L2TP over IPsec,提供了一种通过IPsec安全隧道传输L2TP流量的方法。

  6. RFC 7193 - L2TP Extensions for Generic Routing Encapsulation (GRE) Keying。此RFC提出了L2TP的扩展,用于GRE(通用路由封装)的密钥交换。

2. 报文格式
2.1 L2TP协议格式

在L2TP的实现中,主要涉及两种类型的消息:

  • 控制消息,主要用于在L2TP连接中建立、管理和终止会话。这些消息是L2TP协议的核心组成部分,负责协调和管理隧道及其内的会话。序列号要求出现在所有控制信息中,并用于在控制通道上提供可靠的传输。
  • 数据消息,则是用来封装和传输用户数据的。一旦L2TP隧道和会话被成功建立,数据消息就会通过这些会话传输用户的实际数据。数据消息可以使用序列号来重新排列数据包并检测丢失的数据包。

在这里插入图片描述

控制消息和数据消息的联系:

  • 控制消息和数据消息都在L2TP隧道内传输,共享同一条隧道。
  • 控制消息和数据消息的格式有一些共同的字段,如会话ID、隧道ID等,用于关联隧道和会话。
  • 控制消息和数据消息协同工作,共同完成L2TP隧道的建立、维护和拆除。

控制消息和数据消息的区别:

控制消息数据消息
作用控制消息用于隧道和会话的管理,如隧道建立请求、响应,会话建立请求、响应等。数据消息用于承载用户数据,如PPP帧。
封装控制消息直接封装在L2TP头中,没有其他载荷。数据消息除了L2TP头,还封装了PPP帧等用户数据。
可靠性控制消息必须保证可靠传输,使用重传等机制。数据消息可以容忍一定的丢失,不需要完全可靠。
处理优先级控制消息的处理优先级高于数据消息。收到控制消息后要立即处理,而数据消息可以缓存后再处理。
2.2 L2TP报文格式

L2TP报文通常封装在UDP中进行传输,这样可以利用UDP的多路复用和校验功能,同时也便于NAT穿越:

  • L2TP控制消息使用UDP 1701端口,数据消息使用UDP 1701端口或动态协商的端口。
  • 整个L2TP报文,包括头部和载荷,都作为UDP的载荷。
  • UDP校验和可以关闭,以提高效率,对于控制消息,则应该总是开启。

对于L2TP的数据消息,其载荷是简化后的PPP帧:

  • PPP的帧标志、地址、控制、校验字段都被去除,因为L2TP提供了自己的帧边界和会话管理
  • PPP的协议字段保留,用于标识上层协议,如IP、IPX等。
  • PPP的信息字段作为L2TP数据消息的载荷。

控制通道和数据通道的L2TP数据包共享一个共同的报头格式,但对于控制消息,下面标记为可选的长度、Ns和Nr字段都是必选的

在这里插入图片描述

L2TP报文头部包含以下字段:

  • Type (T, 1 bit)指示该报文是控制消息(0),还是数据消息(1)

  • Length (L, 1 bit) , 指示Length字段是否存在。对于控制消息,该位总为1

  • Sequence (S, 1 bit),指示Ns和Nr字段是否存在,只有在可靠传输时才使用。控制消息的S位必须设置为1

  • Offset (O, 1 bit),指示Offset Size字段是否存在。只有在有Offset字段时才为1。对于控制消息,O位必须设置为0(零)。

  • Priority (P, 1 bit),指示该报文的优先级。如果优先级§位为1,则此数据消息在其本地排队和传输中应得到优先处理。例如,用作链路保留期的LCP回显请求通常应在该位设置为1的情况下发送。如果没有它,临时的本地拥塞间隔可能会导致对keepalive消息的干扰和不必要的链路丢失。此功能仅用于数据消息。对于所有控制消息,P位必须设置为0

  • Version (V, 4 bits),L2TP协议的版本号,当前为2,版本version=1表示L2F协议(RFC2341)

  • Reserved (7 bits),开头的16位里面,有7位必须设为0(出包必须设为0,入包需要忽略),保留供将来使用。

  • Length (16 bits, optional), 整个消息的长度,包括头部和载荷。

  • Tunnel ID (16 bits),识别该报文所属的隧道。L2TP隧道由仅具有局部意义的标识符命名。也就是说,同一条隧道的每一端将被赋予不同的隧道ID。每个邮件中的隧道ID都是预期收件人的ID,而不是发件人的ID。在创建隧道期间,隧道ID作为指定的隧道ID AVP进行选择和交换。

  • Session ID (16 bits),识别该报文所属的会话。L2TP会话由仅具有本地意义的标识符命名。也就是说,同一个会话在会话的每个结尾都会被赋予不同的会话ID。每个邮件中的会话ID都是预期收件人的会话ID,而不是发件人的会话ID。会话ID在创建会话期间被选择并交换为分配的会话ID AVP。

  • Ns (16 bits, optional),表示此数据或控制消息的序列号,从零开始,每发送一条消息递增一。

  • Nr (16 bits, optional),表示下一条控制消息中预期接收的序列号,Nr被设置为接收到的最后一条顺序消息的Ns加1。在数据消息中,Nr是保留的,如果存在(由S位指示),则在收到时必须忽略。

  • Offset Size (16 bits, optional),Offset字段的大小,指定实际负载数据与L2TP头部的偏移量(字节数),两者中间的数据是未定义的。

  • Offset pad (variable, optional),补齐字节,使载荷开始于一个4字节边界,L2TP头部的边界包括Offset pad部分。

对于数据消息,在L2TP头部后面紧跟PPP帧,但控制消息后面是没有PPP帧负载

2.3 L2TP控制消息

为了在允许互操作性的同时最大限度地提高可扩展性,L2TP中使用了统一的消息类型和正文编码方法,称为AVP**(属性-值对,Attribute-Value Pair)**。

在这里插入图片描述

相关字段描述如下:

  • 前六位是位掩码,描述AVP的一般属性。其中M和H位已使用,其余为将来的扩展保留,且保留位必须设置为0。接收到的保留位设置为1的AVP必须视为无法识别的AVP。
  • 强制(M)位控制接收不识别的AVP的实现所需的行为。如果在与特定会话关联的消息中未识别的AVP上设置了M位,则必须终止与此消息关联的会话。如果在与整个隧道相关联的消息中的未识别AVP上设置了M位,则必须终止整个隧道(以及其中的所有会话)。如果未设置M位,则必须忽略无法识别的AVP,然后必须继续处理控制消息,就像AVP不存在一样。
  • 隐藏(H)位,标识AVP属性值字段中数据的隐藏。此功能可用于避免在AVP中以明文形式传递敏感数据,如用户密码。
  • 长度(Length),此AVP中包含的字节数(包括总长度和位掩码字段)。AVP固定长度为6字节,再加上属性值(attribute value)字段的长度即为总长度。该字段本身为10位,允许单个AVP中最多有1023个字节的数据。AVP的最小长度为6,此时属性值字段不存在。
  • 供应商(Vendor)ID,IANA分配的“SMI网络管理私有企业代码”[RFC1700]值Vendor ID = 0对应于IETF采用的属性值,用于本文档中定义的所有AVP。任何希望实现自己的L2TP扩展的供应商都可以使用自己的供应商ID和私有属性值,保证它们不会与任何其他供应商的扩展冲突,也不会与未来的IETF扩展冲突。
  • 属性类型(Attribute Type),在给定供应商ID下定义的所有AVP中具有唯一解释的类型值。
  • 属性值(Attribute Value),由供应商ID和属性类型指示的实际值

L2TP控制消息主要分为以下几个类别:

类别作用
会话管理消息用于建立、维护和终止L2TP会话
隧道管理消息用于建立、维护和终止L2TP隧道
错误通知消息用于通知对端发生的错误情况
数据消息用于传输封装的数据帧

下面对每个类别进行详细解释:

(1) 会话管理消息:

  • ICRQ(Incoming-Call-Request),当LAC检测到有用户拨入电话的时候,向LNS发送ICRQ,用于向隧道对端发起新的会话请求。
  • ICRP(Incoming-Call-Reply),用于响应ICRQ消息,表示接受或拒绝新的会话请求,LNS也会在ICRP中标识L2TP会话必要的参数。
  • ICCN(Incoming-Call-Connected),用于通知隧道对端会话已成功建立。
  • CDN(Call-Disconnect-Notify),由LAC或者LNS发出,用于通知隧道对端会话已断开。

(2) 隧道管理消息:

  • SCCRQ(Start-Control-Connection-Request),控制连接发启请求。由LAC或者LNS向对端发送,用来初始化LAC和LNS之间的隧道,开始隧道的建立过程。NGFW的应用场景中,一般都是由LAC向LNS发起请求。
  • SCCRP(Start-Control-Connection-Reply),用于响应SCCRQ消息,表示接受或拒绝隧道建立请求。
  • SCCCN(Start-Control-Connection-Connected),用于通知隧道对端隧道已成功建立。
  • StopCCN(Stop-Control-Connection-Notification),用于通知隧道对端隧道已关闭。
  • HELLO,用于维护隧道的连通性,定期发送以检测隧道是否存活。LAC和LNS定时向对端发送Hello报文,如果在一段时间内未收到Hello报文的应答,隧道将被清除。

(3) 错误通知消息:

  • CDN(Call-Disconnect-Notify),用于通知隧道对端会话因错误而断开。
  • WEN(WAN-Error-Notify),用于通知隧道对端发生了特定的WAN错误。

(4) 数据消息:

  • Data,用于在L2TP会话中传输封装的数据帧(PPP报文)。
2.4 L2TP报文与MTU

远程用户拨号产生的PPP报文经过L2TP封装后,格式如下:

在这里插入图片描述

一般L2TP会是8字节或者12字节(带序列号),PPP头部是2字节,加上新IP+UDP头部开销,多出来38(42)字节。因此封装后报文的长度可能会超出接口的MTU值,而L2TP协议本身不支持报文分片功能,这时需要设备支持对IP报文的分片功能。

当L2TP报文长度超出发送接口的MTU值时,在发送接口进行报文分片处理,接收端对收到分片报文进行还原,重组为L2TP报文

2.5 L2TPv3协议介绍

L2TPv3(第3版二层隧道协议)(RFC 3931/4719)是一种常用的VPN隧道协议,主要用于在IP网络上传输二层数据帧。它是L2TPv2的改进版本,去除了对PPP的依赖,支持更多的二层协议。

一般用于如下场景:

  • 企业跨地域互联,利用L2TPv3在公网上构建二层VPN。
  • 运营商的二层VPN服务,如VPLS、VPWS。
  • 数据中心互联,DCI(Data Center Interconnect)。

一种典型场景如下(图片和内容来自: L2TP原理描述 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com):

在这里插入图片描述

企业分支局域网之间想通过IP网络进行二层数据通信,在企业出口网关处配置了L2TPv3功能:

  • 控制连接终点LCCE(L2TP Control Connection Endpoint):L2TP控制连接隧道任意一端的L2TP节点。它既可以是LAC,也可以是LNS。取决于在数据链路层还是在网络层处理隧道帧。若在数据链路层处理隧道帧,则LCCE是LAC。若在网络层处理隧道帧,则LCCE是LNS。
  • 伪线PW(Pseudowire),一条从本地AC接口到对端AC接口之间的虚拟的、直接相连的数据通道,能够完成用户的二层数据透明传输。每个L2TPv3会话对应一条PW。
  • AC接口,连接用户侧设备的接口,用于接收和发送用户侧流量。
  • PW接口,连接对端LCCE的接口,用于LCCE接收和发送L2TPv3协议报文和网络侧数据报文。

L2TPv3协议支持两种运输协议:

  • L2TPv3 over IP,使用IP协议号115,这是不兼容旧L2TPv2的场景,但是专门优化了数据包处理过程。
  • L2TPv3 over UDP,兼容旧L2TPv2场景,对Nat友好,通过Version字段区分。
2.6 L2TPv3 over IP报文格式

L2TPv3 over IP的数据报文格式如下:

在这里插入图片描述

主要字段含义:

  • 会话ID(Session ID),包含会话非零标识符的32位字段,L2TP会话由仅具有本地意义的标识符命名。也就是说,在会话的生命周期内,控制连接的每一端都将为同一逻辑会话提供不同的会话ID。当L2TP控制连接用于会话建立时,会话ID在会话创建期间被选择并交换为本地会话ID AVP。会话ID本身为所有进一步的数据包处理提供了必要的上下文,包括Cookie的存在、大小和值、L2特定子层的类型以及正在隧道传输的有效负载的类型。
  • Cookie,可选Cookie字段包含一个可变长度值(最大64位),用于检查接收到的数据消息与会话ID标识的会话的关联。必须将Cookie设置为该会话的已配置或已发信号的随机值。Cookie提供了额外级别的保证,即会话ID已将数据消息定向到正确的会话。

L2TPv3 over IP的控制报文相比于数据报文,其Session ID固定为零,如下:

在这里插入图片描述

主要字段含义:

  • T位必须设置为1,表示这是一条控制消息。
  • L和S位必须设置为1,表示存在长度字段和序列号。
  • 版本(Version)字段表示本文档中描述的L2TP控制消息头的版本,发送时必须将所有消息的此字段设置为3。
  • 长度(Length)字段以字节数表示消息的总长度,始终从控制消息头本身的开头(以T位开始)开始计算。注意,这不包括全零的Session ID长度。
  • 控制连接ID(Control Connection ID)字段包含控制连接的标识符。L2TP控制连接由仅具有本地意义的标识符命名,因此每条消息中的控制连接ID是预期收件人的ID,而不是发件人的ID。
  • Ns表示此控制消息的序列号,从零开始递增循环计数。
  • Nr表示下一条控制消息中预期接收的序列号。
2.7 L2TPv3 over UDP报文格式

L2TPv3 over UDP的数据报文格式如下:

在这里插入图片描述

主要字段含义:

  • T位必须设置为0,表示这是一条数据消息。
  • 保留字段(0位和Reserved)保留用于将来的扩展。传出消息的所有保留值必须设置为0,传入消息的所有保留值必须忽略。
  • Ver字段必须设置为3,表示L2TPv3消息。
  • 会话ID(Session ID),包含会话非零标识符的32位字段。
  • Cookie,可选Cookie字段包含一个可变长度值(最大64位)。

L2TPv3 over UDP的控制报文格式和L2TPv2报文格式类似,如下:

在这里插入图片描述

主要字段含义:

  • T位必须设置为1,表示这是一条控制消息。
  • L和S位必须设置为1,表示存在长度字段和序列号。
  • 版本(Version)字段表示本文档中描述的L2TP控制消息头的版本,发送时必须将所有消息的此字段设置为3。
  • 长度(Length)字段以字节数表示消息的总长度,始终从控制消息头本身的开头(以T位开始)开始计算。注意,这不包括全零的Session ID长度。
  • 控制连接ID(Control Connection ID)字段包含控制连接的标识符。L2TP控制连接由仅具有本地意义的标识符命名,因此每条消息中的控制连接ID是预期收件人的ID,而不是发件人的ID。
  • Ns表示此控制消息的序列号,从零开始递增循环计数。
  • Nr表示下一条控制消息中预期接收的序列号。
3. 工作流程
3.1 Client-Initiated场景流程

本节相关内容和图片来自华为产品文档:L2TP原理描述 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)

在场景下,移动办公用户在访问企业总部服务器之前,需要先通过L2TP VPN软件与LNS建立L2TP隧道。

在这里插入图片描述

主要过程如下:

  1. 移动办公用户与LNS建立L2TP隧道,LAC向对方UDP端口1701发送报文,包含SCCRQ、SCCRP、SCCCN等报文,该过程中LAC和LNS会进行双向认证(CHAP)。隧道建立后,双方都保存有隧道Tunnel ID信息,用于后续的L2TP会话建立。

  2. 移动办公用户与LNS建立L2TP会话,LAC和LNS使用ICRQ、ICRP和ICCN消息建立L2TP会话,这些消息基于前面建立的L2TP隧道中传递(L2TP头部中使用对应的Tunnel ID)。会话建立后由会话ID进行标识。

    ICCN报文中会携带移动办公用户的LCP协商信息和用户认证信息,用于后续LNS与用户建立PPP连接。

  3. 移动办公用户与LNS建立PPP连接,移动办公用户通过与LNS建立PPP连接获取LNS分配的企业内网IP地址。在该过程中,LNS会根据用户名、密码等信息对用户进行认证。

  4. 移动办公用户发送业务报文访问企业总部服务器,业务报文会封装为L2TP报文在公网上传输。

L2TP报文的封装和解封装过程如下

  1. 移动办公用户向企业总部服务器发送业务报文。业务报文通过L2TP拨号软件进行PPP封装和L2TP封装,然后按照移动办公用户PC的本地路由转发给LNS。
  2. LNS接收到报文以后,拆除报文的L2TP头和PPP头,然后按照到企业内网的路由将报文转发给企业总部服务器。
  3. 企业总部服务器收到移动办公用户的报文后,向移动办公用户返回响应报文。

在这里插入图片描述

3.2 NAS-Initiated场景流程

本节相关内容和图片来自华为产品文档:L2TP原理描述 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)

拨号用户先与NAS进行拨号建立PPPoE隧道,然后NAS与LNS完成隧道协商,最后才能访问企业内网资源。

在这里插入图片描述

主要流程如下:

  1. 拨号用户与NAS建立PPPoE连接,发出PPPoE广播报文寻找NAS接入设备。
  2. NAS与LNS建立L2TP隧道。PPPoE连接建立完成后,会触发NAS与LNS间协商L2TP隧道。NAS和LNS之间通过L2TP的控制消息、协商隧道ID和隧道认证等内容协商成功后则建立一条L2TP隧道,由隧道ID进行标识。
  3. NAS与LNS建立L2TP会话,并且将用户CHAP response、response identifier和PPP协商参数传送给LNS,以便后续LNS与用户建立PPP连接。
  4. 拨号用户与LNS建立PPP连接,获取LNS分配的企业内网IP地址,该过程中,LNS可以对拨号用户进行二次身份认证。
  5. 拨号用户发送业务报文访问企业总部,使用企业分配的内网地址访问内网服务器,报文经过NAS和LNS的加解封装后到达对端。

L2TP报文的封装和解封装过程如下

  1. 拨号用户发出的原始数据经过PPP头和PPPoE头封装后发往NAS设备。由于PPPoE是点到点连接,PPPoE连接建立以后,拨号用户本地PC不用进行路由选择,直接将封装后的报文发送给NAS设备。
  2. NAS设备使用VT(Virtual-Template)接口拆除报文的PPPoE头,再进行L2TP封装,然后按照到Internet的公网路由将封装后的数据发送出去。
  3. LNS设备接收到报文以后,拆除报文的L2TP头和PPP头,然后按照到企业内网的路由进行报文转发。
  4. 企业总部服务器收到拨号用户的报文后,向拨号用户返回响应报文。

在这里插入图片描述

3.3 L2TP Client-Initiated场景流程

本节相关内容和图片来自华为产品文档:L2TP原理描述 - NetEngine AR V300R019 配置指南-VPN(命令行) - 华为 (huawei.com)

L2TP Client和LNS配置完L2TP以后,L2TP Client会主动向LNS发起隧道协商请求,建立永久隧道,并承载唯一的一条永久会话。

在这里插入图片描述

  1. L2TP Client与LNS建立L2TP隧道。
  2. L2TP Client与LNS建立L2TP会话。
  3. L2TP Client与LNS建立PPP连接,L2TP Client通过与LNS建立PPP连接获取LNS分配的企业内网IP地址。
  4. 企业分支员工发送访问企业总部服务器的业务报文,报文经过L2TP Client和LNS的加解封装后到达对端。

L2TP报文的封装和解封装过程如下

  1. 企业分支员工向总部内网服务器发送访问请求,分支员工的PC按照本地路由将请求报文转发给L2TP Client。
  2. L2TP Client收到报文后使用VT(Virtual-Template)接口对此报文进行PPP封装和L2TP封装。报文封装完成后L2TP Client再按照到Internet的公网路由将封装好的报文发送出去。
  3. LNS设备接收到报文以后,使用VT接口拆除报文的L2TP头和PPP头,然后按照到企业内网的路由将报文转发给总部内网服务器
  4. 企业总部服务器收到分支员工的报文后,向分支员工返回响应报文

在这里插入图片描述

4. ubuntu实践
4.1 内核对L2TP的支持

在Linux内核中,L2TP的支持是通过内核模块和配置选项来实现的:

  1. CONFIG_PPPOL2TP,这个选项启用PPP over L2TP的支持,它允许在L2TP隧道上传输PPP会话。

  2. CONFIG_L2TP_DEBUGFS,这个选项启用L2TP的debugfs支持,可以通过debugfs接口查看和调试L2TP的运行状态。

  3. CONFIG_L2TP_V3_IP_TUNNEL,这个选项启用L2TPv3 IP隧道驱动,支持在IP隧道上传输L2TPv3数据。

  4. CONFIG_L2TP_ETH,这个选项启用L2TP以太网驱动,支持在L2TP上传输以太网帧。

  5. CONFIG_L2TP_IP,这个选项启用L2TP IP封装驱动,支持在IP层封装L2TP数据。

通常情况下,如果需要在Linux内核中使用L2TP,需要至少启用CONFIG_NET_L2TP、CONFIG_NET_L2TP_V3和CONFIG_PPPOL2TP这几个选项。

除了内核配置外,还需要相应的用户空间工具,如xl2tpd、iproute2等,来配置和管理L2TP连接。

可以在ubuntu设备下查看config文件来确定L2TP配置情况:

ubuntu->~:$ cat /boot/config-5.15.0-56-generic | grep L2TP
CONFIG_NETFILTER_XT_MATCH_L2TP=m
CONFIG_L2TP=m
CONFIG_L2TP_DEBUGFS=m
CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=m
CONFIG_L2TP_ETH=m
CONFIG_PPPOL2TP=m
4.2 L2TPv2使用xl2tpd来搭建LNS和LAC

xl2tpd是一个开源的L2TP服务器和客户端软件,实现了L2TPv2协议,可用于搭建L2TP VPN,支持多种认证方式,如PAP、CHAP、MS-CHAP等。

xl2tpd主要包含以下组件:

  • xl2tpd守护进程,这是xl2tpd的核心组件,负责L2TP隧道和会话的建立、维护和拆除。它监听L2TP控制消息,处理隧道和会话的状态变化。
  • xl2tpd-control工具,这是一个命令行工具,用于控制xl2tpd守护进程。它可以查询和修改L2TP隧道和会话的状态,如建立新的隧道、关闭已有隧道等。
  • pppd插件,xl2tpd通过pppd插件与PPP协议进行交互。当L2TP隧道建立后,xl2tpd会调用pppd来建立PPP会话,并通过PPP传输数据。
  • 配置文件,xl2tpd的配置文件默认为/etc/xl2tpd/xl2tpd.conf,用于定义L2TP服务器或客户端的参数,如监听地址、隧道名称、LNS地址等。

对于L2TP隧道的两端,都可以使用xl2tpd来搭建。一端作为LAC(L2TP Access Concentrator),另一端作为LNS(L2TP Network Server)。它们的配置略有不同:

  1. LAC配置,LAC是L2TP隧道的发起端。在xl2tpd.conf中,LAC需要配置lns参数,指定LNS的IP地址或域名。同时,还需要配置pppoptfile参数,指定PPP选项文件的路径。
  2. LNS配置,LNS是L2TP隧道的终端。在xl2tpd.conf中,LNS需要配置ip range参数,指定分配给LAC的IP地址范围。同时,还需要配置local参数,指定LNS的本地IP地址。

本节在两台直连的虚拟ubuntu服务器上测试,直连IP为6.6.6.1(客户端)和6.6.6.2(服务端),下面在这对接口上配置L2TP隧道

首先需要下载安装ppp和xl2tpd这两个工具,ubuntu下直接使用apt安装,也可以下载源码自行编译:

sudo apt install ppp
sudo apt install xl2tpd

(1) 首先配置服务端的LNS,写入配置文件/etc/xl2tpd/xl2tpd.conf中,如下所示:

[global]
port = 1701							; * Bind to port 1701
auth file = /etc/l2tpd/l2tp-secrets ; * Where our challenge secrets are
access control = no					; * Refuse connections without IP match
debug network = yes					; * 开启网络调试信息
debug packet = yes					; * 开启打印L2TP数据包的调试信息。
debug tunnel = yes					; * 开启隧道调试信息

[lns l2tpv2-server]
ip range = 10.10.10.1-10.10.10.6    ; * Allocate from this IP range
local ip = 10.10.10.10				; * Our local IP to use
require chap = yes					; * Require CHAP auth. by peer
require authentication = yes		; * Require peer to authenticate
name = l2tpv2-server				; * Report this as our hostname
pppoptfile = /etc/ppp/options.l2tpd.lns ; * ppp options file

继续配置服务端的ppp服务选项,其配置文件(/etc/ppp/options.l2tpd.lns,没有则需要创建)如下:

# 服务端要求客户端进行认证
auth
# 开启debug日志, 测试阶段能用于定位
debug

在服务端的ppp也需要配置秘钥文件(使用chap认证),如下:

onceday@ubuntu2:~$ sudo cat /etc/ppp/chap-secrets 
# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
onceday         *       "123456"                *

接下来启动服务端的LNS,如下:

onceday@ubuntu2:~$ sudo xl2tpd -c /etc/xl2tpd/xl2tpd.conf 
onceday@ubuntu2:~$ sudo netstat -ulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
udp        0      0 127.0.0.53:53           0.0.0.0:*                           664/systemd-resolve 
udp        0      0 192.168.0.103:68        0.0.0.0:*                           662/systemd-network 
udp        0      0 0.0.0.0:1701            0.0.0.0:*                           2176/xl2tpd         
udp6       0      0 fe80::a00:27ff:fe23:546 :::*     

如上所示,此时xl2tpd正在监听UDP的1701端口,这也是L2TPv2的控制信息协商接口

同时日志里能看到如下信息:

May  1 08:22:38 ubuntu2 xl2tpd[3751]: Not looking for kernel SAref support.
May  1 08:22:38 ubuntu2 xl2tpd[3751]: Using l2tp kernel support.
May  1 08:22:38 ubuntu2 xl2tpd[3752]: xl2tpd version xl2tpd-1.3.16 started on ubuntu2 PID:3752
May  1 08:22:38 ubuntu2 xl2tpd[3752]: Written by Mark Spencer, Copyright (C) 1998, Adtran, Inc.
May  1 08:22:38 ubuntu2 xl2tpd[3752]: Forked by Scott Balmos and David Stipp, (C) 2001
May  1 08:22:38 ubuntu2 xl2tpd[3752]: Inherited by Jeff McAdams, (C) 2002
May  1 08:22:38 ubuntu2 xl2tpd[3752]: Forked again by Xelerance (www.xelerance.com) (C) 2006-2016
May  1 08:22:38 ubuntu2 xl2tpd[3752]: Listening on IP address 0.0.0.0, port 1701

(2) 配置客户端的LAC,写入配置文件/etc/xl2tpd/xl2tpd.conf中,如下所示:

[lac l2tpv2-client]
lns = 6.6.6.2                 	; * Who is our LNS?
require authentication = no		; * Require peer to authenticate
name = l2tpv2-client			; * Report this as our hostname
pppoptfile = /etc/ppp/options.l2tpd.lns ; * ppp options file

继续配置客户端的ppp服务选项,其配置文件(/etc/ppp/options.l2tpd.lns,没有则需要创建)如下:

user "onceday"
password "123456"
# 客户端不要求服务端进行认证
noauth
# 连接终止后尝试重新打开
persist
# 禁止各种报文压缩策略
nopcomp
noaccomp
nobsdcomp
# 最大连续尝试失败次数
maxfail 5
# 开启debug日志, 测试阶段能用于定位
debug

接下来启动LAC,尝试连接LNS服务端,如下:

onceday@ubuntu1:~$ sudo xl2tpd -c /etc/xl2tpd/xl2tpd.conf 
4.3 L2TPv2隧道交互流程

在完成4.2节操作后,L2TP客户端和服务端的连接仍未建立起来,还需要手动执行命令进行连接:

# l2tpv2-client是LAC的配置文件里名称
onceday@ubuntu1:~$ sudo xl2tpd-control -d connect-lac l2tpv2-client
xl2tpd-control: command to be passed:
@/var/run/xl2tpd/xl2tpd-control-3691.out c l2tpv2-client
xl2tpd-control: command response: 
00 OK

通过在L2TP隧道口抓包,可以看到如下的交互流程(因为ppp配置有错误,所以L2TP控制协商完毕后就直接断掉了):

在这里插入图片描述

分为三个阶段,和3.1节中描述的流程是一致的,只是多出来了ZLB报文,这是用于L2TP控制报文的ACK机制,不携带数据,类似于TCP的ACK报文。

连接正常建立之后,可以在服务端和客户端分别看到ppp接口,如下:

# 客户端
onceday@ubuntu1:~$ ip addr
6: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 3
    link/ppp 
    inet 10.10.10.1 peer 10.10.10.10/32 scope global ppp0
       valid_lft forever preferred_lft forever
    inet6 fe80::34ef:6fad:5622:9fff peer fe80::d83e:f6be:9c55:39b3/128 scope link 
       valid_lft forever preferred_lft forever
# 服务端
onceday@ubuntu2:~$ ip addr
5: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 3
    link/ppp 
    inet 10.10.10.10 peer 10.10.10.1/32 scope global ppp0
       valid_lft forever preferred_lft forever
    inet6 fe80::d83e:f6be:9c55:39b3 peer fe80::34ef:6fad:5622:9fff/128 scope link 
       valid_lft forever preferred_lft forever

可以使用Ping来测试一下连通性,如果需要进一步使用,需要配置静态路由和Nat规则:

onceday@ubuntu1:~$ ping 10.10.10.10
PING 10.10.10.10 (10.10.10.10) 56(84) bytes of data.
64 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=2.32 ms
64 bytes from 10.10.10.10: icmp_seq=2 ttl=64 time=3.36 ms
64 bytes from 10.10.10.10: icmp_seq=3 ttl=64 time=0.987 ms
64 bytes from 10.10.10.10: icmp_seq=4 ttl=64 time=2.07 ms
^C
--- 10.10.10.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3199ms
rtt min/avg/max/mdev = 0.987/2.184/3.361/0.844 ms

我们再来看看在L2TP隧道中Ping报文,如下:

在这里插入图片描述

这里可以看到一点,对于L2TPv2的数据报文,没有Length字段,对于ppp则由Address和Control字段,这是因为在配置文件中禁止了地址和协议压缩(nopcomp和noaccomp)。

此外,这里协商出来的ppp接口的MTU是1500,所以在发送大包时,会遇到多次分帧的问题,如下:

onceday@ubuntu1:~$ ping 10.10.10.10 -s 1600
PING 10.10.10.10 (10.10.10.10) 1600(1628) bytes of data.
1608 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=3.23 ms

抓到的报文显示有三个IP包通过隧道:

在这里插入图片描述

对于ppp接口,Ping报文大小为1608字节(ICMP头部有8字节),需要分成两份发送:

  • 第一个inner-IP-1报文,IP头部(20字节) + ICMP部分报文(1480字节),总计1500字节(即MTU大小)。
  • 第二个inner-IP-2报文,IP头部(20字节) + ICMP剩下报文(128字节),总计148字节。

对于L2TP隧道,L2TP封装本身消耗38(IP头部+UDP头部8字节+L2TP头部6字节+PPP头部4字节)字节,因此隧道报文分成三个:

  • 第一个inner-IP-1报文,经L2TP封装后为L2TP-1,其大小为1538字节,超过以太接口MTU值(1500),则需要分成两个IP包发送:
    • 第一个outer-IP-1(L2TP-1),外层IP头部20字节 + L2TP-1部分报文(1480字节),组成1500字节IP报文。
    • 第二个outer-IP-2(L2TP-1),外层IP头部20字节 + L2TP-1剩余报文(38字节),组成58字节IP报文。
  • 第二个inner-IP-2报文,经L2TP封装后为L2TP-2,其大小为186字节,没有超过MTU值,直接对外发送,即outer-IP-3(L2TP-2)报文。

这三个outer-IP报文,加上以太层头部14字节后,报文大小(1514/72/200)正好对应抓包文件里面报文的大小。

正如2.4节里面所言,L2TP外层的负载报文也会进行IP分片发送,其代价是大于L2TP隧道内部IP分片的

4.4 L2TPv3隧道口配置(over IP)

L2TPv3配置相比于L2TPv2要简单一些,直接使用iproute2中IP工具命令就可以配置。

IP L2TP命令用于建立静态(即所谓的非托管)的L2TP以太网隧道。对于非托管隧道,不存在L2TP控制协议,因此不需要用户空间守护进程,隧道是通过在本地系统和远程对等端发出命令手动创建的

L2TPv3定义了两种报文封装格式:

  • IP封装使用专用的IP协议值承载L2TP数据,没有UDP的开销
  • UDP封装是最常见的,只有当网络路径中没有NAT设备或防火墙时,才需要使用IP封装

当创建L2TPv3以太网会话时,为该会话创建一个虚拟网络接口,然后必须像任何其他网络接口一样配置和启动该虚拟网络接口。

当数据通过该接口时,将通过L2TP隧道传送到对端。通过配置系统路由表或将接口加入网桥,L2TP接口就像一条虚拟线(伪线 pseudowire)一样连接到对端。

(1) L2TPv3 over IP隧道口配置步骤如下:

  1. 加载L2TP内核模块:

    onceday@ubuntu1:~$ sudo modprobe l2tp_netlink
    onceday@ubuntu1:~$ sudo modprobe l2tp_ip
    onceday@ubuntu1:~$ lsmod |grep l2tp
    l2tp_ip                20480  0
    l2tp_ppp               24576  0
    l2tp_netlink           24576  1 l2tp_ppp
    l2tp_core              57344  3 l2tp_ppp,l2tp_ip,l2tp_netlink
    
  2. 创建L2TP隧道,IP L2TP命令配置的静态隧道,要求远程对端也必须参数和本地配置一一对应,因此隧道ID和封装需要对应上

    onceday@ubuntu1:~$ sudo ip l2tp add tunnel tunnel_id 10 peer_tunnel_id 11 encap ip local 6.6.6.1 remote 6.6.6.2
    onceday@ubuntu1:~$ sudo ip l2tp show tunnel
    Tunnel 10, encap IP
      From 6.6.6.1 to 6.6.6.2
      Peer tunnel 11
    

    (1)创建了一个L2TP隧道,本地隧道ID为10(tunnel_id 10),对端隧道ID为11(peer_tunnel_id 11)。

    (2)隧道本地IP为10.10.10.1(local 10.10.10.1),远程对端IP为10.10.10.2(remote 10.10.10.2)

    (3)encap ip表示使用IP封装。

  3. 创建L2TP会话,这里在tunnel_id为10的隧道上创建了一个session_id为10,peer_session_id为11的L2TP会话,也会创建一个对应的虚拟接口。

    onceday@ubuntu1:~$ sudo ip l2tp add session tunnel_id 10 session_id 10 peer_session_id 11 cookie 12345678 peer_cookie 12345678
    onceday@ubuntu1:~$ sudo ip l2tp show session
    Session 10 in tunnel 10
      Peer session 11, tunnel 11
      interface name: l2tpeth0
      offset 0, peer offset 0
      cookie 12345678  peer cookie 12345678
    onceday@ubuntu1:~$ ip addr
    7: l2tpeth0: <BROADCAST,MULTICAST> mtu 1458 qdisc noop state DOWN group default qlen 1000
        link/ether e6:62:ca:e4:cb:62 brd ff:ff:ff:ff:ff:ff
    

    这里设置了cookie,该值可以是4个字节或者8个字节,用于双方进行验证。

  4. 配置虚拟网络接口,这里为l2tpeth0接口配置了IP地址10.10.10.1/24,并启用该接口。

    onceday@ubuntu1:~$ sudo ip addr add 10.10.10.1/24 dev l2tpeth0
    onceday@ubuntu1:~$ sudo ip link set l2tpeth0 up
    onceday@ubuntu1:~$ ip addr
    7: l2tpeth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1458 qdisc fq_codel state UNKNOWN group default qlen 1000
        link/ether e6:62:ca:e4:cb:62 brd ff:ff:ff:ff:ff:ff
        inet 10.10.10.1/24 scope global l2tpeth0
           valid_lft forever preferred_lft forever
        inet6 fe80::e462:caff:fee4:cb62/64 scope link 
           valid_lft forever preferred_lft forever
    
  5. 配置路由(可选),如果需要通过L2TP隧道转发特定目标网络的数据,可以配置相应的路由。

    onceday@ubuntu1:~$ sudo ip route add 192.168.2.0/24 dev l2tpeth0
    

完成以上步骤后,L2TP隧道就创建成功了,然后按照同样的顺序在对端设备上也配置一遍(隧道ID、会话ID等配置对称),如下所示:

sudo ip l2tp add tunnel tunnel_id 11 peer_tunnel_id 10 encap ip local 6.6.6.2 remote 6.6.6.1
sudo ip l2tp show tunnel
sudo ip l2tp add session tunnel_id 11 session_id 11 peer_session_id 10 cookie 12345678 peer_cookie 12345678
sudo ip l2tp show session
sudo ip addr add 10.10.10.2/24 dev l2tpeth0
sudo ip link set l2tpeth0 up

使用Ping来进行测试,如下:

onceday@ubuntu1:~$ ping 10.10.10.2
PING 10.10.10.2 (10.10.10.2) 56(84) bytes of data.
64 bytes from 10.10.10.2: icmp_seq=1 ttl=64 time=2.67 ms

在这里插入图片描述

从报文来看,L2TPv3 over IP的L2TP头部由4字节的session ID和8字节的cookie组成,后续跟着一个ether报文,该ether报文封装的mac地址是l2tpeth0接口的mac地址,就像两端是直连在一起的以太接口一样。

同理,如果不给l2tpeth0接口配置IP,而是配置成桥子接口,那就可以直接传输其他接口的原始以太网帧了,如下所示:

# ip link set l2tpeth0 up mtu 1446
# ip link add br0 type bridge
# ip link set l2tpeth0 master br0
# ip link set eth0 master br0
# ip link set br0 up
4.5 L2TPv3(over UDP)

L2TPv3 over UDP和L2TPv3 over IP的配置类似,因此细节不在赘述,相关配置命令如下:

# 客户端
sudo ip l2tp add tunnel tunnel_id 20 peer_tunnel_id 20 encap udp local 6.6.6.1 remote 6.6.6.2 udp_sport 1701 udp_dport 1701
sudo ip l2tp show tunnel
sudo ip l2tp add session tunnel_id 20 session_id 20 peer_session_id 20 cookie 12345678 peer_cookie 12345678
sudo ip l2tp show session
sudo ip addr add 10.10.20.1/24 dev l2tpeth1
sudo ip link set l2tpeth1 up
# 服务端
sudo ip l2tp add tunnel tunnel_id 20 peer_tunnel_id 20 encap udp local 6.6.6.2 remote 6.6.6.1 udp_sport 1701 udp_dport 1701
sudo ip l2tp show tunnel
sudo ip l2tp add session tunnel_id 20 session_id 20 peer_session_id 20 cookie 12345678 peer_cookie 12345678
sudo ip l2tp show session
sudo ip addr add 10.10.20.2/24 dev l2tpeth1
sudo ip link set l2tpeth0 up

如果配置时提示错误:Address already in use,这是因为端口1701已经被监听,请把后台的xl2tpd程序关闭,再尝试

相关输出信息如下:

onceday@ubuntu1:~$ sudo ip l2tp show tunnel
Tunnel 20, encap UDP
  From 6.6.6.1 to 6.6.6.2
  Peer tunnel 20
  UDP source / dest ports: 1701/1701
  UDP checksum: disabled
onceday@ubuntu1:~$ sudo ip l2tp show session
Session 20 in tunnel 20
  Peer session 20, tunnel 20
  interface name: l2tpeth1
  offset 0, peer offset 0
  cookie 12345678  peer cookie 12345678
onceday@ubuntu1:~$ ip addr
10: l2tpeth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1442 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether d6:5d:29:e6:e4:42 brd ff:ff:ff:ff:ff:ff
    inet 10.10.20.1/24 scope global l2tpeth1
       valid_lft forever preferred_lft forever
    inet6 fe80::d45d:29ff:fee6:e442/64 scope link dadfailed tentative 
       valid_lft forever preferred_lft forever

通过Ping包测试来查看连通性,抓包信息如下:

在这里插入图片描述

可以看到L2TPv3 over UDP的封装中L2TP头部是包含Flags和Reserved等字段,这与IP封装不同。

数据中包含8字节的cookie,wireshark无法识别,这需要给wireshark编写Lua插件,后续再来搞定这部分工作。

5. 总结

L2TP协议是一类常见的隧道协议,其中L2TPv2版本支持IP报文隧道传输,L2TPv3报文支持Ether IP报文传输,两者结合,功能非常强大。

对于L2TP而言,在IPsec上的应用更加广泛,适用于大多数VPN场景,虽然这些技术较老,但是其设计思想仍有借鉴意义。

L2TP文档的资料不多,也比较繁杂,只能在华为和华三等数通厂商里面找到一些专业描述,更多的资料还是只能从RFC文档获取。这与IP/TCP/UDP/ICMP等大众非常熟悉的报文协议不一样,所以本文撰写过程相当曲折,在资料获取和学习思维上都需要做出较大改变,也是间接进步了。

L2TP接触下来,一个明显的感觉是太乱,格式不固定,字段太多可选(optional),表面上兼容性高,实际只会导致程序处理复杂,而且效率不高。网络报文处理头部开销是不可避免的,尽量固定格式更重要,而且L2TPv3和L2TPv2也分离出两种封装,这意味着处理时又要多考虑 一种可能性。

L2TP协议实现上比较复杂,本文只是从初学者角度,以使用场景、报文格式、工作流程和实践四大部分来学习L2TP,这不过才刚刚开始,但希望也能给其他初学者提供一些帮助。







Alt

Once Day

也信美人终作土,不堪幽梦太匆匆......

如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!

(。◕‿◕。)感谢您的阅读与支持~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/587917.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python算法题

需求 代码 class Solution:def searchInsert(self, nums: List[int], target: int) -> int:if max(nums) >target:for i in range(len(nums)-1):if nums[i1] > target and nums[i] <target:return i1if max(nums) <target:return len(nums)if min(nums) > …

kubectl_入门_Pod控制器

Pod控制器 在k8s中&#xff0c;按照pod的创建方式可以将其分为两类 自主式pod&#xff1a;k8s直接创建出来的pod&#xff0c;这种pod删除后就没有了&#xff0c;也不会重建控制器创建的pod&#xff1a;通过控制器创建的pod&#xff0c;这种pod删除了之后还会自动重建 1. 什么…

【docker 】 push 镜像提示:denied: requested access to the resource is denied

往 Docker Registry &#xff08;私服&#xff09;push 镜像提示&#xff1a;denied: requested access to the resource is denied 镜像push 语法&#xff1a;docker push <registry-host>:<registry-port>/<repository>:<tag> docker push 192.16…

C语言 | Leetcode C语言题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; struct ListNode* rotateRight(struct ListNode* head, int k) {if (k 0 || head NULL || head->next NULL) {return head;}int n 1;struct ListNode* iter head;while (iter->next ! NULL) {iter iter->next;n;}int add n…

第12章 软件测试基础(第一部分)概念、质量保证、测试用例、测试执行过程

一、软件测试 &#xff08;一&#xff09;定义 动态验证计算机程序对有限的测试用例集是否可产生期望的结果的过程。测试计划是描述了要进行的测试活动的范围、方法、资源和进度的文档。编写测试计划目的&#xff1a;使测试工作顺利进行、使项目参与人员沟通更舒畅、使测试工…

操作系统:线程

目录 前言&#xff1a; 1.线程 1.1.初识线程 1.2.“轻量化”进程 1.3.线程与进程 2.线程控制 2.1.pthread原生线程库 2.2.线程控制的接口 2.2.1.线程创建 2.2.线程退出|线程等待|线程分离|线程取消 2.3.pthread库的原理 2.4.语言和pthread库的关系 2.5.线程局部…

redis核心数据结构——跳表项目设计与实现(跳表结构介绍,节点类设计,随机层级函数)

跳表结构介绍。跳表是redis等知名软件的核心数据结构&#xff0c;其实现的前提是有序链表&#xff0c;思想的本质是在原有一串存储数据的链表中&#xff0c;间隔地抽出一半元素作为上一级链表&#xff0c;并将抽提出的元素和原先的位置相关联&#xff0c;这样重复下去直到最上层…

Android AOSP探索之Ubantu下Toolbox的安装

文章目录 概述安装Toolbox解决运行的问题 概述 由于最近需要进军android的framework,所以需要工具的支持&#xff0c;之前听说江湖上都流传source insight,我去弄了一个破解版&#xff0c;功能确实强大&#xff0c;但是作为多年android开发的我习惯使用android studio。虽然使…

数据分析及AI技术在旅游行业的应用

引言 旅游行业是一个充满潜力和机遇的领域&#xff0c;而数据分析和人工智能&#xff08;AI&#xff09;技术的迅猛发展为这个行业带来了前所未有的机遇和挑战。本文将探讨数据分析及AI技术在旅游行业中的具体应用及其带来的影响。 数据分析在旅游行业的4种应用 在旅游行业…

【开源设计】京东慢SQL组件:sql-analysis

京东慢SQL组件&#xff1a;sql-analysis 一、背景二、源码简析三、总结 地址&#xff1a;https://github.com/jd-opensource/sql-analysis 一、背景 开发中&#xff0c;无疑会遇到慢SQL问题&#xff0c;而常见的处理思路都是等上线&#xff0c;然后由监控报警之后再去定位对应…

附录3-小程序常用事件

目录 1 点击事件 tap 2 文本框输入事件 input 3 状态改变事件 change 4 下拉刷新事件 onPullDownRefresh() 5 上拉触底事件 onReachBottom() 1 点击事件 tap 2 文本框输入事件 input 可以使用 e.detail.value 打印出当前文本框的值 我现在在文本框中依次输入12345&…

APScheduler定时器使用:django中使用apscheduler,使用mysql做存储后端

一、基本环境 python版本&#xff1a;3.8.5 APScheduler3.10.4 Django3.2.7 djangorestframework3.15.1 SQLAlchemy2.0.29 PyMySQL1.1.0二、django基本设置 2.1、新增一个app 该app用来写apscheduler相关的代码 python manage.py startapp gs_scheduler 2.2、修改配置文件s…

Typora+PicGo+阿里云OSS搭建个人博客图床(2024最新详细搭建教程)

创作者&#xff1a;Code_流苏(CSDN) 目录 一、什么是图床&#xff1f;二、准备工作三、配置PicGo四、配置Typora五、使用 很高兴你打开了这篇博客&#xff0c;如有疑问&#xff0c;欢迎评论。 更多好用的软件工具&#xff0c;请关注我&#xff0c;订阅专栏《实用软件与高效工具…

基于肤色模型的人脸识别FPGA实现,包含tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 matlab2022a的测试结果如下&#xff1a; vivado2019.2的仿真结果如下&#xff1a; 将数据导入到matlab中&#xff0c; 系统的RTL结构图如下图所示…

安装“STM32F4 Discovery Board Programming with Embedded Coder”MATLAB获取硬件支持包失败

安装“STM32F4 Discovery Board Programming with Embedded Coder”MATLAB获取硬件支持包失败 -完美解决方法 显示请续订您的软件维护服务&#xff0c;解决办法 根据知乎的文章 MATLAB获取硬件支持包失败&#xff0c;显示请续订您的软件维护服务&#xff0c;解决办法&#xff…

为家庭公网IP配置DDNS域名

文章目录 域名配置域名更新frp配置修改 在成功完成frp改造Windows笔记本实现家庭版免费内网穿透之后&#xff0c;某天我突然发现内网穿透失效了&#xff0c;一番排查之后原来是路由器对应的公网IP更换了。果然我分到的并不是固定的公网IP&#xff0c;而是会定期变化的。为了免受…

头歌:SparkSQL简单使用

第1关&#xff1a;SparkSQL初识 任务描述 本关任务&#xff1a;编写一个sparksql基础程序。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1. 什么是SparkSQL 2. 什么是SparkSession。 什么是SparkSQL Spark SQL是用来操作结构化和半结构化数据的接口。…

【深耕 Python】Data Science with Python 数据科学(18)Scikit-learn机器学习(三)

写在前面 关于数据科学环境的建立&#xff0c;可以参考我的博客&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;1&#xff09;环境搭建 往期数据科学博文一览&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;2&…

2024五一杯数学建模C题思路分享 - 煤矿深部开采冲击地压危险预测

文章目录 1 赛题选题分析 2 解题思路2.1 问题重述2.2 第一问完整思路2.2 二、三问思路更新 3 最新思路更新 1 赛题 C题 煤矿深部开采冲击地压危险预测 煤炭是中国的主要能源和重要的工业原料。然而&#xff0c;随着开采深度的增加&#xff0c;地应力增大&#xff0c;井下煤岩动…

搜索引擎的设计与实现参考论文(论文 + 源码)

【免费】搜索引擎的设计与实现.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89249705?spm1001.2014.3001.5501 搜索引擎的设计与实现 摘要&#xff1a; 我们处在一个大数据的时代&#xff0c;伴随着网络信息资源的庞大&#xff0c;人们越来越多地注重怎样才能…