4. PPP协议深度解析:PPP链路建立过程、LCP协商、PAP/CHAP认证、NCP阶段(IPCP)

说到DTU通信,PPP协议是个绕不开的老伙计。很多刚入行的朋友觉得PPP太古老,没什么好学的。其实不然,我这些年调试过的DTU设备,十有八九的拨号问题都出在PPP的某个环节上。今天咱们就把PPP的链路建立过程掰开揉碎了讲清楚。

4.1 PPP链路建立的四个阶段

PPP的链路建立,说白了就是四个步骤走下来。我习惯把它比作两个人打电话:先确认线路通不通(LCP),再验证对方身份(认证),然后商量怎么传数据(NCP),最后才能开始聊天(数据传输)。

具体来说,分为这四个阶段:

  1. 链路建立阶段 —— LCP协商,确定基本的通信参数
  2. 认证阶段 —— PAP或CHAP,验证身份
  3. 网络层协议阶段 —— NCP协商,比如IPCP分配IP地址
  4. 链路终止阶段 —— 关闭链路,释放资源

嗯,这里要注意:认证阶段是可选的。有些场景下不需要认证,直接从LCP跳到NCP。但DTU上公网时,运营商基本都会要求认证。

4.2 LCP协商:链路建立的基石

LCP(Link Control Protocol)是PPP的第一步。它的任务就是让通信双方确认:咱们能不能用PPP说话?用什么参数说话?

LCP协商的内容包括:

配置项 说明 典型值
MRU 最大接收单元 1500字节
认证协议 选择PAP还是CHAP CHAP优先
魔术字 检测环路 随机生成
协议压缩 是否压缩协议字段 通常关闭
ACFC 地址和控制字段压缩 通常关闭

LCP的协商过程很有意思,它用的是"请求-应答-确认"的三次握手。我举个例子:

// LCP配置请求报文示例
// 发送方发起协商
Configure-Request (ID=1)
  - MRU: 1500
  - Auth-Protocol: CHAP
  - Magic-Number: 0x12345678

// 接收方同意所有选项
Configure-Ack (ID=1)

// 或者接收方部分同意
Configure-Nak (ID=1)
  - MRU: 1492  // 建议修改MRU

// 或者接收方完全不认识某个选项
Configure-Reject (ID=1)
  - ACFC       // 不支持ACFC压缩

我在项目中遇到过一个问题:某款4G DTU拨号总是失败,抓包一看,LCP协商时设备请求了ACFC压缩,但基站不支持,直接发了Reject。设备收到Reject后没有重新协商,而是直接放弃了。说白了,这就是设备协议栈实现不完善的问题。

4.3 PAP与CHAP认证:两种不同的思路

认证阶段,PPP提供了两种方式:PAP和CHAP。我个人的建议是:能用CHAP就别用PAP。

4.3.1 PAP认证

PAP(Password Authentication Protocol)是最简单的认证方式。它直接把用户名和密码以明文形式发送给对方。

// PAP认证过程
// 被认证方发送
Authenticate-Request
  - Peer-ID: "user@cmnet"
  - Password: "123456"

// 认证方回复
Authenticate-Ack    // 认证成功
// 或
Authenticate-Nak    // 认证失败

你看,密码是明文传输的。这在公网上非常危险。我曾经在客户的现场抓包,一眼就看到DTU的PAP密码。嗯,那个客户后来被我劝着改成了CHAP。

注意:PAP的密码是明文传输,且认证方无法控制认证时机。被认证方可以随时发起认证请求。这在安全性要求高的场景下是致命的。

4.3.2 CHAP认证

CHAP(Challenge Handshake Authentication Protocol)就聪明多了。它不直接传密码,而是用挑战-应答的方式。

CHAP的工作流程是这样的:

  1. 认证方发送一个随机数(Challenge)给被认证方
  2. 被认证方用密码和这个随机数做MD5运算,把结果返回
  3. 认证方自己也做同样的运算,比对结果
// CHAP认证过程
// 认证方发起挑战
Challenge (ID=1)
  - Value: 0xA1B2C3D4E5F6...  // 16字节随机数
  - Name: "server"

// 被认证方应答
Response (ID=1)
  - Value: MD5(ID + Password + Challenge)
  - Name: "user@cmnet"

// 认证方确认
Success (ID=1)
// 或
Failure (ID=1)

你想想看,即使有人在中间抓包,拿到Challenge和Response,他也无法反推出密码。因为MD5是单向的。而且CHAP会在链路建立后定期重新认证,防止会话劫持。

实战经验:我在调试CHAP时发现一个坑:有些DTU设备对Challenge中的Name字段处理有问题。如果Name字段包含特殊字符,MD5计算结果就不对。后来我建议客户在配置用户名时只用字母和数字,问题就解决了。

4.4 NCP阶段:IPCP分配IP地址

认证通过后,就进入NCP(Network Control Protocol)阶段了。对于IP网络来说,这个阶段叫IPCP(IP Control Protocol)。

IPCP的主要任务有两个:

  • 协商IP地址(通常是运营商分配一个公网IP)
  • 协商DNS服务器地址

IPCP的协商过程和LCP类似,也是请求-应答的模式:

// IPCP配置请求
Configure-Request
  - IP-Address: 0.0.0.0    // 表示请求分配
  - Primary-DNS: 0.0.0.0   // 请求DNS

// 运营商回复
Configure-Nak
  - IP-Address: 10.20.30.40    // 分配的内网IP
  - Primary-DNS: 114.114.114.114

// 设备确认
Configure-Request
  - IP-Address: 10.20.30.40
  - Primary-DNS: 114.114.114.114

// 运营商确认
Configure-Ack

这里有个细节:设备第一次发请求时,IP地址填0.0.0.0,意思是"我没有IP,请分配一个"。运营商回复Nak,给出分配的IP。设备再用这个IP重新请求,运营商才回复Ack。

为什么要多这一步?说白了,就是确认设备确实收到了分配的IP,并且愿意使用它。

关键点:IPCP协商成功后,PPP链路才算真正建立。此时设备才能通过这个链路发送IP数据包。很多DTU拨号失败,问题就出在IPCP阶段——要么是运营商没分配IP,要么是设备没正确处理Nak报文。

4.5 完整的PPP链路建立时序

把上面几个阶段串起来,一个完整的PPP链路建立过程是这样的:

DTU                             基站
  |                               |
  |--- LCP Configure-Request ---->|   // 协商MRU、认证方式等
  |<-- LCP Configure-Ack ---------|   // 基站同意参数
  |<-- LCP Configure-Request -----|   // 基站也发起协商
  |--- LCP Configure-Ack -------->|   // DTU同意
  |                               |
  |--- CHAP Response ------------>|   // 应答挑战
  |<-- CHAP Success --------------|   // 认证通过
  |                               |
  |--- IPCP Configure-Request --->|   // 请求IP地址
  |<-- IPCP Configure-Nak --------|   // 分配IP
  |--- IPCP Configure-Request --->|   // 确认使用
  |<-- IPCP Configure-Ack --------|   // 完成
  |                               |
  |========= 数据通信 ============|   // 开始传数据

整个过程通常只需要几百毫秒。如果超过3秒还没完成,基本可以断定某个环节出了问题。

我曾经遇到一个案例:某款DTU在信号弱的地方拨号特别慢。抓包发现,LCP协商要重传三四次才能成功。后来定位到是设备对LCP超时重传的间隔设置太短,只有200ms。在信号差的时候,报文传输延迟大,200ms根本不够。把重传间隔改成1秒后,问题就解决了。

好了,PPP的链路建立过程就讲到这里。下一章咱们聊聊PPP的帧格式和高级特性,比如多链路PPP和PPP over Ethernet。这些东西在实际的DTU开发中经常会碰到。