
1. 从一条拨不上去的报错说起很多人第一次接触 L2TP 的 CALL LNS 场景都是被一个很具体的需求推着走的总部有一台 LNSL2TP Network Server分支或者出差在外的设备需要主动拨过去把自己挂进总部内网。听起来就是配个地址、填个密钥的事但真上手之后十有八九会卡在某个阶段——要么隧道建不起来要么隧道起来了但 PPP 协商不过要么能 ping 通对端却访问不了内网其他机器。我自己最早踩这个坑是在一个多分支互联的小项目里。当时总部侧是一台 Linux 网关跑 LNS分支侧用的是另一台 Linux 设备做 LACL2TP Access Concentrator要求分支主动 CALL 总部。我一开始想当然地以为两边都装个 l2tp 就完事了结果调了整整一个下午最后发现问题出在隧道和会话是两层独立的东西很多人包括当时的我把它们混为一谈导致排查方向完全跑偏。这篇内容就是围绕L2TP 配置实例——CALL LNS这个主题把 LAC 主动呼叫 LNS 的完整链路拆开讲清楚。它适合三类人一是刚接触 L2TP、需要快速跑通一个可复现实例的网络初学者二是手上有分支拨总部需求、但被各种参数绕晕的运维人员三是想搞明白 L2TP 控制消息和 PPP 协商到底怎么配合的中级工程师。我会尽量用为什么这么配的方式讲而不是甩一堆命令让你抄。需要先说明一点L2TP 本身只负责把二层帧搬过去它不负责加密也不负责地址分配。加密通常交给 IPsec地址分配交给 PPP 里的 IPCP。这个分工是理解后面所有配置的钥匙记住它很多参数你就知道该填在哪一层了。2. LAC 主动 CALL LNS 的链路到底分几层2.1 隧道与控制连接先握手再谈别的L2TP 的通信分成两个层次控制连接Control Connection和会话Session。控制连接就是我们常说的隧道它负责承载各种控制消息比如 SCCRQStart-Control-Connection-Request、SCCRPReply、SCCCNConnected。会话则是真正承载用户数据的那条通道一个隧道里可以塞多个会话。LAC 主动 CALL LNS 的过程本质上是 LAC 先发 SCCRQLNS 回 SCCRPLAC 再回 SCCCN三次握手完成后隧道就建立了。这一步只验证对端在不在、能不能通信跟用户认证、地址分配一点关系都没有。很多人隧道建起来了却上不了网就是因为把隧道当成已经通了其实真正的用户链路还没开始。这里有个容易忽略的点隧道是有 Tunnel ID 的会话有 Session ID。这两个 ID 在控制消息里来回传如果两边对不上会话就建不起来。抓包的时候你会看到 SCCRQ 里带着一个 Assigned Tunnel IDLNS 回的 SCCRP 里带着它自己的 Tunnel ID 和它期望的 Peer Tunnel ID。理解这个对应关系排查隧道通了会话不通时就有方向了。2.2 会话建立PPP 才是真正干活的那一层隧道建好之后LAC 会发 ICRQIncoming-Call-Request去请求建立一个会话LNS 回 ICRPLAC 再回 ICCN会话就建立了。但注意这时候只是通道通了用户能不能拿到地址、能不能通过认证全靠会话里跑的PPP。PPP 在 L2TP 会话里做的事情包括LCP 协商链路层参数比如 MRU、认证方式、认证PAP 或 CHAP、IPCP 协商分配 IP 地址、DNS 等。所以你在 LNS 上看到的用户拨上来其实是 PPP 层的一个 Peer。这也是为什么 LNS 侧的配置里经常要配一个 PPP 地址池——因为地址是 PPP 发的不是 L2TP 发的。我见过不少人把 L2TP 和 PPP 的配置搅在一起比如在 L2TP 配置里找分配地址的选项找不到就以为配置错了。其实地址池应该配在 PPP 那一侧L2TP 只管把帧搬过去。分清这个配置思路立刻就顺了。2.3 为什么 CALL LNS 和 LNS 等 CALL 是两套逻辑L2TP 有两种典型角色LAC 主动拨CALL LNS和 LNS 等别人拨进来。前者是客户端逻辑后者是服务端逻辑。CALL LNS 的场景里LAC 侧要配的是我要拨到哪个 LNS、用什么认证、本地用什么标识LNS 侧要配的是我接受谁的呼叫、给谁分配地址、怎么认证。这两套逻辑的配置项几乎不重叠所以如果你拿一份LNS 配置模板去配 LAC肯定跑不起来。我建议在动手之前先明确自己这台设备是 LAC 还是 LNS然后只找对应角色的配置。下面我会以 Linux 环境下常见的实现方式为例把两侧的配置都过一遍。3. 动手前必须确认的几件事3.1 内核模块和依赖别在第一步就翻车在 Linux 上跑 L2TP通常需要内核支持 l2tp_ppp 和 l2tp_netlink 模块。你可以先用modprobe l2tp_ppp试着加载如果报错说模块不存在那可能是内核编译时没开或者需要装额外的包。不同发行版的包名不一样有的叫xl2tpd有的把内核模块和用户态工具分开打包。我个人的习惯是动手前先跑三条命令确认环境modprobe l2tp_ppp lsmod | grep l2tp which xl2tpd第一条加载模块第二条看模块是否真的在第三条确认用户态守护进程在不在。三条都过了再往下走。如果xl2tpd不在先装包别急着改配置——配置改得再对工具没有也是白搭。提示有些环境里 l2tp_ppp 依赖 ppp_generic 和 pppox如果加载 l2tp_ppp 时报依赖错误先把 ppp_generic 加载上再试。3.2 网络可达性隧道之前先保证能通L2TP 的控制消息走的是 UDP 1701 端口。LAC 要能主动把 UDP 包发到 LNS 的 1701LNS 也要能把回包发回来。所以在配 L2TP 之前先用ping确认 LAC 能到 LNS 的公网/可达地址再用nc -u或者抓包确认 1701 没被中间设备拦掉。这一步听起来废话但我遇到过好几次配置全对就是不通最后发现是中间某台设备把 UDP 1701 给挡了。L2TP 不像 TCP 那样有明确的连接状态UDP 被挡的时候LAC 侧只会看到发了 SCCRQ 没回应很容易误判成配置问题。所以先确认可达性再怀疑配置这个顺序能省你很多时间。3.3 认证方式的选择PAP 还是 CHAPPPP 认证有 PAP 和 CHAP 两种。PAP 是明文传用户名密码CHAP 是挑战-响应不传明文。在 L2TP 场景里如果外层没有 IPsec 保护PAP 的密码在网络上是裸奔的所以能用 CHAP 就用 CHAP。但 CHAP 对配置的要求更严一点比如 LNS 侧要有对应的用户密码且不能是空密码。我的建议是测试阶段可以先用 PAP 快速跑通确认链路没问题后再换成 CHAP。这样能把链路问题和认证问题分开排查。如果一上来就用 CHAP认证失败的时候你分不清是链路没通还是密码不对。4. LNS 侧配置把接电话的姿势摆好4.1 xl2tpd 的核心配置项逐个拆LNS 侧的 xl2tpd 配置核心是告诉它监听谁、接受谁、认证交给谁。一个典型的配置片段长这样[global] port 1701 auth file /etc/ppp/chap-secrets [lns default] ip range 192.168.100.10-192.168.100.100 local ip 192.168.100.1 require authentication yes name lns-server ppp debug yes pppoptfile /etc/ppp/options.l2tpd.lns这里每一项都有它的作用。ip range是分配给拨入用户的地址池local ip是 LNS 在这个 PPP 链路里的本地地址require authentication强制认证name是 LNS 的标识pppoptfile指向 PPP 的详细参数文件。我特别想强调local ip和ip range的关系它们必须在同一个网段里因为 PPP 链路两端要能直接通信。如果你把 local ip 设成 192.168.100.1地址池却写成 10.0.0.x那用户拨上来之后根本 ping 不通 LNS因为不在一个网段。这个错误我见过不止一次而且报错信息很不直观容易让人以为是认证问题。4.2 PPP 选项文件里藏着的关键参数pppoptfile指向的文件才是真正决定 PPP 行为的地方。一个能用的 LNS 侧 PPP 配置大概是这样refuse-pap require-mschap-v2 ms-dns 8.8.8.8 ms-dns 8.8.4.4 proxyarp mtu 1400 mru 1400refuse-pap和require-mschap-v2一起用意思是拒绝 PAP要求 MSCHAPv2。ms-dns是推给客户端的 DNS。proxyarp让 LNS 在以太网侧代答 ARP这样内网其他机器才能找到拨入的用户——这个参数很多人会漏漏了之后用户能 ping 通 LNS 但访问不了内网其他机器。mtu和mru设成 1400 是个经验值。L2TP 本身有开销如果外层还套了 IPsec开销更大1500 的默认值容易导致大包被分片甚至丢弃。设小一点虽然牺牲一点效率但能避免很多小包能通、大包不通的诡异问题。这个坑我在实际项目里踩过当时网页能打开但图片加载不出来查了半天才发现是 MTU 问题。4.3 认证文件怎么写才不出错/etc/ppp/chap-secrets的格式是用户名 服务名 密码 IP 地址。服务名一般写*IP 地址写*表示任意来源。比如branch01 * branchpass *这行的意思是用户 branch01任意服务密码 branchpass允许从任意地址拨入。注意这里的密码是明文存的所以文件权限要收紧一般设成 600属主是 root。注意CHAP 的密码在 chap-secrets 里是明文但传输过程中是挑战-响应不会明文过网。文件权限一定要管好否则等于把密码写在公告板上。5. LAC 侧配置主动拨号的正确打开方式5.1 定义我要拨到哪lac 段配置LAC 侧的配置重点是定义一个 lac 段告诉它 LNS 的地址和本地的标识。典型配置[lac to-lns] lns 203.0.113.10 name branch01 pppoptfile /etc/ppp/options.l2tpd.lac redial yes redial timeout 10 max redials 5lns是 LNS 的可达地址name是本地标识会作为隧道名发给 LNS。redial系列参数控制断线重拨这在分支场景里很实用——链路抖一下自动重连不用人工干预。这里有个细节name要和 LNS 侧 chap-secrets 里的用户名对应上否则认证会失败。我建议两侧用同一个名字减少对不上的概率。另外redial timeout别设太短太短会在 LNS 还没准备好时疯狂重拨反而加重负担10 秒是个比较稳妥的值。5.2 LAC 侧 PPP 选项认证和路由LAC 侧的 PPP 配置和 LNS 侧不太一样重点是我怎么认证、要不要默认路由noauth user branch01 password branchpass mtu 1400 mru 1400 defaultroute persistnoauth表示不要求对端认证自己因为 LAC 是拨号方通常只做单向认证。user和password是拨号凭据。defaultroute会在拨通后加一条默认路由指向 PPP 接口这样分支的所有流量都走隧道。persist让 PPP 断开后自动重连。要不要加defaultroute取决于你的需求。如果只是访问总部内网某几个网段应该用具体的路由而不是默认路由否则分支本地上网流量也会被吸进隧道既浪费带宽又可能出问题。这个选择要根据实际拓扑来定没有标准答案。5.3 发起呼叫命令行还是自动配置写好后可以用xl2tpd-control手动发起呼叫也可以让 xl2tpd 启动时自动拨。手动发起的好处是方便调试xl2tpd-control connect to-lns这条命令会让 LAC 去连to-lns这个 lac 段定义的 LNS。如果配置有问题日志里会直接报出来。调试阶段我强烈建议用手动方式确认没问题后再改成自动。查看状态可以用xl2tpd-control status to-lns它会告诉你当前是连接中、已连接还是断开。配合ip addr看 PPP 接口有没有起来基本就能判断链路状态了。6. 隧道通了但业务不通分层排查法6.1 先看隧道层SCCRQ 有没有回应排查的第一步永远是确认隧道层。在 LAC 侧抓包看 UDP 1701如果只看到 SCCRQ 发出去没有 SCCRP 回来那问题在隧道层可能是 LNS 没监听、地址不对、或者中间挡了 UDP。如果看到了完整的 SCCRQ/SCCRP/SCCCN 三次握手说明隧道没问题往会话层看。我习惯用tcpdump -i any -n udp port 1701抓包配合-w存文件用分析工具看。抓包是最诚实的排查手段配置和日志都可能骗你但包不会。6.2 再看会话层ICRQ 和 PPP 协商隧道通了之后看有没有 ICRQ/ICRP/ICCN。如果会话建不起来常见原因是 LNS 侧的 lac 段没匹配上或者认证配置有问题。会话建起来之后就该看 PPP 的 LCP、认证、IPCP 了。这一步的日志在/var/log/messages或者 xl2tpd 自己的日志里ppp debug yes打开后信息很详细。一个典型的会话通了但拿不到地址的情况往往是 IPCP 协商失败。原因可能是 LNS 侧地址池配错、地址池耗尽、或者local ip和地址池不在一个网段。对着日志里的 IPCP 消息看基本能定位。6.3 最后看路由和转发能 ping 通不代表能访问链路全通了用户也拿到地址了但访问不了内网其他机器——这时候问题在路由和转发。LNS 侧要确认net.ipv4.ip_forward是 1要有到内网的回程路由proxyarp要开。LAC 侧要确认路由指向 PPP 接口。我遇到过一个很隐蔽的情况LNS 能 ping 通拨入用户用户也能 ping 通 LNS但用户访问不了 LNS 后面的内网服务器。最后发现是内网服务器没有回程路由到 PPP 地址池包能过去但回不来。这种问题只能靠在内网服务器上抓包才能发现光看 LNS 是看不出来的。7. 几个反复踩到的坑和我的处理习惯7.1 MTU 问题小包通大包不通这是 L2TP 最经典的坑。表现是 ping 小包正常ping 大包比如ping -s 1472不通或者网页能打开但图片加载失败。根因是 L2TP 封装增加了开销实际可用 MTU 小于 1500。解决办法是把两侧的 MTU/MRU 都调小1400 是个常用值如果外层还有 IPsec可能要调到 1300 甚至更低。我的习惯是配置阶段就把 MTU 设成 1400别等出问题再改。虽然理论上 1500 也能跑但一旦中间有设备做分片或者路径 MTU 发现有问题排查起来非常费劲。预防性设小一点省心。7.2 认证失败密码对但就是不过有时候密码明明是对的认证就是不过。常见原因有三个一是 chap-secrets 里用户名大小写和 LAC 侧不一致二是服务名写错比如 LNS 要求特定服务名但 chap-secrets 里写了*三是密码里有特殊字符配置文件解析出问题。我的处理习惯是认证失败时先把认证方式降到 PAP 试一次。如果 PAP 能过说明密码本身没问题问题在 CHAP 的配置细节上。如果 PAP 也过不了那就是用户名密码或者文件格式的问题。这个二分法能快速缩小范围。7.3 重拨风暴链路抖动引发的连锁反应分支场景里如果链路不稳定LAC 会不断重拨。如果redial timeout设得太短或者 LNS 侧有连接数限制就可能引发重拨风暴把 LNS 拖垮。我的做法是redial timeout至少设 10 秒max redials设一个上限超过就停下来等人工介入而不是无限重试。另外 LNS 侧也可以做一些保护比如限制单个来源的隧道数。不过这些要看具体实现支持不支持不是所有版本都有。至少 LAC 侧的重拨参数要控制好这是你能直接掌控的。7.4 日志级别调试时开稳定后关ppp debug yes在调试时非常有用但稳定运行后建议关掉否则日志量很大既占磁盘又影响性能。我的习惯是调试阶段全开确认稳定后把 debug 关掉只保留必要的运行日志。这样出问题时还能从历史日志里找线索平时又不会太吵。8. 一个可复现的最小实例复盘把上面的内容串起来一个最小的 CALL LNS 实例大概是这样LNS 侧配好 xl2tpd 的 lns 段、PPP 选项、chap-secrets确认 UDP 1701 可达LAC 侧配好 lac 段、PPP 选项用xl2tpd-control connect发起呼叫然后按隧道层、会话层、PPP 层、路由层逐层验证。我自己的验证顺序是先tcpdump确认三次握手再xl2tpd-control status确认会话状态再ip addr看 PPP 接口和地址再pingLNS 的 local ip最后ping内网一台机器。这个顺序从下往上每一层都确认了再往上走出问题时能立刻定位到是哪一层。最后分享一个我个人的小习惯每次配完 L2TP我都会把两侧的关键配置和验证命令记在一个小本子上包括这次用的 MTU、认证方式、地址池。下次再配类似环境时直接翻本子比重新查文档快得多。L2TP 这东西参数不多但容易记混有个自己的配置清单能省很多重复劳动。