6.4. Using to Automate Dialing
One of the things that may have struck
you as inconvenient in the previous example is that you had to
establish the connection manually before you could fire up pppd. pppd
relies on an external program or shell script to log in and connect
to the remote system. The command to be executed can be given to pppd
with the connect command-line option. pppd will
redirect the command's standard input and output to
the serial line.The pppd software package is supplied with a very simple program
called , which is capable of being used in this way to automate
simple login sequences. We'll talk about this
command in some detail.If your login sequence is complex, you will
need something more powerful than . One useful alternative you
might consider is expect, written by Don Libes.
It has a very powerful language based on Tcl and was designed exactly
for this sort of application. Those of you whose login sequence
requires, for example, challenge/response authentication involving
calculator-like key generators will find expect
powerful enough to handle the task. Since there are so many possible
variations on this theme, we won't describe how to
develop an appropriate expect script in this
book. Suffice it to say, you'd call your
expect script by specifying its name using the
pppd connect option. It's also
important to note that when the script is running, the standard input
and output will be attached to the modem, not to the terminal that
invoked pppd. If you require user interaction, you should manage it
by opening a spare virtual terminal, or arrange some other means.
The
command lets you specify a script. Basically, a script
consists of an alternating sequence of strings that we expect to
receive from the remote system, and the answers we are to send. We
will call them expect and
send strings, respectively. This is a typical
excerpt from a script:
ogin: b1ff ssword: s3|<r1tThis script tells to wait for the remote system to send the
login prompt and return the login name b1ff. We wait only for
ogin: so that it doesn't matter
if the login prompt starts with an uppercase or lowercase l, or if it
arrives garbled. The following string is another expect string that
makes wait for the password prompt and send our response
password.This is basically what scripts are all about. A complete script
to dial up a PPP server would, of course, also have to include the
appropriate modem commands. Assume that your modem understands the
Hayes command set, and the server's telephone number
is 318714. The complete invocation to establish a connection
with c3po would then be:
$ -v '' ATZ OK ATDT318714 CONNECT '' ogin: ppp word: GaGariNBy definition, the first string must be an expect string, but as the
modem won't say anything before we have kicked it,
we make skip the first expect by specifying an empty string. We
then send ATZ, the reset command for
Hayes-compatible modems and wait for its response
(OK). The next string sends the dial command along
with the phone number to and expects the
CONNECT message in response. This is followed by
an empty string again because we don't want to send
anything now, but rather wait for the login prompt. The remainder of
the script works exactly as described previously. This
description probably looks a bit confusing, but
we'll see in a moment that there is a way to make
scripts a lot easier to understand.
The -v option makes log
all activities to the syslog daemon local2
facility.[3][3] If you edit
Specifying the script on the command
line bears a certain risk because users can view a
process's command line with the
ps command. You can avoid this risk by putting
the script in a file such as dial-c3po. You
make read the script from the file instead of the command line
by giving it the -f option, followed by the
filename. This action has the added benefit of making our expect
sequences easier to understand. To convert our example, our
dial-c3po file would look like this:
'' ATZWhen we use a script file in this way, the string we expect to
OK ATDT318714
CONNECT ''
ogin: ppp
word: GaGariN
receive is on the left and the response we will send is on the right.
They are much easier to read and understand when presented this way.The complete pppd incantation would now look like this:
# pppd connect " -f dial-c3po" /dev/ttyS3 38400 -detach \
crtscts modem defaultroute
Besides the connect
option that specifies the dial-up script, we have added two more
options to the command line: -detach, which tells
pppd not to detach from the console and become a background process,
and the modem keyword, which makes it perform
modem-specific actions on the serial device, such as disconnecting
the line before and after the call. If you don't use
this keyword, pppd will not monitor the port's DCD
line and will therefore not detect whether the remote end hangs up
unexpectedly. The examples we have shown are rather
simple; allows for much more complex scripts. For instance, it
can specify strings on which to abort the with an error. Typical
abort strings are messages such as BUSY or
NO CARRIER that your modem usually generates when
the called number is busy or doesn't answer. To make
recognize these messages immediately rather than timing out, you
can specify them at the beginning of the script using the
ABORT keyword:
$ -v ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ...Similarly, you
can change the timeout value for parts of the scripts by
inserting TIMEOUT options.
Sometimes you also need to have conditional
execution for parts of the script: when you
don't receive the remote end's
login prompt, you might want to send a BREAK or a
carriage return. You can achieve this by appending a subscript to an
expect string. The subscript consists of a sequence of send and
expect strings, just like the overall script itself, which are
separated by hyphens. The subscript is executed whenever the expected
string it is appended to is not received in time. In the example
above, we would modify the script as follows:
ogin:-BREAK-ogin: ppp ssword: GaGariNWhen doesn't see the remote system send the
login prompt, the subscript is executed by first sending a
BREAK and then waiting for the login prompt again.
If the prompt now appears, the script continues as usual; otherwise,
it will terminate with an error.