Linux PPP

Setting up PPP links with Linux is done with the ppp daemon, pppd. This daemon can establish the physical link, negotiate the ppp Link Control Protocol (LCP), negotiate IP parameters, create a ppp device (ppp0, ppp1...) then configure its parameters and add a route to it. There are many options to pppd, which are described in 'man pppd', but the examples below cover the normal cases.

Example 1: PPP over a fixed serial link

You can run ppp over an RS232 link directly connecting two PCs, like this:
/usr/sbin/pppd cua0 38400 -crtscts local passive persist \
  10.0.0.1:10.0.0.2 netmask 255.255.255.252 
The '\' at the end of the first line is simply to join the two lines together; you can type the whole thing as one line if you prefer. Here is the meaning of each of the parameters:
cua0
The serial port to connect through
38400
The bit rate
-crtscts
Don't use RTS/CTS handshaking. Specify this if your cable doesn't connect the RTS and CTS signals. If it does, specify crtscts instead
local
Don't use the DTR/DCD modem control lines
passive
If the LCP fails to establish a ppp link, don't exit, but hang around silently waiting for the other end to initiate the link. Otherwise you would have to start the pppd at both ends within 60 seconds of each other, to prevent the first one from timing out.
persist
If the link is lost, don't quit but try to re-establish the connection.
10.0.0.1:10.0.0.2
The local (near-end) and remote (far-end) IP numbers. You can omit these if they have already been set at the far end, since pppd will negotiate them.
netmask 255.255.255.252
The netmask for the link, in this case for a /30 net. This can be omitted if a subnet has not been allocated for the link.
As you can see, pppd tends to need a very long command line. If you are running the same pppd command over and over again, you can just put it into a shell script. For example, create a file /usr/local/bin/go-ppp
#!/bin/sh
/usr/sbin/pppd cua0 38400 -crtscts local passive persist \
  10.0.0.1:10.0.0.2 netmask 255.255.255.252 
then make it executable by
chmod a+x /usr/local/bin/go-ppp
Then typing 'go-ppp' will bring up your ppp connection.

Example 2: PPP dial-out to the Internet via a modem

/usr/sbin/pppd cua0 38400 crtscts modem lock defaultroute \
  connect '/usr/sbin/chat -v -f /usr/local/etc/isp.chat'
In this case, here is the meaning of each of the parameters:
cua0
The serial port to connect through
38400
The bit rate
crtscts
Use RTS/CTS flow control
modem
Use DTR/DCD modem control signals. This is so that if you kill pppd the modem connection will be dropped, and also so that pppd can tell if the remote modem has dropped the connection.
lock
Create a 'lock file' in /var/lock to allow shared access with uugetty.
defaultroute
When the ppp link has been brought up, automatically add a default route to the far end (this would be appropriate if the far end is an Internet Service Provider)
connect '/usr/sbin/chat -v -f /usr/local/etc/isp.chat'
Give a command to establish the physical link. In this case we use the 'chat' program to send AT commands to the modem. The '-v' flag causes verbose logging of the chat sequence to /var/log/messages.

No IP numbers are given because we assume that they will be allocated by the other end. The file /usr/local/etc/isp.chat will look something like this:

ABORT BUSY ABORT 'NO CARRIER' ABORT 'NO DIALTONE'
TIMEOUT 5
"" AT OK-AT-OK ATDT123456
TIMEOUT 60
CONNECT "" in:--in: username word: \qpassword
This is a chat script, a sequence of expect...send...expect...send strings. The 'ABORT' commands give strings which, if seen, cause the script to abort immediately. The 'TIMEOUT' commands set the timeout period for subsequent expect strings.

Replace the phone number, username and password as appropriate. '\q' in front of the password prevents it being stored in the chat script debugging output. Since the chat script contains a password you should make the file unreadable by anyone but 'root':

cd /usr/local/etc
chown root isp.chat
chmod 600 isp.chat
To terminate the ppp connection, send a terminate signal to the pppd process. This is most easily accomplished by typing:
killall pppd
which will terminate all pppd processes running on your system.

Example 3: PPP dial-out with automatic re-establishment

If you need a dial-up Internet link to stay constantly available, but poor quality phone lines mean that the link tends to drop, you can create a script which will automatically redial if the link fails. This can be used to create a pseudo-leased line where a leased line is not actually available.
#!/bin/sh
{
while [ "x" ]; do
  /usr/sbin/pppd cua0 57600 modem crtscts lock -detach defaultroute \
    connect '/usr/sbin/chat -v -f /usr/local/etc/isp.chat'
  sleep 3
done
} &
This script runs pppd as usual. However the -detach flag prevents it running in the background as it normally does, so the script does not continue until pppd terminates. At this point we wait 3 seconds then go round in a loop to re-establish the link. The {...}& construction makes the script as a whole go into the background.

This type of behaviour is most useful when you get a fixed IP number from your ISP; this means that when you dial back in after the link drops, existing TCP sessions can continue where they left off. If you get a dynamic IP number, the chances are that your IP number will be different the next time you dial in, and all TCP connections using the old IP number will be permanently stuck.

Example 4: creating a dial-in PPP account

In order to have people dial into your system with PPP, first you must have your system accepting incoming calls through your modem (with 'uugetty'). Then you need to create a login account for each user, which starts pppd running once they have entered their username and password.

The Slackware 3.1 'adduser' command is not suitable for this since if you specify a home directory such as '/tmp' it alters the permissions on that directory. The next version of Slackware will incorporate the much better 'useradd' command:

useradd -s /usr/sbin/pppd -d /tmp pppuser
If you don't have this, edit the /etc/passwd file directly and add a new line at the end:
pppuser::547:100::/tmp:/usr/sbin/pppd
where 'pppuser' is the name you have chosen for your ppp account, and '547' is the first unused userID in the passwd file. In either case you also need to set the account's password:
passwd pppuser
Note that because pppuser is an account on the system, it will automatically also be able to receive mail as pppuser@your.domain, and the user can collect it using POP3. If you don't want this to happen, choose a username which contains at least one upper-case letter.

Finally, you need to allocate IP numbers for each line, since you don't want users to be able to pick their own IP numbers at random. By allocating one IP number per line, if you have more than one line you effectively have dynamic IP allocation (since the IP number received by the user depends on which line they connect on).

To set up the parameters for dial-in IP, create a file /etc/ppp/options.ttyS0 for each line (where ttyS0 is the device name for the line in question). It should contain:

10.0.0.1:192.168.0.1 crtscts modem lock
where 10.0.0.1 is the local IP number (you can use your machine's ethernet IP number if you like), and 196.168.0.1 is the number you are allocating to the far end.

If you have an ethernet (say 206.27.238.0/24) with spare IP numbers, you can 'steal' individual numbers from it using Proxy ARP:

206.27.238.1:206.27.238.45 crtscts modem lock proxyarp
In this case, 206.27.238.1 is the IP number of the server, and 206.27.238.45 is an unused number on the network. This number is allocated to the dial-in user. Routing works because the server responds to ARP requests for that number from any other device on the ethernet.

If you need to create accounts with static IP numbers, you should create a separate home directory for each user, e.g. /home/pppuser, and create a file .ppprc in that directory which contains the IP number options specific to that user.


Red Hat 4.1 note: ppp accounts won't work straight away, because the pppd program needs root privileges to operate. You can give pppd root privileges, but then you open a security hole by allowing all users to dial out with pppd too. One solution is to run pppd as root, but limit its access to one particular group of users:
chown root.dip /usr/sbin/pppd
chmod 4750 /usr/sbin/pppd
usermod -G dip pppuser
The first two lines set pppd to be run suid root, but it can only be run by root and members of group 'dip'. The last line modifies account 'pppuser' so it is in supplementary group 'dip', i.e. in addition to its normal privileges, it can also access files in group 'dip'. You would do this for all accounts which require access to pppd.

'dip' (for "dial-up IP") is a group which already exists in Red Hat. If you want to create a new group, either use 'groupadd' or edit the file /etc/group directly.


Debugging PPP connections

If a ppp connection fails to work, you can get pppd to log additional information by adding 'debug' to the command line. Look for the messages generated in /var/log/messages. 'chat' will also log messages here if the -v flag is given on its command line.

SLIP over a fixed link

It is also possible to run SLIP over a fixed serial link. Since SLIP is a very simple protocol, with no link management facilities, this can be convenient if you have an unreliable link which keeps going up and down. If it's a leased line modem link you can configure the modems to keep trying to reconnect; the computer will never even know that the link has been lost, so the interface will remain configured.

Red Hat doesn't have the 'slattach' utility which would normally be used to configure a fixed line SLIP connection. Instead, you can use 'sliplogin' (which would normally be used as a login shell for dial-in SLIP accounts), by making up a login name for that line. Let's say we use "Sisp". Add a line into /etc/slip/slip.hosts:

Sisp 10.0.0.1 10.0.0.2 255.255.255.252 compressed -1
Where 10.0.0.1 is the local IP number, 10.0.0.2 is the remote IP number, 255.255.255.252 is the netmask, and you can replace "compressed" with "normal" if the other end doesn't support CSLIP.

Then configure the line and start SLIP running:

stty 38400 crtscts clocal -hupcl </dev/cua0
sliplogin Sisp </dev/cua0
sliplogin should automatically configure the interface and add the routing entry (check by typing "ifconfig" then "netstat -rn"). To terminate it, you manually kill the sliplogin process.

If you are using a serial cable which doesn't support RTS/CTS flow control, replace "crtscts" with "-crtscts" in the stty command.


Last updated 27 Mar 1997