在前一个例子中,可能让您觉得不方便的事情之一是,您必须手动建立连接,然后才能启动 pppd。与 dip 不同,pppd 没有自己的脚本语言来拨打远程系统并登录,而是依赖于外部程序或 shell 脚本来完成这项工作。要执行的命令可以通过 connect 命令行选项提供给 pppd。pppd 将把该命令的标准输入和输出重定向到串行线路。
pppd 软件包附带一个非常简单的程序,名为 chat,它能够以这种方式用于自动化简单的登录序列。我们将详细讨论这个命令。
如果您的登录序列很复杂,您将需要比 chat 更强大的工具。一个有用的替代方案是 expect,由 Don Libes 编写。它有一种非常强大的基于 Tcl 的语言,并且正是为此类应用而设计的。那些登录序列需要例如质询/响应身份验证(涉及类似计算器的密钥生成器)的用户会发现 expect 足够强大来处理这项任务。由于这个主题可能有非常多的变体,我们不会在本书中描述如何开发合适的 expect 脚本。 只要说您可以使用 pppd 的 connect 选项指定 expect 脚本的名称来调用它。同样重要的是要注意,当脚本运行时,标准输入和输出将连接到调制解调器,而不是调用 pppd 的终端。如果您需要用户交互,您应该通过打开一个备用的虚拟终端或安排其他方式来管理它。
chat 命令允许您指定 UUCP 风格的 chat 脚本。基本上,chat 脚本由一系列交替的字符串组成,这些字符串是我们期望从远程系统接收的,以及我们要发送的答案。我们将分别称它们为 expect(期望)和 send(发送)字符串。这是一个典型的 chat 脚本摘录
ogin: b1ff ssword: s3|<r1t |
此脚本告诉 chat 等待远程系统发送登录提示符并返回登录名 b1ff。我们只等待 ogin:,这样登录提示符是以大写还是小写 l 开头,或者是否出现乱码都无关紧要。以下字符串是另一个 expect 字符串,它使 chat 等待密码提示符并发送我们的响应密码。
这基本上就是 chat 脚本的全部内容。一个完整的拨号 PPP 服务器的脚本,当然,还必须包含适当的调制解调器命令。假设您的调制解调器理解 Hayes 命令集,并且服务器的电话号码是 318714。那么,建立与 c3po 连接的完整 chat 调用将是
$ chat -v '' ATZ OK ATDT318714 CONNECT '' ogin: ppp word: GaGariN |
根据定义,第一个字符串必须是一个 expect 字符串,但是由于在启动调制解调器之前它不会说任何话,我们通过指定一个空字符串来使 chat 跳过第一个 expect。然后我们发送 ATZ,这是 Hayes 兼容调制解调器的重置命令,并等待其响应 (OK)。下一个字符串将 dial 命令以及电话号码发送给 chat,并期望收到 CONNECT 消息作为响应。 之后再次跟一个空字符串,因为我们现在不想发送任何东西,而是等待登录提示符。chat 脚本的其余部分与之前描述的完全相同。这个描述可能看起来有点令人困惑,但我们稍后会看到有一种方法可以使 chat 脚本更容易理解。
The–v选项使 chat 将所有活动记录到 syslog 守护程序 local2 facility。[1]
在命令行上指定 chat 脚本存在一定的风险,因为用户可以使用 ps 命令查看进程的命令行。您可以通过将 chat 脚本放在像这样的文件中来避免这种风险dial-c3po。您可以通过给 chat 提供以下–f选项,后跟文件名,来使 chat 从文件而不是命令行读取脚本。此操作还有一个额外的好处,即使我们的 chat expect 序列更容易理解。要转换我们的示例,我们的dial-c3po文件将如下所示
'' ATZ OK ATDT318714 CONNECT '' ogin: ppp word: GaGariN |
完整的 pppd 调用现在看起来像这样
# pppd connect "chat -f dial-c3po" /dev/ttyS3 38400 -detach \ crtscts modem defaultroute |
除了指定拨号脚本的 connect 选项之外,我们还在命令行中添加了两个选项:–detach,它告诉 pppd 不要从控制台分离并成为后台进程;以及 modem 关键字,它使 pppd 在串行设备上执行特定于调制解调器的操作,例如在呼叫前后断开线路。如果您不使用此关键字,pppd 将不会监视端口的 DCD 线路,因此将无法检测到远程端是否意外挂断。
我们展示的示例相当简单;chat 允许使用更复杂的脚本。例如,它可以指定在哪些字符串上中止 chat 并报错。典型的中止字符串是诸如 BUSY 或 NO CARRIER 之类的消息,这些消息通常在被叫号码忙或无人接听时由您的调制解调器生成。为了使 chat 立即识别这些消息而不是超时,您可以使用 ABORT 关键字在脚本的开头指定它们
$ chat -v ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ... |
同样,您可以通过插入 TIMEOUT 选项来更改 chat 脚本某些部分的超时值。
有时您还需要对 chat 脚本的某些部分进行条件执行:当您没有收到远程端的登录提示符时,您可能想要发送一个 BREAK 或一个回车符。您可以通过将下标附加到 expect 字符串来实现这一点。下标由一系列 send 和 expect 字符串组成,就像整个脚本本身一样,它们之间用连字符分隔。每当未及时收到附加到的预期字符串时,就会执行下标。在上面的示例中,我们将按如下方式修改 chat 脚本
ogin:-BREAK-ogin: ppp ssword: GaGariN |
当 chat 没有看到远程系统发送登录提示符时,将执行下标,首先发送一个 BREAK,然后再次等待登录提示符。如果提示符现在出现,脚本将照常继续;否则,它将终止并报错。
[1] | 如果您编辑syslog.conf要将这些日志消息重定向到一个文件,请确保这个文件不是全局可读的,因为默认情况下 chat 也会记录整个 chat 脚本——包括密码。 |