你必须非常努力,才能看起来毫不费力!
分类: 系统运维
2008-09-10 19:50:36
Linux网络管理员手册(8)
2000-07-29 10:40
发布者: 阅读次数:1180翻译:赵炯
gohigh@shtdu.edu.cn
第八章 点对点协议
8.1 揭开P字母
正像SLIP一样,PPP是在串行连接上发送数据报的协议,但却改进了前者的几个不足之处。它让通信的双方在开始时协商诸如IP地址和最大数据报大小等选项,并且为客户提供授权(权限)。对于每个这样的功能,PPP都有一个独立的协议。下面,我们将概要地讨论PPP的这些基本创建框图。这里的讨论远不是完整的;如果你想对PPP知道的更多些,极力推荐你阅读RFC-1548中它的规格说明,以及许多相关的RFCs。[1]
PPP的最底层是高级数据链路控制协议(High-Level Data Link Control Protocol),缩写为HDLC,[2] 它定义了单个PPP帧的分界,并提供了16比特的检查和。相对于非常原始的SLIP包装来说,一个PPP帧能够容纳除IP以外的其它协议,如Novell的IPX、或Appletalk。PPP通过在基本的HDLC帧上加上一个协议字段来做到这功能,这个字段用于识别帧所携带的包的类型。
LCP,链路控制协议(the Link Control Protocol),用于HDLC的上层,用于协商适合于数据链路的选项,如指出链路的一边同意接收的最大数据报大小的最大接收单元(MRU)。
在PPP连接的配置阶段重要的一步是客户授权(权限)。尽管不是强制的,但对于拨号线路几乎是必要的。通常,被呼叫的主机(服务器)通过验证客户是否知道某个秘密的键值来要求客户认证自己。如果呼叫者不能给出正确的秘密键值,连接就中断了。使用PPP,授权工作是双方面的;也即,呼叫者也可以要求服务器认证自己。这些认证过程对于双方是完全独立的。对于不同的认证类型有两个协议,我们将在下面更进一步地讨论。它们被命名为口令认证协议(Password Authentication protocol),或PAP和质询握手认证(Challenge Handshake Authentication Protocol),或CHAP。
路由通过数据链路的每一个网络协议,如IP、Appletalk等等,使用相应的网络控制协议(Network Control Protocol)(NCP)被动态地配置。例如,要通过链路发送IP数据报,PPP的双方首先必须协商双方使用的IP地址。用于此目的的控制协议是IPCP,即互连网协议控制协议(Internet Protocol Control Protocol)。
除了通过链路发送标准的IP数据报,PPP也支持IP数据报的Van Jacobson头压缩。这是一项将TCP包头缩小到仅有三个字节的技术。它也用于CSLIP,并且常常通俗地称为VJ头压缩。是否使用压缩同样可以在开始时通过IPCP协商来决定。
8.2 Linux上的PPP
在Linux中,PPP的功能被分成了两个部分,一个是位于内核的低级的HDLC驱动程序部分,另一部分是处理各种控制协议的用户空间的pppd后台程序。Linux的PPP当前发行版是linux-ppp-1.0.0,包含有内核PPP模块、pppd、和一个用于拨号至远程系统的称为chat的程序。
PPP内核驱动程序是由Michael Callahan编制的。pppd源自于为Sun和386BSD机器的一个免费PPP实现,它是由Drew Perkins和其他人编制的,并且由Paul Mackerras维护。是由Al Longyear[3] 移植到Linux上的。chat是由Karl Fox编制的。[4]
正如SLIP,PPP是通过一个特殊的线路规程来实现的。要以PPP连接使用某个串行线路,你首先要象往常那样通过modem建立一个连接,随后将线路转换成PPP模式。在这种模式下,所有的进入的数据都传给了PPP驱动程序,该驱动程序检查传入的HDLC帧的有效性(每个HDLC帧带有一个16比特的检验和),并且解开并分发它们。目前,它能够处理IP数据报,可选地使用Van Jacobson头压缩。为了支持IPX,PPP驱动程序也将被扩展成能处理IPX包。
内核的驱动程序是由pppd,PPP后台程序,协助工作的,在实际的网络通信能在链路上进行之前,它执行必要的整个初始化和认证过程。pppd的行为可以使用一些选项来调整。由于PPP非常复杂,不可能在一章中解释所有的东西。因此本书不打算涵盖pppd的所有方面,而只是给你一个介绍。详细信息,请参考在线手册页和pppd原始发行版中的READMEs,它将帮助解决在这章中没有讨论过的大多数问题。如果在阅读了所有的文档之后你的问题还没有得到解决,你应该到新闻组comp.protocols.ppp寻求帮助,在那里你可以接触到包括pppd开发者的大多数人。
8.3 运行pppd
当你想通过一个PPP连接连到Internet上,你必须设置好基本的网络功能,如回送设备和解析器。这两者已在前面章节中讨论过了。还有些有关在串行链路上使用DNS的解释;请参考SLIP一章中对此的描述。
作为一个使用pppd如何建立一个PPP连接的入门例子,假设你再次在vlager。你已经拨号到PPP服务器,c3po,并且登录进ppp帐号。c3po已经启动它的PPP驱动程序。在退出用于拨号的通信程序以后,你执行下面的命令:
# pppd /dev/cua3 38400 crtscts defaultroute
这会将串行线路cua3转换到PPP模式并建立一个到c3po的IP连接。用于串行端口的传输速度将是38400bps。crtscts选项打开端口的硬件握手功能,这对于高于9600bps的速度是绝对必要的。
在启动之后pppd所做的首件事情是使用LCP与远端协商几种连接特性,通常,pppd所试用的缺省的选项集将能工作,所以我们不打算在这里考虑这些。我们将在后面几节中再回过来详细讨论LCP。
此时,我们也假设c3po不需要从我们这边取得任何认证,所以配置阶段成功地完成了。
然后pppd将使用IPCP,IP控制协议,与它的对等点协商IP参数。由于上面我们没有对pppd指定任何特殊的IP地址。它将试着使用通过解析器查找本地主机名获得的地址。此后,两者将向对方宣告他们的地址。
通常,这些缺省设置并没有什么错误。即使你的机器是在一个以太网上,你可以对以太网和PPP接口使用同一个IP地址。当然,pppd允许你使用不同的地址,或者请求对方使用某个特定的地址。这些选项将在以后章节中描述。
在通过了IPCP设置阶段以后,pppd将准备你的主机的网络层来使用PPP连接。它首先配置PPP网络接口作为一个点对点连接,对第一个活动的PPP连接使用ppp0,对第二个使用ppp1,依次类推。下一步,它将设置一个指向链路另一端主机的路由表条目。在上面示出的例子中,pppd将使得缺省网络路由指向c3po,因为我们已给它defaultroute选项。[5] 这使得所有到不在本地网络上主机的数据报都被发送到c3po。pppd还支持几个不同的路由选择方案,这将在本章后面详细讨论。
8.4 使用选项文件
在pppd分析它的命令行参数之前,为了查找缺省选项它扫描几个文件。这些文件可能含有有效的命令行参数,它们分布在任意的行上。注释语句是由“#”开头的。
第一个选项文件是/etc/ppp/options,当pppd启动时总会扫描它。使用它设置一些全局缺省值是个好主意,因为它允许你阻止你的用户做某些危及安全的事情。例如,要使得pppd要求对方某种授权认证(PAP或CHAP),你应该在该文件中加入auth选项。用户覆盖不了这个选项,所以与不在我们的授权数据库中的任何系统建立一个PPP连接变成不可能的事。
在/etc/ppp/options文件以后读取的其它选项文件,是用户主目录中的.ppprc。它允许每个用户指定她自己的缺省选项集。
一个样本/etc/ppp/options文件可以是象这样的:
# Global options for pppd running on vlager.vbrew.com
auth # require authentication
usehostname # use local hostname for CHAP
lock # use UUCP-style device locking
domain vbrew.com # our domain name
这些选项的头两个用于权限认证并且将在下面给出解释。lock关键字使得pppd遵守标准的UUCP设备锁定方法。根据这个惯例,每个访问串行设备的进程,如/dev/cua3,在UUCP spool目录中创建一个名为LCK..cua3的锁定文件,用于指示该设备正在使用。这是避免任何其它程序如minicom或uucico去打开PPP正在使用的串行设备。
在全局配置文件中提供这些选项的原因是如上显示的那些选项是不能被覆盖掉的,因而提供了一个合理的安全级。然而,请注意有些选项可以在后面被覆盖掉;这样的一个例子是connect串。
8.5 使用chat拨出
在上例中让你感到不便的事情之一是在你能够启动pppd之前必须手工地建立连接。不象dip,pppd对于拨号至远程系统以及登录没有自己的脚本语言,而是需要依赖于某些外部程序或shell脚本来做这些事。要执行的命令可以用connect命令行选项给予pppd。pppd将重定向该命令的标准输入和输出到串行线路上。针对此一个有用的程序是expect,是由Don Libes编写的。它有一个基于Tcl的非常强大的语言,并且是针对此类应用明确地设计出来的。
pppd软件包带有一个同样称为chat的程序,是用于指定UUCP-风格的会话脚本的。基本上说,一个会话脚本是由我们期望从远程系统收到的交互式的字符串序列以及我们所发送的应答字符串序列。我们将分别称之为期望字符串和发送字符串。这是从一个典型会话脚本中的摘录:
ogin: b1ff ssword: s3kr3t
这告诉chat等待远程系统发送来登录提示,并且返回登录名b1ff。我们只是等待ogin: 所以登录提示是大写还是小写没什么关系,也不用管它是否完全正确。接下来的又是一个期望字符串它使得chat等待口令输入提示,并且随后发出你的口令。
这基本上,上面是chat脚本所要做的。当然,拨号到一个PPP服务器的完整脚本也必须包括适当的modem命令。假设你的modem使用Hayes命令集,并且服务器的电话号码是318714。那么与c3po创建一个连接的完整的会话请求是
$ chat -v "" ATZ OK ATDT318714 CONNECT "" ogin: ppp word: GaGariN
根据定义,头一个字符串必须是期望字符串,但是在我们启动modem之前,modem是不会发出任何东西的,所以我们通过指定一个空串来跳过第一个期望字符串。然后我们继续发出ATZ,即Hayes兼容modem的复位命令,并等待它的响应(OK)。下一个串向chat发送出一个拨号命令和电话号码,并且期望得到CONNECT消息的响应。接下来又是一个空串,因为我们现在还不想发送出任何信息,而是等待登录提示的出现。余下的chat脚本所做的工作完全象我们上面描述的一样。
-v选项使得chat将所有的活动记录在syslog后台程序的local2中。[6]
在命令行上写出会话脚本会承担一定的风险,因为用户可以使用ps命令观察进程的命令行。你可以将会话脚本放入一个文件,比如说是dial-c3po,来避免这个风险。通过给chat一个-f选项后跟这个文件名,你可以使得chat从该文件中读取脚本取而代之从命令行读取。现在完整的pppd命令就象这样:
# pppd connect "chat -f dial-c3po" /dev/cua3 38400 -detach \
crtscts modem defaultroute
除了指定拨号脚本的connect选项,我们在命令行上多加了两个选项:-detach—告知pppd不要从控制台分离并且变成为后台进程。Modem关键字使得pppd在串行设备上执行某些modem专用的动作,就如在拨号之前和之后挂断线路。如果你不使用这个关键字,pppd将不会监视端口的DCD线,因而将不会检测是否远端出呼意料地挂断了。
上面给出的例子是非常简单的;chat允许有更为复杂的会话脚本。一个非常有用的特性是指定中止含有错误的的会话。典型的中止字符串是象消息BUSY、或NO CARRIER,这是当所拨的号码是忙音、或没有提起电话时,你的modem产生的。为了使得chat迅速地识别出这些中止字符串,而不是等到超时,你可以使用ABORT关键字在脚本的开头指定它们:
$ chat -v ABORT BUSY ABORT "NO CARRIER" "" ATZ OK ...
以同样的方式,你可以通过插入TIMEOUT选项来改变会话部分中的超时值。详细资料,请参见chat(8)的手册页。
有时,你也想有条件地执行会话脚本的一部分。例如,当你没有接收到远端的登录提示时,你可能想发送一个BREAK,或一个回车键。你可以通过给期望字符串附加一个子脚本来做到。它是由一系列的发送和期望字符串组成,正象整个脚本本身,它是用连字号分开的。每当附加的期望字符串没有及时收到时,该子脚本就会被执行。在上面的例子中,我们要象下面那样修改会话脚本:
ogin:-BREAK-ogin: ppp ssword: GaGariN
现在,当chat没有收到远程系统发送的登录提示时,子脚本就被执行,首先发送一个BREAK,然后再次等待登录提示的出现。如果现在提示出现时,脚本就会象往常那样继续,否则的话,它将带错而终止。
8.6 调试你的PPP设置
缺省地,pppd将把任何警告和出错消息记录到syslog的daemon设施中。你必须往syslog.conf中增加一个条目,以使得这些消息重定向到一个文件中,或者甚至到控制台上,否则的话syslog就会轻易地丢弃这些消息。下面这个条目将所有的消息送到/var/log/ppp-log:
daemon.* /var/log/ppp-log
如果你的PPP设置不能立刻工作,查看这个日志文件会给你什么地方出错的一点提示。如果这没有什么帮助,你可以使用debug选项打开额外的调试输出信息。这使得pppd将所有发送和接收的控制数据包的内容记录到syslog中。所有的消息将传入daemon设施中。
最后,最猛烈的方法是通过使用选项kdebug调用pppd,以激活内核层的调试。在该选项之后是下面数值的比特位或运算的数值:1表示一般调试消息,2 表示打印所有传入的HDLC帧的内容,4 是使得驱动程序打印出所有传出的HDLC帧。要捕获内核的调试消息,你必须或者运行读取/proc/kmsg文件的syslogd后台程序,或者是klogd后台程序。这两者都将内核的调试信息定向到syslog的kernel设施中。
8.7 IP配置选项
在连接配置期间,IPCP是用于协调几个IP参数的。通常,每个端点都会发出一个IPCP配置请求包,指出它想要改变哪些缺省值,改成什么值。在接收方,远端依次检查每个选项,并且或者同意改变或者拒绝。
关于pppd将尝试协调哪些IPCP选项,pppd给了你许多的控制权。你可以通过命令行选项来调节这些选项,我们将在下面讨论它们。
8.7.1 选择IP地址
在上面的例子中,我们用pppd拨号到c3po并且建立了一个IP连接。在连接的两端没有预备要选择一个特定的IP地址。而是使用vlager的地址作为本地IP地址,并让c3po自己给出自己的。然而,有时候在连接的一端或两端控制要使用的地址是很有用的。pppd支持这种控制的几种变异。
要请求特定的地址,通常你要给pppd提供下面的选项:
local_addr:remote_addr
这里local_addr和remote_addr可以用点分四组表示法表示,或用主机名表示。[7] 这使得pppd试图使用第一个地址作为它自己的IP地址,而第二个作为对等点的。如果在IPCP协商时,对方拒绝了其中之一的地址,那么就不能建立起IP连接了。[8]
如果你只想设置本地地址,并接受任何对等点使用的地址,你只需不使用remote_addr部分就行了。例如,要使得vlager使用IP地址130.83.4.27而不使用自己的IP地址,你需要在命令行上给出130.83.4.27:即可。类似地,如果只想设置远端点的地址,你只需让local_addr字段为空。此时,缺省地,pppd将使用与你的主机相应的地址。
有些处理许多客户站点的PPP服务器动态地为客户分配地址:只有当拨号进来时才给客户系统分配地址,而当客户退出时就再次清除。当拨号到这种服务器时,你必须确信pppd没有要求从服务器要求任何特定的IP地址,而是接受服务器让你使用的地址。这意味着你不必指定local_addr参数。另外,你必须使用noipdefault选项,该选项使得pppd等待对等点提供IP地址,以替代使用本地主机的地址。
8.7.2 通过PPP连接进行路由
在设置好网络接口以后,pppd通常将主机的路由只设置到它所连接的远端点上。如果远端主机是在一个LAN上,你当然也希望能够连接到远端主机所在网络的其它主机上;也即,必须设置一个网络路由。
上面,我们已经知道可以使用defaultroute选项请求pppd设置默认的路由。如果你所拨号连接的服务器将作为你的Internet网关话,那么这个选项将是非常有用的。
相反的情况是,你的系统作为孤独的主机的一个网关,也同样很容易做到。例如,假设虚拟酿酒厂的某个雇员,他家的机器叫做loner。当通过PPP连接到vlager时,他使用酿酒厂子网的地址。在vlager端,我们现在可以给pppd一个proxyarp选项,它将为loner安装一个代理ARP条目。这将自动地使得loner可以访问酿酒厂和葡萄酒厂的所有主机了。
然而事情并不是总是那样的简单,例如,当连接两个局域网时。这常常需要增加一个特殊的网络路由,因为这些网络都可以有它们自己默认的路由。另外,使得两个端点使用PPP连接作为默认路由将产生一个循环,到未知目的地的包将在这两个端点之间来回传送,直到它们过了存活期。
作为一个例子,假设虚拟酿酒厂在某个其它城市开了一个分支机构。这个附属机构使用IP网络号191.72.3.0运行一个他们自己的以太网,它是酿酒厂的B类网络的子网3。他们想通过PPP连接到酿酒厂的主以太网上以更新客户的数据库等等。再次,vlager将作为一个网关;它的远端点被称作sub-etha且IP地址为192.72.3.1。
当sub-etha连接到vlager时,它将象平常一样使得默认路由指向vlager。然而,在vlager上,我们必须为通过sub-etha的子网3安装一个网络路由。为此,我们使用一个pppd的至今还没有讨论过的特性—ip-up命令。这是一个位于/etc/ppp中的shell脚本或程序,是在PPP接口配置完以后执行的。当使用时,它是用下列参数调用的:
ip-up iface device speed local addr remote addr
这里,iface指定所使用的接口,device是所使用的串行设备文件(如果使用了stdin/stdout,那么是/dev/tty)的路径名,speed是设备的速度。local_addr和remote_addr给出了以点分四组表示的用于连接两端点的IP地址。在我们这种情况下,ip-up脚本可以包含下列代码段:
#!/bin/sh
case $5 in
191.72.3.1) # this is sub-etha
route add -net 191.72.3.0 gw 191.72.3.1;;
esac
exit 0
以类似的方式,/etc/ppp/ip-down是用于在PPP连接再次断开以后取消所有ip-up的活动。
然而,路由选择方案还没有完成。我们已经在双方的PPP主机上设置好了路由选择表条目,但至今,在两个网上的所有其它主机关于PPP连接的任何事情。如果在附属机构的所有主机有指向sub-etha的默认路由,并且酿酒厂的所有主机都默认地路由到vlager的话,
这就不是个大问题了。如果不是这样的话,那么你唯一的选择是使用一个象gated的路由选择后台程序。在vlager上创建了网络路由以后,路由选择后台程序将会对所有子网上的主机广播这个新路由。
8.8 链路控制选项
上面,我们已经遇到过LCP,也即链路控制协议,它是用于协调链路特性以及测试链路的。
通过LCP协调的两个重要的选项是最大接收单元,和异步控制字符映射表。还有许多其它的LCP配置选项,但它们太特殊,这里就不给予描述了。请参考RFC1548中对它们的解释。
异步控制字符映射表,俗称异步表,是用于象电话线路的异步链路上确定必须被换码的控制字符(用一特殊的二字符序列替换)。例如,你可能想要避开用于软件握手信号的XON和XOFF字符,因为某些配置不当的modem在接收到一个XOFF时可能会卡住。其它的控制字符包括Ctrl-](telent的换码字符)。通过在异步表中指定这些控制字符,PPP允许你对ASCII码0到31 中的任何字符进行换码。
异步表是一个32比特宽的位图,最低比特位对应于ASCII的NUL字符,最高比特位对应于ASCII码31。如果一个比特位置位,它表示相应的字符在发送到链路之前必须被转义(换码)。最初,异步表被设置为0xffffffff,它表示所有的控制字符都将被转义。
为了告诉你的对等点不需要对所有的控制字符换码,而只需要对其中的几个进行转义,你可以使用asyncmap选项给pppd指定一个新的异步映射。例如,如果只有^S和^Q(ASCII 17和ASCII 19,通常用作XON和XOFF)必须被转义,那么就使用下面的选项:
asyncmap 0x000A0000
最大接收单元(Maximum Receive Unit),或MRU,通知对等点我们想接收的HDLC帧的最大长度。尽管这会使你想起MTU的值(最大传输单元Maximum Transfer Unit),这两者很少有共同之处。MTU是内核网络设备的一个参数,描述了接口能够处理的最大帧的大小。而MRU只是对远端点不要产生任何大于MRU值的一个建议;不管怎样,接口必须能够接收最大为1500字节的帧。
因此,如何选择一个MRU的大小就与链路的传输能力关系不大了,而是与如何能达到最大的吞吐量有关。如果你打算在链路上运行交互式的应用程序,那么将MRU值设置为小到296是个不错的主意,这样一个偶然的大数据包(比如,从一个FTP来的会话)就不会使得你的光标“跳动”了。要告知pppd请求一个296的MRU,你必须给它一个选项mru 296。然而,小的MRUs只有在你没有禁止VJ头压缩(它默认是激活的)时才有意义。
pppd也能够理解一些设置协调过程整体行为的LCP选项,比如在链路终止前可以交换的最大请求配置数。除非你明确的知道你在做什么,否则不要改动它们。
最后,还有两个用于LCP回显消息的选项。PPP定义了两类消息,回显请求(Echo Reguest)和回显响应(Echo Response)。Pppd使用这个特性来检查一个链路是否还在运行。你可以通过使用lcp-echo-interval选项和一个以秒计的时间值来激活这个特性。如果在这个时间间隔内没有从远程主机收到帧,那么pppd生成一个Echo Reguest,并切期待对等点返回一个Echo Response。如果对等点没有产生一个响应,那么在发送了一定数量的请求以后链路即被中止。这个数量可以用lcp-echo-failure选项来设置。缺省地,这个特性是全部禁止的。
8.9 常规安全考虑
一个配置不当的PPP后台程序能成为一个破坏性的安全缺口。它糟糕到象允许任何人能够将他的机器接入你的以太网上(这是非常糟糕的)。在本节中,我们将讨论一些能使你安全配置PPP的方法。
Pppd的一个问题是,要配置网络设备和路由选择表需要root权限。通常解决这个问题的办法是运行它setuid root。然而,pppd允许用户设置各种与安全相关的选项。为了免受用户可能通过操作这些选项而发起的攻击,建议你在全局/etc/ppp/options文件中设置一些默认值,就象使用选项文件一节例子中显示的。其中有些,比如授权认证选项用户是覆盖不了的,所以对操作起到了一定的保护作用。
当然,你也需要针对你用PPP连接的系统来保护自己。要挡开假冒他人的主机,你应该总是检查你的对等点的授权认证。另外,你不应该允许外部主机能使用它们选择的任何IP地址,而是限制他们只能使用几个地址。下面一节将涉及到这些问题。
8.10 PPP授权认证
8.10.1 CHAP与PAP
对于PPP来讲,每个系统可以要求它的对等点使用两种授权认证协议之一来认证自己。这两个协议是口令认证协议(Password Authentication Protocol)(PAP)和质询握手认证协议(Challenge Handshake Authentication Protocol)(CHAP)。当创建了一个连接以后,两端都可以请求对方认证自己,而不管它是呼叫者还是被呼叫者。下面当我想区别认证系统和认证者时,我将宽松地用“客户”和“服务器”来讲。一个PPP后台程序能够请求它的对等点通过发送另一个确定期望的认证协议的LCP配置请求来进行认证。
PAP与通常的登录过程的工作原理基本上一样。客户通过向服务器发送一个用户名和一个(可以是加密的)口令来认证自己,服务器用它们与自己的秘密数据库相比较。对于那些通过监听串行线路以获得口令的偷听者和对于重复试验出错(trial and error)的攻击来说,这项技术是易受攻击的。
CHAP就没有这些不足之处。对于CHAP,认证者(也即是服务器)向客户发送一个随机生成的“质询”字符串和自己的主机名。客户使用该主机名来查询适当的秘码(口令),并将其与质询合在一起形成一个字符串,并且使用一个单向(杂凑)哈希函数加密该串。结果值与自己的主机名一起返回给服务器。现在服务器执行相同的计算,如果得到相同的结果就认可该客户。
CHAP的另一个特性是它不仅在开始时请求客户认证自己,而且每隔一定的时间就发送一个质询,以确信客户并没有被入侵者替换掉,例如通过切换电话线路。
pppd将CHAP和PAP的秘密键值分别存放在两个不同的文件中,称为/etc/ppp/chap-secrets和pap-secrets,通过使用一个或另一个文件来进入远程主机,你可以很好地控制是使用CHAP还是PAP来与对方认证我们自己,反之也然。
默认地,pppd无须来自远端的认证,但是同意来自远端的认证请求。由于CHAP比PAP来得更为稳固和强壮,pppd会尽可能地使用前者。如果对方不支持它,或者pppd在它的chap-secrets文件中找不到该远程系统的一个CHAP秘密(密码),它就回过来使用PAP。如果它也没有针对于对等点的PAP密码,它就拒绝做任何认证。结果,连接被关闭。
这种行为可以从几个方面进行修改。例如,当给出auth键值时,pppd将请求对方来认证自己。如果pppd分别在CHAP或PAP数据库中有一个对于该对等点的密码时, pppd将同意使用CHAP或PAP来做。还有一个可以打开或关闭特定认证协议的选项,但这里我们就不再描述它们了。详细信息请参考pppd(8)手册页。
如果所有和你进行PPP对话的系统同意为你认证它们自己,你应该将auth选项放入全局/etc/ppp/options文件中并且为每个系统在chap-secrets文件中定义口令。如果一个系统不支持CHAP,那么就在pap-secrets文件中为其加入一个条目。这样,你就可以确信连接到你的主机上的任何系统都是认证过的。
下面两节描述了这两个PPP密码文件,pap-secrets和chap-secrets。它们位于/etc/ppp中,包含客户、服务器和口令三为一组的值,还可以后接任选的一个IP地址列表。客户和服务器字段的解释对于CHAP和PAP是不同的,这也起决于我们是否要为对方认证我们自己,或者要求服务器为我们认证它们自己。
8.10.2 CHAP的秘密文件
当pppd必须为某些使用CHAP的服务器认证自己时,pppd就在pap-secrets文件中寻找客户字段与本地主机名相同、服务器字段与在CHAP质询中发送来的远程主机名相同的条目。当要求对等点认证它自己时,该规则只是简单地反一下:此时pppd寻找客户字段与远程主机名相同(经由客户的CHAP响应发送过来的)、服务器字段与本地主机名相同的条目。
下面是vlager的一个样本chap-secrets文件:[9]
# CHAP secrets for vlager.vbrew.com
#
# client server secret addrs
#-------------------------------------------------------------------
vlager.vbrew.com c3po.lucas.com "Use The Source Luke" vlager.vbr
c3po.lucas.com vlager.vbrew.com "riverrun, pasteve" c3po.lucas
* vlager.vbrew.com "VeryStupidPassword" pub.vbrew.
当与c3po建立了一个PPP连接时,c3po要求vlager通过发送一个CHAP质询用CHAP来认证自己。然后pppd扫描chap-secrets文件中的客户字段等于vlager.vbrew.com、服务器字段等于c3po.lucas.com的条目,[10] 这样就找到了上面的第一行。然后它就从质询字符串和密码(Use The Source Luke)生成一个CHAP响应,并发送给c3po。
与此同时,pppd为c3po组合成一个CHAP质询,其中包含一个唯一的质询字符串和它的全资主机名vlager.vbrew.com。c3po以刚才我们讨论的方式构成一个CHAP响应,并将其返回给vlager。现在,pppd从响应中取得客户的主机名(c3po.vbrew.com),并且查找chap-secrets文件中客户字段为c3po、服务器字段为vlager的一行。这正是上面的第二行,所以pppd将CHAP质询和该行的密码(riverrun, pasteve)组合在一起并进行加密,并将结果与c3po的CHAP响应相比较。
可选的第四个字段列出了在第一个字段的客户的IP地址的一个列表。这个地址可以用点分四组表示法给出也可以用解析器查找出的主机名给出。例如,如果c3po在IPCP协商中请求使用一个不在这个列表中的IP地址,请求将被拒绝,并且IPCP将被关闭。因此在上面所示的样本文件中,c3po被限制于只能使用自己的IP地址。如果地址字段是空的,那么就允许使用任何地址;如果该字段不空,就限制了该客户使用的IP地址。
样本chap-secrets文件的第三行允许任何主机与vlager建立一个PPP链接,因为一个为*的客户或服务器字段与任何主机名匹配。唯一的限制是这些主机必须知道秘码,并且使用地址pub.vbrew.com。以通配符作主机名的任何条目可以在秘密文件中的任何地方,因为pppd总是使用服务器/客户对最为匹配的条目。
关于pppd在秘密文件中查找获取主机名的方式,还有一些要作说明。就象前面所解释的,远程主机名总是通过对等点的CHAP质询或响应包提供的。本地主机名缺省的是通过调用gethostname(2)函数来得到的。如果你已经将系统名设置为你的非限制的主机名,这样的话,你就必须使用domain选项为pppd另外给出一个域名:
# pppd …domain vbrew.com
这将使得对于所有有关授权认证的活动,都将把酿酒厂的域名添加到vlager上。其它修改本地主机名的progpppd的想法是usehostname和name。当你使用“local:varremote”(local不是点分四组表示的名字)在命令行上给出本地IP地址,pppd将使用它作为本地主机名。详细信息请参见pppd(8)的手册页。
8.10.3 PAP秘密文件
PAP秘密文件与CHAP所用的非常相似。头两个字段总是包含一个用户名和一个服务器名;第三个字段含有PAP密码。当远端发送来一个认证请求时,pppd使用服务器字段等于本地主机名、用户字段等于请求中发送过来的用户名的条目。当为对等点认证自己时,pppd从用户字段等于本地用户名、服务器字段等于远程主机名的行中取得密码(secret)。
一个样本PAP秘密文件就象这一样:
# /etc/ppp/pap-secrets
#
# user server secret addrs
vlager-pap c3po cresspahl vlager.vbrew.com
c3po vlager DonaldGNUth c3po.lucas.com
第一行用于和c3po对话时认证我们自己。第二行说明一个名为c3po的用户必须为我们认证它自己。
第一列的名字vlager-pap是我们发送给c3po的用户名。缺省地,pppd将用本地主机名作为用户名,但是你也可以通过给出user选项后跟一个名字来指定一个不同的名字。
当为了与对等点进行认证而从pap-secrets文件中选取一个条目时,pppd必须知道远端主机的名字。由于它没法找出该名字,你必须在命令行上使用remotename关键字后跟对等点的主机名来指定它。例如,要使用上面的条目与c3po认证,我们必须在pppd的命令行上加入下面的选项:
\#{} pppd … remotename c3po user vlager-pap
在第四个字段(以及所有后面的字段),你可以指定特定的主机所允许的IP地址,正如CHAP秘密文件中的一样。这样,对等点就可以从那个列表中只请求地址。在样本文件中,我们要求c3po使用它的真实IP地址。
注意,PAP是一个非常弱的认证方法,所以建议尽可能使用CHAP。因此我们在这里对PAP就不再详述了;如果你对PAP的使用感兴趣的话,你可以在pppd(8)的手册页中找到许多有关PAP的特性。
8.11 配置一个PPP服务器
以服务器方式运行pppd只需在命令行上加上一些适当的选项。原则上讲,你要创建一个特殊的帐号,比如说是ppp,并给它一个脚本或程序作为用这些选项调用pppd的登录shell。例如,你要在/etc/passwd中加入下面一行:
ppp:*:500:200:Public PPP Account:/tmp:/etc/ppp/ppplogin
当然,你可以使用与上面所示不同的uids和gids。你还必须使用passwd命令为上面的帐号设置口令。
然后,ppplogin脚本可以象这样:
#!/bin/sh
# ppplogin - script to fire up pppd on login
mesg n
stty -echo
exec pppd -detach silent modem crtscts
mesg命令用于禁止其他用户往tty写信息,比如使用write命令。stty命令关闭字符回显功能。这是必须的,否则的话对等点发送来的任何信息都将回显回去。上面给出的最重要的pppd选项是-detach,因为它防止pppd脱离控制tty。如果我们不指定这个选项,它就会进入后台,使得shell脚本退出。随之而来的是串行线路将被挂断,连接中止。silent选项使得pppd在开始发送前进行等待直到它从呼叫系统接收到一个数据包。这可以防止当呼叫系统很缓慢地启动它的PPP客户时传输的超时。modem选项用于使得pppd监视DTR引线用以观察对等点是否已掉线,而crtscts选项用以打开硬件握手信号。
除了这些选项以外,你还可以迫使使用某些授权认证,例如通过在pppd的命令行上或在全局选项文件中指定auth。有关开启和禁用各种认证协议的更多选项的描述,可参见在线手册。
注释
[1] 相关的RFCs列在本书后面的指定参考书目中。
[2] 实际上,HDLC是一个由国际标准化组织(ISO)设计的非常通用协议。
[3] 两位作者都已经说过今后会比较忙。如果你有任何有关PPP的一般问题,你最好询问Linux积极分子mailing list的NET通道上的人。
[4] karl@morningstar.com 。
[5] 缺省的网络路由只是在还没有时才被建立。
[6] 如果你编辑syslog.conf将这些登录信息重定向到一个文件中,请确信这个文件是不可读的,因为chat缺省地记录下整个会话脚本—包括口令和所有其它的信息。
[7] 对于CHAP权限认证方法在该选项中使用主机名表示是有其因果关系的。请参见下面的CHAP一节。
[8] 通过将选项ipcp-accept-local和ipcp-accept-remote给予pppd,你可以允许远端点覆盖你对使用IP地址的设想。详细信息请参阅手册。
[9] 双引号不是口令的一部分,它们只是用来标明口令中的空格而已。
[10] 这个主机名是从CHAP质询中得到的。