目录
PAP(Password Authentication Protocol,口令认证协议)
概述
PPP(point-to-point协议),即点对点协议,是数据链路层封装协议的一种。提供一种标准的方式在点对点的链路上传输多个网络层协议的数据报,PPP协议包括各种网络控制协议族(NCP)如:IPCP和IPXCP等,链路控制协议族(LCP)以及验证协议族(CHAP、PAP)等。其中,网络控制协议主要用来协商链路上传输的数据包的格式和类型,链路控制协议主要用来建立、拆除和监控PPP数据链路,验证协议主要用来提供网络安全的保证。
PPP协议工作在串行接口和串行链路上,一般来说,PPP协议所构成的网络只允许双方之间通信,不允许像以太网一样接入交换机后接入其他的主机或设备。
结构组成
为了在点对点的链路上建立通信,PPP链路的两端必须发送LCP数据包进行数据链路的测试和配置。等链路建立起来之后,还可能要进行端的验证,然后,PPP必须发送NCP数据包选择并配置一个或多个网络层协议,当所选择的网络层协议配置成功之后,每个网络层发送的数据报就可以在链路上传送了。链路一直保持着直到有明确的LCP或NCP数据包断开链路或某些外来的事件发生
PPP协议为在点对点链路传输各种协议数据报提供了一个标准方法,主要由以下三部分构成:
- 对各种协议数据报的封装方法(封装成帧)
- 链路控制协议LCP 用于建立、配置以及测试数据链路的连接
- 一套网络控制协议NCPs 其中的每一个协议支持不同的网络层协议
帧格式
- Flag字段为帧定界标志,用来标识PPP帧的开始与结束,长度为1字节,取值固定为0x7E
- Address字段为地址字段,用来标识接收方的地址,长度为1字节,由于点到点链路的接收方是唯一的,故此字段取值固定为0xFF,表示只有对端才能接受到数据。
- Control字段为控制字段,长度为1字节,取值固定为0x03,表示无序号信息(Unnumbered Information)。
- Protocol字段为协议字段,用来标识PPP帧封装的协议数据类型,长度为2字节。此字段使PPP得以封装不同的协议。
字段值 协议 0x0021 IP(Internet Protocol) 0x0029 Appletalk 0x8021 IPCP(Internet Protocol Control Protocol) 0xC021 LCP(Link Control Protocol) 0xC023 PAP(Password Authentication Protocol) 0xC025 LQR(Link Quality Report) 0xC223 CHAP(Challenge Handshake Authentication Protocol) - Information字段为信息字段,该字段长度不固定,最大长度等于MRU(Maximum Receive Unit)值,默认为1500字节。此字段存放承载的协议数据,包括LCP、NCP等。
- FCS(Frame Checksum)字段为帧校验和字段,用来检测PPP帧的完整性(CRC计算),长度为2字节。
差错检测
接收方每收到一个PPP帧,就进行CRC检验(多项式)。若CRC检验正确,就收下这个帧;反之就丢弃这个帧(不可靠传输服务)。检验由尾部的FCS实现
使用PPP的数据链路层,向上提供的是不可靠数据传输服务,PPP协议没有纠错和重传机制。
ppp工作流程(阶段与状态)
在一下关于协议的描述中,我们需要区分两个概念:phase与state,翻译过来就是阶段与状态。在下面的应用中,我们可以看到,整个过程由不同的几个阶段构成,而每个阶段则是由不同的状态转换过程构成的,这些转换过程反映了协商的过程,所以不同的阶段可能包括相同的状态转换过程,表明它们的协商原理是一致的。
在建立、保持和终止PPP链路的过程中,PPP链路需要经过5个阶段,除认证阶段外,其它4个阶段都是必要过程。 5个阶段如下:
1 链路不可用阶段(Dead,物理层未准备好):
链路在该阶段启动和结束。当外部事件指示链路准备好去使用的时候,PPP将进入建立阶段。在该阶段,lcp自动机将处于初始化或正在启动状态,链路向建立阶段的转换将发送一个up事件到状态机
实现注意事项:典型的,在调制解调器断开连接后,链路应当自动转换到该状态。
2 链路建立阶段(Establish) :
LCP通过交换配置信息建立连接,当一个configure-ack包发送和接收后即完成配置阶段,进入打开状态。如果接收到LCP配置请求,会引起状态由网络协议层或着认证状态回退到LCP的建立阶段。
3 认证阶段(Authenticate):
该过程完成双方的认证,这并不是强制要求的,但是如果使用了,则在没有完成认证前不能进入网络协议配置阶段。一个实现不能简单的使认证过程失效因为超时或者缺少响应,而应该在多次尝试失败后才认为认证失败。
4 网络层协议阶段(Network):
完成上述两个阶段的配置后就可进入这一阶段进行网络层的协议的协商。当NCP进入打开状态后,PPP就可以承载响应网络协议的数据包了。在进入opened状态之前,任何收到的网络层的数据包都将被丢弃。实现上需注意,如果lcp处于打开状态,收到任何不被支持的协议的数据包都将会发送一个协议拒绝包,仅仅支持的协议才会被悄悄的丢弃。
5 链路终止阶段(Terminate):
PPP可以在任何时候终止链路,这可能在一下情况下发生:丢失信号、认证失败、链路质量确认失败、超过最大空闲时间以及管理员的主动关闭行为。Lcp通过交换terminate数据包来进行关闭链路的操作。当链路正在关闭时,PPP会通知网络层,以便其采取相应的措施。终止请求的发送者将关闭链路在收到终止请求响应后或者重启计数器超时。终止请求的接收着应当等待对方断开链路,在发送一个终止响应后重启计数器超时前接收者不能断开链路。之后,PPP进入dead阶段。
通过lcp关闭链路已经足够了,而且应当就由lcp来关闭链路。
LCP协议详解
概述
LCP(Link Control Protocol,链路控制协议):用于建立、配置、维护和终止PPP链路
LCP负责PPP的链路管理,和上层(网络层)协议无关。
报文格式
当PPP帧中Protocol字段为0xC021
时,表示Information 字段数据为LCP报文。
- Code为代码字段(也称类型字段),长度为1字节,用来标识LCP中链路控制报文的类型。
- Identifier为标识符字段,长度为1字节,是报文的唯一标识。Identifier字段用于匹配请求和回复。
- Length为长度字段,长度为2字节,Length字段指出该报文的长度,包括Code,Identifier,Length和Data。
- Data为数据字段,长度是零或多个八位字节,由Length字段声明。Data字段的格式由Code字段决定。
报文种类
LCP报文类型分为三大类,分别是:
1. 配置请求报文(Configure-Request):发送方向接收方请求协商某个参数的值。
2. 配置响应报文(Configure-Ack):接收方回复发送方的请求,同意协商某个参数的值。
3. 配置拒绝报文(Configure-Nak):接收方回复发送方的请求,拒绝协商某个参数的值,并提供一个备选值。
类型 | 功能 | 报文类型 | 报文代码 | 说明 |
链路配置 | 建立和配置链路 | Configure-Request | 1 | 配置请求:包含建议选项及其值的列表 |
Configure-Ack | 2 | 配置确认:接受所有建议的选项 | ||
Configure-Nak | 3 | 配置不确认:告知某些选项不能被接受 | ||
Configure-Reject | 4 | 配置拒绝:告知某些选项不可识别 | ||
链路终止 | 终止链路 | Terminate-Request | 5 | 终止请求:请求关闭线路 |
Terminate-Ack | 6 | 终止确认:接受关闭请求 | ||
链路维护 | 管理和调试链路 | Code-Reject | 7 | 编码拒绝:告知一个未知编码 |
Protocol-Reject | 8 | 协议拒绝:告知一个未知协议 | ||
Echo-Request | 9 | 回声请求:检测另一端是否活动的一种呼叫报文 | ||
Echo-Reply | 10 | 回声应答:对回声请求报文的响应 | ||
Discard-Request | 11 | 丢弃请求:丢弃分组的请求 |
LCP工作过程
链路建立和配置流程
- 需要建立逻辑链路时,发起方发送Configure-Request(配置请求)报文,用于协商参数;
- 若接收方收到的每一个配置选项的值都可接受,则回送Configure-Ack(配置确认)报文;
- 若收到的配置选项是可以识别,但部分配置选项参数不能接受,则回送Configure-Nak(配置否认)报文,并标示出需要重新协商的配置选项;
- 若配置选项不可识别或不可接受,则回送Configure-Reject(配置拒绝)报文。
链路终止流程
- Terminate-Request(终止请求)报文
- Terminate-Ack(终止应答)报文
链路维护流程
- Code-Reject(代码拒绝)
- Protocol-Reject(协议拒绝)
- Echo-Request(回复请求)和Echo-Reply(回复应答)
- Discard-Request(丢弃请求)
认证
PPP协议支持两种认证方式,分别是PAP和CHAP。
PAP(Password Authentication Protocol,口令认证协议)
优点:PAP的整个认证流程非常简单
缺点:认证只能在链路建立阶段进行,身份和口令是以明文进行传输,安全性低
认证流程
1. 发送方发送认证请求报文,包含用户名和密码。
2. 接收方回复认证响应报文,表示认证成功或失败。
报文格式
PAP协议的报文共有三种:
- Authenticate-Request(认证请求)
- Authenticate-Ack(认证确认)
- Authenticate-Nak(认证否认)
若PPP帧中Protocol字段取值为0xC023
时,表示Information字段承载的是PAP报文。
CHAP协议
CHAP(Challenge Handshake Authentication Protocol,基于挑战的握手认证协议)
CHAP为三次握手协议,可以在链路建立和数据通信阶段多次使用,进行认证,同时安全性较高
认证过程中需配合事先协商好的算法,确认被认证方的身份,通常使用MD5(Message Digest Algorithm 5)作为其默认算法。只在网络上传输用户名,而不传输用户口令。
目前PPP协议的认证阶段多使用CHAP认证协议。
认证流程
1. 发送方发送挑战请求报文,包含一个随机数。
2. 接收方回复挑战响应报文,包含一个经过加密的随机数。
3. 发送方将接收到的随机数和密码进行加密,生成一个响应报文。
4. 接收方验证响应报文是否正确,如果正确则认证成功,否则认证失败。
报文格式
CHAP协议的报文共有四种:
- Challenge
- Response
- Success
- Failure
若PPP帧中Protocol字段取值为0xC223
时,表示Information字段承载的是CHAP报文
NCP协议(Network网络层协商阶段)
NCP(Network Control Protocol,网络控制协议)用于建立、配置网络层协议,进行参数协商。
不同的网络层协议会使用不同的NCP协议。
- IP协议使用IPCP(Internet Protocol Control Protocol,IP控制协议);
- Appletalk协议使用Appletalk NCP进行协商;
- Novell的 IPX协议使用IPE(Internet Packet Exchange,互连网包交换协议)进行协商。
IPCP协议
若PPP帧中Protocol字段取值0x8021
,表示PPP帧正在使用IPCP协商相关通信参数。
IPCP会完成协商IP地址等工作,其后在该PPP链路上传送IP数据报;
若IP数据报传送完毕,若要关闭IP协议,仍需通过IPCP协商终止;
若要释放链路,则需借助LCP协议。
报文格式
类型 | 功能 | 报文类型 | 报文代码 |
链路配置 | 建立和配置链路 | Configure-Request | 1 |
Configure-Ack | 2 | ||
Configure-Nak | 3 | ||
Configure-Reject | 4 | ||
链路终止 | 终止链路 | Terminate-Request | 5 |
Terminate-Ack | 6 | ||
链路维护 | 管理和调试链路 | Code-Reject | 7 |
与LCP报文格式几乎一样
配置选项
IPCP协议中,通信双方可协商的配置选项包括3个:
- 多个IP地址(IP-Addresses)
多个IP地址很难全部协商成功
本选项很少使用
- IP压缩协议(IP Compression Protocol)
用于协商使用的压缩协议
IPCP中仅规定了“Van Jacobson”一个压缩协议,编号为0x002D,Type字段取值为0x02。
该选项默认值为不进行压缩。
- IP地址(IP Address)
若发起方请求对端分配一个IP地址,接收方应会返回一个合法的IP地址。此时,发起方发送configure-request,type为0x03,length为0x06,其后4字节全为0x00,指明由对端提供IP地址。
IPCP Configure-Request报文示例:
LWIP PPP
如何下载lwip ppp demo



文件结构
数据结构
protent
1. `u_short protocol`:表示 PPP 协议的协议号。
2. `void (*init) (ppp_pcb *pcb)`:初始化过程,当需要初始化一个新的 PPP 协议时调用。
3. `void (*input) (ppp_pcb *pcb, u_char *pkt, int len)`:处理接收到的数据包。
4. `void (*protrej) (ppp_pcb *pcb)`:处理接收到的协议拒绝。
5. `void (*lowerup) (ppp_pcb *pcb)`:表示底层已经连接上。
6. `void (*lowerdown) (ppp_pcb *pcb)`:表示底层连接断开。
7. `void (*open) (ppp_pcb *pcb)`:打开该协议。
8. `void (*close) (ppp_pcb *pcb, const char *reason)`:关闭该协议,并指定关闭原因。
9. `int (*printpkt) (const u_char *pkt, int len, void (*printer) (void *, const char *, ...), void *arg)`:将数据包以可读形式打印输出。
10. `void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len)`:处理接收到的数据包。
11. `const char *name`:协议的文本名称。
12. `const char *data_name`:对应数据协议的文本名称。
13. `option_t *options`:命令行选项列表。
14. `void (*check_options) (void)`:检查请求的选项并分配默认值。
15. `int (*demand_conf) (int unit)`:配置接口以进行按需拨号。
16. `int (*active_pkt) (u_char *pkt, int len)`:确定是否为此数据包建立连接。
用于衔接PPP各个子模块。
该数据结构提供了一个模型,可以说是一个模子,当我们在不同的阶段需要时会复制一份,并根据当前需要进行赋值。该结构体的protocol域用于指示当前具体的PPP协议,可能的选择有lcp、pap、chap、ipcp等等,用于表示不同的PPP阶段。之后的几个域是函数指针,根据名称我们可以对它们进行具体的赋值,比如如果将其用于LCP协议中,则init就可以使用lcp_init函数来注册,将其地址保存下来。在PPP中我们定义了一个该结体指针的数组,其中各个项就是各个结构体的地址,如下:
最终就形成一个表,如下:
控制块:struct ppp_pcb_s(ppp.h-312行)–>typedef struct ppp_pcb_s ppp_pcb(ppp.h-154行)–>ppp_pcb *ppp(程序中用户定义);
通信协议接口:struct netif ppp_netif;
//请求 DNS 服务器 地址
ppp_set_usepeerdns(ppp, 1);
// 登陆用户 和 密码
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
// 初始化 PPP 协商,没有等待(holdoff =0 )一定能被调用 如果 PPP 是死亡状态(即连接不成功)
u16_t holdoff = 0;
ppp_connect(ppp, holdoff);
将接收的PPP帧传入lwip内核可以使用这两个接口
void pppos_input(ppp, buffer, buffer_len);
void pppos_input_tcpip(ppp, buffer, buffer_len);
总体流程
1、创建网络接口:
创建一个全局的网络接口:struct netif pppnetif;
2、创建PPP控制块并初始化
用pppos_create()创建PPP控制块:ppppcb,并把网络接口、串口输出回调函数等赋值给ppppcb。
3、设置默认网络接口
用pppapi_ppp_set_default(ppp)把PPP设置为默认的网络接口。
4、设置用户及密码
如果用到验证,用ppp_set_auth();函数设置用户名及密码
5、启动ppp_connect();
ppp_connect(ppp,holdoff);
因为在用pppos_create()创建ppp_pcb的时候已经把pppos_connect()的回调函数地址赋值给ppppcb了,所以启用ppp_connect()后就是直接启用pppos。