闲谈PPP协议

 

闲谈PPP协议

 (一)、PPP数据帧的格式

PPP协议也许大家都听说过,可以说现在家里的ADSL都是通过PPP协议进行链路的搭建,今天就说说PPP到底是个啥东东。
  想要了解PPP,个人认为有3个关键的知识点。
   1、PPP数据帧的格式;
  2、PPP的几种报文;
  3、PPP的状态转移
  
       首先说说的PPP数据帧的格式,因为 PPP是链路层协议,所以我们将它的数据单位称为帧, 
7E FF 03 7E
标志 地址 控制 协议域 信息域 校验  标志
1B 1B 1B 2B 缺省1500B 2B 1B
每一个PPP数据帧均是以一个标志字节起始和结束的,该字节为0x7E(这样很容易区分出每个PPP帧)
    紧接在起始标志字节后的一个字节是地址域,该字节为 0x FF 。我们熟知网络是分层的,且对等层之间进行相互通信,而下层为上层提供服务。当对等层进行通信时首先需获知对方的地址,而对不同的网络,在数据链路层则表现为需要知道对方的MAC 地址、X.121 地址、ATM 地址等;在网络层则表现为需要知道对方的IP 地址、IPX 地址等;而在传输层则需要知道对方的协议端口号。例如如果两个以太网上的主机希望能够通信的话,首先发送端需获知对端的MAC 地址。但由于 PPP协议是被运用在点对点的链路上的特殊性,它不像广播或多点访问的网络一样,因为点对点的链路就可以唯一标示对方,因此使用PPP协议互连的通信设备的两端无须知道对方的数据链路层地址,所以该字节已无任何意义,按照协议的规定将该字节填充为全1的广播地址。同地址域一样,PPP数据帧的控制域也没有实际意义,按照协议的规定通信双方将该字节的内容填充为0x03。(既然无意义,就可以随便赋值了吧,呵呵,只要大家都遵守一个标准就行)
   PPP 协议本身而言,我们最关心的内容应该是它的协议域和信息域。协议域可用来区分PPP 数据帧中信息域所承载的数据报文的内容。协议域的内容必须依据ISO 3309 的地址扩展机制所给出的规定。该机制规定协议域所填充的内容必须为奇数,也即是要求低字节的最低位为“1” ,高字节的最低位为“0” 。如果当发送端发送的PPP 数据帧的协议域字段不符合上述规定,则接收端会认为此数据帧是不可识别的,那么接收端会向发送端发送一个Protocol-Reject 报文,在该报文尾部将完整地填充被拒绝的报文。
   信息域缺省时最大长度不能超过1500 字节,其中包括填充域的内容,1500 字节大小等于PPP 协议中配置参数选项MRU Maximum Receive Unit )的缺省值,在实际应用当中可根据实际需要进行信息域最大封装长度选项的协商。信息域如果不足1500 字节时可被填充,但不是必须的,如果填充则需通信双方的两端能辨认出有用与无用的信息方可正常通信。
  协议域和信息域是需要合在一起看的,目前主要用到的协议类型有LCP、NCP和普通的IP协议,而他们相对应的协议域字段则为0×C021、0×8021和0×0021,可以看到应证了这句话:也即是要求低字节的最低位为“1”,高字节的最低位为“0”而后面的信息根据不同协议包含了不同的报文内容。

0×C021 LCP数据报文 校验 
0×8021 NCP数据报文 校验
0×0021 IP数据报文     校验
其实这3种不同协议就对应PPP协议在运行过程中的不同状态,以后会在PPP状态转移中介绍到,我们可以很容易根据PPP帧的协议域就判断目前处于PPP的哪个阶段。遇到PPP问题,我们通常通过抓包,然后判断PPP哪个阶段有问题,再进行分析和问题定位。注意一点的就是,NCP不是一种协议,它的全称是网络控制协议,也就是说最后双方都遵循的数据传输协议,可以是IPCP,也可以是IPXCP。
   
(二)PPP的状态转移

  昨天闲谈中,大家应该对PPP帧的结构有了基本的理解,其中在帧结构中,我们会看到有个协议域,分别可以C021,0021,8021三种代码,其实,这不同的代码就代表了当前帧所处的PPP状态,下面我们就聊聊PPP的5种状态。
   先请大家看一下附件中的PPP状态转移图

   首先双方都处于链路不可用阶段,接着会有一方提出链路请求,
如果希望通过PPP协议建立点对点的通信,无论哪一端的设备都需发送LCP数据报文来配置链路,一旦LCP的配置参数选项协商完后,通信的双方就会根据LCP配置请求报文中所协商的认证配置参数选项来决定链路两端设备所采用的认证方式。协议缺省情况下双方是不进行认证的,而直接进入到NCP配置参数选项的协商,直至所经历的几个配置过程全部完成后,点对点的双方就可以开始通过已建立好的链路进行网络层数据报文的传送了,整个链路就处于可用状态。只有当任何一端收到LCPNCP的链路关闭报文时(一般而言协议是不要求NCP有关闭链路的能力的,因此通常情况下关闭链路的数据报文是在LCP协商阶段或应用程序会话阶段发出的);物理层无法检测到载波或管理人员对该链路进行关闭操作,都会将该条链路断开,从而终止PPP会话。
  以下是PPP协议整个链路过程需经历阶段的状态转移图说明:在点对点链路的配置、维护和终止过程中,PPP需经历以下几个阶段:
  链路不可用阶段。有时也称为物理层不可用阶段,PPP链路都需从这个阶段开始和结束。(即使双方已经有物理连接,但没有激活PPP,也可以算不可用阶段)当通信双方的两端检测到物理线路激活(通常是检测到链路上有载波信号)时,就会从当前这个阶段跃迁至下一个阶段(即链路建立阶段)。先简单提一下链路建立阶段,在这个阶段主要是通过LCP协议(需要在PPP帧的协议域内填充C021)进行链路参数的配置,LCP在此阶段的状态机也会根据不同的事件发生变化。当处于在链路不可用阶段时,LCP的状态机是处于initial(初始化状态)或starting(准备启动状态),一旦检测到物理线路可用,则LCP的状态机就要发生改变。当然链路被断开后也同样会返回到这个阶段,往往在实际过程中这个阶段所停留的时间是很短的,仅仅是检测到对方设备的存在。
  链路建立阶段。是PPP协议最关键和最复杂的阶段。这是在数据链路层进行。该阶段主要是发送一些配置报文来配置数据链路,这些配置的参数不包括网络层协议所需的参数。当完成数据报文的交换后,则会继续向下一个阶段跃迁,该下一个阶段既可是验证阶段,也可是网络层协议阶段,下一阶段的选择是依据链路两端的设备配置的(通常是由用户来配置,但对NASBAS设备(这些设备主要是用来进行3A:认证、授权和计费)PPP模块缺省就需要支持PAPCHAP中的一种认证方式)。在此阶段LCP的状态机会发生两次改变,前面我们说了当链路处于不可用阶段时,此时LCP的状态机处于initialstarting,当检测到链路可用时,则物理层会向链路层发送一个UP事件,链路层收到该事件后,会将LCP的状态机从当前状态改变为Request-Sent(请求发送状态),根据此时的状态机LCP会进行相应的动作,也即是开始发送Config-Request报文来配置数据链路,无论哪一端接收到了Config-Ack报文时,LCP的状态机又要发生改变,从当前状态改变为opened状态,进入Opened状态后收到Config-Ack报文的一方则完成了当前阶段,应该向下一个阶段跃迁。同理可知,另一端也是一样的,但须注意的一点是在链路配置阶段双方是链路配置操作过程是相互独立的。如果在该阶段收到了非LCP数据报文,则会将这些报文丢弃。 
  验证阶段。多数情况下的链路两端设备是需要经过认证后才进入到网络层协议阶段,缺省情况下链路两端的设备是不进行认证的。在该阶段支持PAPCHAP两种认证方式,验证方式的选择是依据在链路建立阶段双方进行协商的结果。(这里想到一个小插曲,记得我去应聘现在的这家公司的时候,面试官问了我PPP验证阶段有几种认证方式,以前对于PPP也只是一知半解,知道有PAP和CHAP两种,也知道PAP是2次握手,CHAP是3次握手,但是具体是怎么通讯的,我只记得PAP的,而CHAP怎么也想不起来,很丢脸,呵呵。其实CHAP的C代表Chanllenge的意思,即验证方会首先发起挑战:你把密码告诉我,这是第一次握手;然后被验证方才会将密码告知验证方,这是第二次握手;最后验证方反馈验证结果,这是第三次握手。而PAP则只有后两次握手,另外PAP的密码是明文,CHAP的是密文,sao多了,继续吧,呵呵)然而,链路质量的检测也会在这个阶段同时发生,但协议规定不会让链路质量的检测无限制的延迟验证过程。在这个阶段仅支持链路控制协议、验证协议和质量检测数据报文,其它的数据报文都会被丢弃。如果在这个阶段再次收到了Config-Request报文,则又会返回到链路建立阶段。(其实有的时候是不需要通过验证阶段,链路建立就直接进入网络层协议阶段了)
  网络层协议阶段。一旦PPP完成了前面几个阶段,每种网络层协议(IPIPXAppleTalk)会通过各自相应的网络控制协议进行配置,每个NCP协议可在任何时间打开和关闭。当一个NCP的状态机变成Opened状态时,则PPP就可以开始在链路上承载网络层的数据包报文了。如果在个阶段收到了Config-Request报文,则又会返回到链路建立阶段。
  网络终止阶段PPP能在任何时候终止链路。当载波丢失、授权失败、链路质量检测失败和管理员人为关闭链路等情况均会导致链路终止。链路建立阶段可能通过交换LCP的链路终止报文来关闭链路,当链路关闭时,链路层会通知网络层做相应的操作,而且也会通过物理层强制关断链路。对于NCP协议,它是没有也没有必要去关闭PPP链路的。(PPP的除了不可用阶段,任何一种状态都可以立即进入网络终止阶段) 

  


三)LCP报文

我们在上一篇文章也说到,链路建立阶段是PPP状态转移中的一个非常重要的阶段,我们今天就单独对这个阶段中所涉及的LCP报文进行较为细致的分析。
  LCP 数据报文是在链路建立阶段被交换的,它作为PPP 的净载荷被封装在PPP 数据帧的信息域中。在链路建立阶段的整个过程中信息域的内容是在变化的,它包括很多种类型的报文,所以这些报文也要通过相应的字段来区分,请见附图一
  PPP 数据帧的协议域固定填充 0xC021  
   代码域的长度为一个字节,主要是用来标识LCP 数据报文的类型的。在链路建立阶段时,接收方收到LCP 数据报文的代码域无法识别时,就会向对端发送一个LCP 的代码拒绝报文(Code-Reject 报文)。 
   标识域也是一个字节,其目的是用来匹配请求和响应报文。一般而言在进入链路建立阶段时,通信双方无论哪一端都会连续发送几个配置请求报文(Config-Request 报文),而这几个请求报文的数据域可能是完全一样的,而仅仅是它们的标识域不同罢了。通常一个配置请求报文的ID 是从0x01 开始逐步加1 的,当对端接收到该配置请求报文后,无论使用何种报文(回应报文可能是Config-Ack Config-Nak Config-Reject 三种报文中的一种)来回应对方,但必须要求回应报文中的ID (标识域)要与接收报文中的ID 一致,当通信设备收到回应后就可以将该回应与发送时的进行比较来决定下一步的操作。 
   长度域的内容 =  总字节数据(代码域+ 标志域+ 长度域+ 数据域)。长度域所指示字节数之外的字节将被当作填充字节而忽略掉,而且该域的内容不能超过MRU 的值。
数据域的内容根据不同的LCP数据报文的内容也是不一样的。

下面说一下LCP包括的几种报文类型,见附图二,不同的报文在标识域中所填充的内容也不同。
LCP报文主要分为1、链路配置报文;2、链路终止报文;3、链路维护报文。
链路配置报文主要包括Config-RequestConfig-AckConfig-NakConfig-Reject四种报文。
当通信双方需要建立链路时,无论哪一方都需要发送Config-Request报文并携带每一端自已所希望协商的配置参数选项。
当接收方收到Config-Request报文时,会在剩下的三种类型的报文中选择一种来响应对方的请求报文,到底选择哪种报文来响应对方需依据以下两个条件:
不能完全识别配置参数选项的类型域,我们知道一个Config-Request报文中会同时携带多个配置参数选项,而对于一个支持PPP协议的通信设备也不一定会支持上表中所有列出的配置选项,即使支持,也可能在实际应用中关闭掉某些选项功能。(例如:当使用PPP协议通信的一端可能将一些无用的配置选项都关闭了,而仅支持0x010x03两个配置参数选项,因此当对方发送的Config-Request报文中含有0x04配置选项时,对于本端而言这个配置参数选项就无法识别,也即是不支持这个配置参数选项的协商)。
如果能支持完全识别配置参数选项,但接收端也可能不认可Config-Request报文中配置参数选项数据域中的内容(例如:当一端发送魔术字配置参数选项中的魔术字为全0,而对端认为应该为其它值,这种情况就属于不支持配置参数选项中的内容)。
所以依据上面的两个条件,我们就可以明确在回应对方配置请求报文时,采用何种报文回应。
当接收Config-Request报文的一端能识别发送过来的所有配置参数选项且认可所有配置参数选项数据域的内容时,接收端将会给对端回一个Config-Ack报文并将配置请求报文中的配置参数选项原封不动的放置在Config-Ack报文的数据域内(根据协议的规定是不可改变配置参数选项的顺序)。当配置请求报文的发送端收到Config-Ack报后,则会从当前阶段进入到下一个阶段。 
当接收Config-Request报文的一端能识别发送端所发送过来的所有配置参数选项,但对部分配置参数选项数据域中的内容不认可时,接收端将会给对端回应一个Config-Nak报文,(注意,是能够识别,只是对部分参数内容不认可,所以不是Config-Reject报文)该报文中只携带不认可的配置参数选项,而这些配置参数选项的数据内容为本端希望的值。然而当接收端收到Config-Nak报文后,会重新发送Config-Request报文,而这个Config-Request报文与上一次所发送的Config-Request报文区别在于那些被对端不认可的配置参数选项的内容被填写到刚刚协商完后再次发送的Config-Request报文中(Config-Nak报文发送回来的那些配置参数选项)。

  当接收Config-Request报文的一端不能识别所有的发送端发送过来的配置参数选项时,此时接收端将会向对端回一个Config-Reject报文,该报文中的数据域只携带那些不能识别的配置参数选项(当配置参数选项的类型域不识别时)。当对端接收到Config-Reject报文后,同样会再次发送一个Config-Request报文,这个配置请求报文与上一次发送的区别在于将不可识别的那些配置参数选项给删除了。 
  链路终止报文分为Terminate-RequestTerminate-Reply两种报文。LCP报文中提供了一种机制来关闭一个点对点的连接,想要关断链路的一端会持续发送Terminate-Request报文,直到收到一个Terminate-Reply为止。接收端一旦收到了一个Terminate-Request报文后,必须回应一个Terminate-Reply报文,同时等待对端先将链路断开后,再完成本端的所有断开的操作。

  LCP的链路终止报文的数据域与链路配置报文的数据域不一样,链路终止报文中无需携带各配置参数选项。对于链路终止报文也同样需要ID一致,当接收到Terminate-Reply报文才会做链路终止操作。



  最后说一下魔术字的含义,这是在链路建立过程中比较重要的一个参数,这个参数是在Config-Request里面被协商的,主要的作用是防止环路,如果在双方不协商魔术字的情况下,某些LCP的数据报文需要使用魔术字时,那么只能是将魔术字的内容填充为全0;反之,则填充为配置参数选项协商后的结果。

  魔术字在目前所有的设备当中都是需要进行协商的,它被放在Config-Request的配置选项参数中进行发送,而且需要由自身的通信设备独立产生,协议为了避免双方可能产生同样的魔术字,从而导致通信出现不必要的麻烦,因此要求由设备采用一些随机方法产生一个独一无二的魔术字。一般来说魔术字的选择会采用设备的系列号、网络硬件地址或时钟。双方产生相同魔术字的可能性不能说是没有的,但应尽量避免,通常这种情况是发产在相同厂商的设备进行互连时,因为一个厂商所生产的设备产生魔术字的方法是一样的。
  我们知道魔术字产生的作用是用来帮助检测链路是否存在环路,当接收端收到一个Config-Request报文时,会将此报文与上一次所接收到的Config-Request进行比较,如果两个报文中所含的魔术字不一致的话,表明链路不存在环路。但如果一致的话,接收端认为链路可能存在环路,但不一定存在环路,还需进一步确认。此时接收端将发送一个Config-Nak报文,并在该报文中携带一个重新产生的魔术字,而且此时在未接收到任何Config-RequestConfig-Nak报文之前,接收端也不会发送任何的Config-Request报文。这时我们假设可能会有以下两种情况发生:
  1.        链路实际不存在环路,而是由于对方在产生魔术字时与接收端产生的一致,但实际这种情况出现的概率是很小的。当Config-Nak被对端接收到后,应该发送一个Config-Request报文(此报文中的魔术字为Nak报文中的),当对端接收到后,与上次比较,由于接收端已经在Nak报文中产生了一个不同的魔术字,此时接收端收到的Config-Request报文中的魔术字与上次配置请求报文中不一样,所以接收端可断定链路不存在环路。
  2.        链路实际上确实存在环路,一段时间后Config-Nak报文会返回到发送该报文的同一端。这时接收端比较这个Config-Nak报文与上一次发出去的一样,因此链路存在环路的可能性又增大了。我们知道当一端收到了一个Config-Nak报文时,又会发送一个Config-Request报文(该报文中的魔术字与Config-Nak中的一致),这样又回到了最初的状态,在这条链路上就会不断的出现Config-RequestConfig-Nak报文,因此这样周而复始下去,接收端就会认为PPP链路存在环路的可能性在不断增加,当达到一定数量级时,就可认为此链路存在环路。(注意,不是第一次受到相同的魔术字就判断有环路的)
  但在实际应用中根据不同设备实现PPP协议的方法,我们在链路环路检测时可采用两种方法。第一种机制就是如上面所述的,这个过程不断地重复,最终可能会给LCP状态机发一个Down事件,这时可能会使LCP的状态机又回到初始化阶段,又开始新一轮的协商。当然对于某些设备还会采用第二种机制,就是不产生任何事件去影响当前LCP的状态机,而是停留在请求发送状态。但这时认为链路有环路的一端设备需要不断的向链路上发送Echo-Request报文来检测链路环路是否被解除,当接收端收到Echo-Reply报文时,就认为链路环路被解除,从而就可能进行后续的PPP的过程。 
  具体的例子可以参见附图三。
  好了,基本上通过3篇PPP闲谈,我们可以比较彻底的了解PPP协议的工作机制和特点,其实,会者不难,协议都是人制订的,只有简单易用的协议才会最终保留下来,就像TCP/IP打败OSI一样。所以,只要静下心来,没有什么高深的。可能这3篇文章里面有部分个人理解错误的地方,希望大家可以多提意见,大家共同进步。
 

 

 

 

CRC校验域主要是对PPP数据帧传输的正确性进行检测的,当然在数据帧中引入了一些传输的保证机制是好的,但可以反过来说,同样我们会引入更多的开销,这样可能会增加应用层交互的延迟。
   最后给大家一个通过Ethereal抓下来的PPP帧,对应上面的说明,看看大家是否可以看懂:
   7E FF 03 C021 01 01 00 17 02 06 00 0A 00 00 05 06 00 0B 42 CB 07 02 08 02 0D 03 06 7E 
   至于信息域里面的东西,还可以再细分,之后在PPP报文里面再说。

 

来源:http://hi.baidu.com/enut2006/blog/item/5ba8412cb31d78ec8b13995b.html

 

 

 

 

 

 

 

 

你可能感兴趣的:(网络)