The original and most recent version of this page can be found at the following URL on the Ringlord Technologies site: http://www.ringlord.com/publications/ppp-automation/
Most ppp dial-out tools shipped with Linux these days require relatively little effort to set up and get running. It's with the fine-tuning and the customization beyond what these tools were designed to do that I have run into limitations. As a result I ``went back to basics'', abandoning the fancy GUI stuff and resorting to the pppd and chat programs to accomplish what I needed.
With this document I hope to explain how you, too, can set up an automated and easily controlled ppp dial-up link. In the process you will come to understand that there is no magic and no mystery to a ppp dial-up link: it's quite simple actually, and even easy to understand!
Based on my own needs, this document demonstrates. . .
The following are worth mentioning:
The /etc/ppp/ directory contains most (or all, if you choose) our scripts and configuration files for the ppp link. Here is what I have there. The files created, modified, or otherwise of interest are highlighted as well as commented:
| chap-secrets | |
| ioptions | |
| ip-down | |
| ip-up | |
| ip-up.local | Executed each time the link is established |
| options | The majority of options to configure pppd are stored in this file |
| pap-secrets | |
| peers/ | |
| plugins/ | |
| pppoe.conf | |
| pppoe-server-options | |
| ppp-off | A script to shutdown the connection (kill pppd) |
| ppp-on | A script to bring up pppd to dial out and establish the link |
| ppp-on-dialer | The script to establish the ppp connection with your ISP |
| ppp-myisp.conf | The ISP-specific information |
| resolve.conf |
It may be helpful, at least in the future, to separate out the settings that are definitely different from one ISP to another. It's debatable whether this is really necessary at this point, but I'm myself working towards being able to dial out to a choice of more than one ISP. For whatever it's worth this file summarizes the type of information I would need to save if I wanted to get a PPP running on a windoze box, for example:
| The /etc/ppp/ppp-myisp.conf File |
TELEPHONE=5551212 # The telephone number to dial ACCOUNT=mylogin # The account name with your ISP for logon PASSWORD=mypassword # The password for this account |
| You need to alter the text in italics to match your own ISP setup |
The above simply sets three shell variables (TELEPHONE, ACCOUNT, and PASSWORD); the ppp-on script sources this config file to cause these variables to be set.
In order to being the ppp link up, we could simply execute the following script using the command /etc/ppp/ppp-on & but we'll get around to something niftier once we have this script in place:
| The /etc/ppp/ppp-on File |
#!/bin/sh
#
# Script to initiate a ppp connection. The dialing script creates a temporary
# file into which it writes sensitive information (login name and password) so
# that information cannot be snooped by other system users unless they have
# access to the /etc/ppp/ directory. . .
#
#
# This script must set TELEPHONE, ACCOUNT, and PASSWORD variables
. /etc/ppp/ppp-sprint.conf
if [ -z "$TELEPHONE" -o -z "$ACCOUNT" -o -z "$PASSWORD" ]; then
echo "ERROR: Some or all of TELEPHONE, ACCOUNT, and PASSWORD are not set"
exit 0
fi
# These are the parameters. Change as needed.
LOCAL_IP=0.0.0.0 # Local IP address if known. Dynamic = 0.0.0.0
REMOTE_IP=0.0.0.0 # Remote IP address if desired. Normally 0.0.0.0
NETMASK=255.255.255.0 # The proper netmask if needed
#
# Export the stuff needed by the 'ppp-on-dialer' script
export TELEPHONE ACCOUNT PASSWORD
#
# This is the location of the script which dials the phone and logs
# in. Please use the absolute file name as the $PATH variable is not
# used on the connect option. (The use of a potentially user-alterable
# $PATH by a root-priviliged program would be a security hole).
#
DIALER_SCRIPT=/etc/ppp/ppp-on-dialer
#
# Initiate the connection
#
# The majority of the options are stored in the /etc/ppp/options file,
# which is the first config file that that pppd looks for.
#
exec /usr/sbin/pppd /dev/modem 115200 \
$LOCAL_IP:$REMOTE_IP \
netmask $NETMASK \
connect $DIALER_SCRIPT
|
Note: ``115200'' is the connection rate between modem and computer. Even though a connection may be only 31.2k (31200 baud, about 3 kb/sec) plain text can be compressed significantly and could come in at speeds in excess of 5 kb/sec. If I were to configure the serial port to communicate at a speed less than 5 kb/sec I might throttle connections that could otherwise provide me with much higher throughput!
Note 2: /dev/modem is simply a symlink that I made to my /dev/ttyS1 device. Your physical serial port maybe something other than /dev/ttyS1 and you may even find a /dev/modem already configured on your computer.
The /etc/ppp/options file is the configuration for pppd; pppd looks for its configuration in several places and /etc/ppp/options is the first place. What is specified in this file needs not be given on the command line.
| The /etc/ppp/options file |
# Prevent pppd from forking into the background -detach # Use the modem control lines modem # use uucp style locks to ensure exclusive access to the serial device lock # use hardware flow control crtscts # ask the ISP to supply us with one or two DNS servers; these values # will be written to /etc/ppp/resolv.conf and also passed as DNS1 and # possibly DNS2 to the /etc/ppp/ip-up scripts. usepeerdns # create a default route for this connection in the routing table; if you # have another network (home network, for example) where a default route # exists then you MUST NOT add another default route! There must not be # more than one default route. defaultroute # do NOT setup any "escaped" control sequences asyncmap 0 # use a maximum transmission packet size of 552 bytes mtu 552 # use a maximum receive packet size of 552 bytes mru 552 # Terminate the connection after it has been idle (no traffic) for some time # idle 300 # Dial out on demand when the line is down and traffic is looking to go out # demand |
Note: The ``idle'' and ``demand'' options are commented out: demand dialing requires that you have an IP address that is known before you dial out (which also implies that the route is already setup so that the proper interface (ppp0) is ``woken up'' to start the redialing. Unless you have demand dialing enabled you probably want automatic shutdown of the connection disabled (the ``idle'' option).
This script is invoked by pppd to control the actual dialing and authentication. Notice that it is essentially all one long command line (conveniently broken up over multiple display lines using the \-escape symbol at the end of each display line to prevent the line terminator from being interpreted as a command terminator.
The script will react to BUSY, NO ANSWER, and to multiple RINGING indicators (the latter one would be caused by someone calling you on your dedicated(?) computer line, so you don't necessary want your modem to answer that call (quite yet).
Also, the shell variables TELEPHONE, ACCOUNT, and PASSWORD are used herein:
| The /etc/ppp/ppp-on-dialer script |
#!/bin/sh
#
# This script performs the login authentication with your ISP. Notice that we're
# creating the file /etc/ppp/ppp-chat on the fly; if we passed account/password
# parameters on the command line (which is certainly possible) a savvy user on
# our network could snoop ps(1) to view the chat program's command line parameters
# and discover the login/password at our ISP's. Use of a script avoids that risk.
#
cat >/etc/ppp/ppp-chat <<EOF
TIMEOUT 3
ABORT '\nBUSY\r'
ABORT '\nNO ANSWER\r'
ABORT '\nRINGING\r\n\r\nRINGING\r'
'' \rAT
'OK-+++\c-OK' ATH0
TIMEOUT 30
OK ATDT$TELEPHONE
CONNECT ''
ogin:--ogin: $ACCOUNT
assword: $PASSWORD
EOF
exec /usr/sbin/chat -f /etc/ppp/ppp-chat
|
| The /etc/ppp-off script |
#!/bin/sh
######################################################################
#
# Determine the device to be terminated.
#
if [ "$1" = "" ]; then
DEVICE=ppp0
else
DEVICE=$1
fi
######################################################################
#
# If the ppp0 pid file is present then the program is running. Stop it.
if [ -r /var/run/$DEVICE.pid ]; then
kill -INT `cat /var/run/$DEVICE.pid`
#
# If the kill did not work then there is no process running for this
# pid. It may also mean that the lock file will be left. You may wish
# to delete the lock file at the same time.
if [ ! "$?" = "0" ]; then
rm -f /var/run/$DEVICE.pid
echo "ERROR: Removed stale pid file"
exit 1
fi
#
# Success. Let pppd clean up its own junk.
echo "PPP link to $DEVICE terminated."
exit 0
fi
#
# The ppp process is not running for ppp0
echo "ERROR: PPP link is not active on $DEVICE"
exit 1
|
Before continuing with the next section, please ensure that the following command establishes a connection with your ISP (and sets the correct default route; see /sbin/route):
/etc/ppp/ppp-on & |
and that this command shutsdown the link, causing the previous command to terminate:
/etc/ppp/ppp-off |
If these aren't working, please refer to the ``Linux PPP-HOWTO'' (Redhat maintains a copy of it) and work out the problems until these scripts are working. The preceding is entirely based on that document; the stuff below requires that the above is working.
You now have a way of bringing up and shutting down a ppp link with a script, but that's nothing more than what most GUI tools offer. The real fun starts below, where we'll construct interrelated scripts to. . .
This script enhances the functionality of the /etc/ppp/ppp-on script that we constructed in the preceding section. We rely on the fact that /etc/ppp/ppp-on will not exit (because pppd won't exit) until the connection with the ISP is broken. At that point the /usr/local/bin/ppp-up script regains control and we can decide whether the termination was a scheduled activity or an unscheduled interruption of communications:
| The /usr/local/bin/ppp-up script |
#!/bin/sh
# REDIAL_DELAY should be 0 to redial immediately or a number of seconds
# before redialing is initiated to re-establish the broken connection
REDIAL_DELAY=0
while [ 1 ]; do
if [ -e /etc/ppp/.nwstaydown ]; then
echo "ERROR: ppp link stays down so long as /etc/ppp/.nwstaydown exists"
exit 1
elif [ `/sbin/route -n | grep ppp0 | wc -l` -gt 0 ]; then
echo "NOTE: ppp link is already up according to router table"
exit 0
fi
# bring the ppp link up as requested
/etc/ppp/ppp-on
if [ -e /etc/ppp/.nwforcedown ]; then
echo "ppp link forced down"
rm -f /etc/ppp/.nwforcedown
exit 0
else
echo "WARNING: ppp link terminated unexpectedly; trying to re-establish"
if [ ! "$REDIAL_DELAY" -eq 0 ]; then sleep $REDIAL_DELAY; fi
fi
done
|
You will notice that the script checks at different times for the presence of two files: /etc/ppp/.nwstaydown and /etc/ppp/.nwforcedown; When invoked as part of a scheduled operation to establish a connection (we'll get to the scheduling part below) we could force the network connection not to be established if we create the file /etc/ppp/.nwstaydown.
The /etc/ppp/.nwforcedown file is created by the next script, the one that we use to bring the link down. That file's existence signals us that the shutdown of pppd was intended rather than accidental. We'll just clean up that file and exit.
This script enhances the functionality of the /etc/ppp/ppp-off script that we constructed earlier. This script acts in concert with /usr/local/bin/ppp-up by creating the /etc/ppp/.nwforcedown file so that /usr/local/bin/ppp-up knows that the shutdown of pppd was intentional:
| The /usr/local/bin/ppp-down script |
#!/bin/sh
if [ -e /etc/ppp/.nwstayup ]; then
echo "WARNING: ppp link stays up so long as /etc/ppp/.nwstayup exists"
exit 0
elif [ `/sbin/route -n | grep ppp0 | wc -l` -eq 0 ]; then
echo "ERROR: ppp link is already down according to router table"
fi
# the /root/ppp-up script stops the redialing and exits when pppd exits
# and it sees this file
touch /etc/ppp/.nwforcedown
# kill the pppd
/etc/ppp/ppp-off
|
The presence of the file /etc/ppp/.nwstayup effectively prevents this script from shutting down the link. This is useful to me when I know that the scheduler will take down the link in a few minutes but I still have a download running that I do not want interrupted, or if I want to keep the link up indefinitely for some reason.
As mentioned on numerous occasions above, I like to ensure that my home network is connected to the internet during certain hours of the day. Some in our family get up earlier than I, so this ensures that they don't need to wake me up to connect them. It also ensures that email that has been waiting in their mailbox at our ISP's is delivered by the time they get to the computer. No long delays, no inconveniences. It also means that I can go on vacation and don't have to worry that the bloody spammers fill up my mailbox and cause legitimate and important email to bounce:
| The /etc/crontab entries |
30 0 * * 1,2,3,4,5 root /usr/local/bin/ppp-down 30 7 * * 1,2,3,4,5 root /usr/local/bin/ppp-up 30 1 * * 6,7 root /usr/local/bin/ppp-down 0 9 * * 6,7 root /usr/local/bin/ppp-up |
| Only root can alter the /etc/crontab file |
Unless you're familiar with cron(1) you will probably wonder what the heck you are looking at with those four cryptic lines. Let me explain: There are seven (7) fields on each line. The first five refer to a time, the 6th is a uid, and the 7th (and everything else beyond it) is a command to execute. The five time fields are: minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-7; 0 or 7 is Sunday). And asterisk (*) means everything.
This translates to the following pattern:
The recipe above is easy to adjust if you shutdown the link after midnight (in the wee hours), otherwise you'll have to work out your own scheduling. It doesn't know about holidays or days off from work. :-)
The /etc/ppp/ip-up.local script is executed once the link is established. Since I dial out approximately once a day and redials are relatively rare, I run rdate(1) against a time server to synchronize my system's clock. All the machines on my network then synchronize against my router/gateway. In addition to that I update a static name with my dynamic address so that I can easily find my network at home from anywhere on the internet.
It should go without saying that a firewall setup (ipchains or iptables) is a basic precaution that any networked computer should have installed. Further, telnet and ftp should be replaced with ssh (which also supplies scp for secure file copying). Leaving a network unprotected is risky. But this is not the place to teach you about basic network security. Suffice to have made you aware of it if you weren't already.
Here is an example /etc/ppp/ip-up.local script that may serve you. Of special note is the fact that I'm manipulating the existing /etc/resolv.conf file that primarily supplies to the network subsystem a list of DNS (Domain Name Server) hosts. The script below presumes that you've two name servers operating within your own network (perhaps passive caching servers); it keeps all lines from the existing /etc/resolv.conf file that are not nameserver entries, then adds the name servers obtained from your ISP and then a list of your local name servers. It then ensures that the file is world readable and its permissions and ownership are correct. Just in case. . . can't hurt, right? And finally I trigger sendmail to retry all pending transmissions.
| The /etc/ppp/ip-up.local script |
#!/bin/bash ### create the resolv.conf grep -v 'nameserver' /etc/resolv.conf >/tmp/new-resolv.conf cat /etc/ppp/resolv.conf >>/tmp/new-resolv.conf cat >>/tmp/new-resolv.conf <<EOF nameserver 10.1.8.17 nameserver 10.1.0.24 EOF /bin/chmod go=r /tmp/new-resolv.conf /bin/chown root:root /tmp/new-resolv.conf ### make it current: mv /tmp/new-resolv.conf /etc/resolv.conf /bin/chmod go=r /etc/resolv.conf /bin/chown root:root /etc/resolv.conf ### Process email that's been waiting (overnight) in the queue /usr/sbin/sendmail -q & exit 0 |
Once you have created the various scripts and added the appropriate entries into /etc/crontab (try man 5 crontab for more details on the file's format) your internet connection should be quite persistent while still giving you some control over the whole thing:
The stuff above works for me. I don't know if it will work for you. It's simple enough that the failure points are few and debugging should be fairly straight-forward; to me it seems that this should certainly be easier to figure out than how to make some other tool work whose inner workings I do not understand and which isn't even geared towards automated operations.