Inside Linux The following shows a sample nfs (Web hosting services)

Inside Linux The following shows a sample nfs script. # . /etc/rc.config nfs=no while read where what type options rest ; do case “$where” in #*|”") ;; *) case “$options” in *noauto*) ;; *) if test “$type” = “nfs” ; then nfs=yes break fi ;; esac esac done < /etc/fstab case `uname -r` in 0.*|1.*|2.0.*) RPCSTATD="" ; RPCLOCKD="" ;; *) test -x /usr/sbin/rpc.kstatd && RPCSTATD=/usr/sbin/rpc.kstatd test -x /usr/sbin/rpc.klockd && RPCLOCKD=/usr/sbin/rpc.klockd ;; esac return=$rc_done case "$1" in start|reload) test "$nfs" = "yes" || exit 0; test -n "$RPCLOCKD" && startproc $RPCLOCKD test -n "$RPCSTATD" && startproc $RPCSTATD echo -n "Importing Network File System (NFS)" mount -at nfs || return=$rc_failed sleep 1 ldconfig -X 2>/dev/null echo -e “$return” ;; stop) test “$nfs” = “yes” && echo -n “Remove Net File System (NFS)” umount -at nfs & sleep 2 test “$nfs” = “yes” && echo -e “$return” ;; restart) $0 stop && $0 start || return=$rc_failed ;; status) mount -t nfs | while read from x point rest ; do echo -e “$from 33[50G$point” done ;; *) echo “Usage: $0 {start|stop|status|reload|restart}” exit 1 esac test “$return” = “$rc_done” || exit 1 exit 0 As mentioned previously, mountd is the mount daemon and nfsd is the NFS server daemon. On your distribution, the daemons may be named rpc.mountd and rpc.nfsd. Be sure to check the documentation for your Linux distribution. Remember, the portmapper must be invoked and running before the mountd and nfsd daemon. Exporting Filesystems There is no broadcast of available filesystems by the server to NFS clients. The NFS server maintains a list of exported filesystems and the restrictions that are applicable for each export, called the filesystem table. When a mount request is received from an NFS client, the NFS server checks the request against its filesystem table. If the filesystem is in the list and the restrictions are satisfied, the server permits the mount. The filesystem table and the contents of the /etc/exports file can be different. The NFS server creates the filesystem table from the contents of the /etc/exports file at the time that it initializes. The filesystem table is not updated by the NFS server unless the system is rebooted or the exportfs command is executed. page 220 #BREAK# Inside Linux The exportfs command is used to maintain the table of exported filesystems. On some Linux distributions, the table exists as the /var/lib/nfs/xtab file. Unfortunately, not all Linux distributions have the exportfs command installed. If you do not have one, you can create a script to perform the logic. The following demonstrates the minimum for the script: #!/bin/bash killall -HUP /usr/sbin/rpc.mountd killall -HUP /usr/sbin/rpc.nfsd Be sure that the command name for each daemon is correct for your Linux distribution and that the directory path is appropriate. The HUP signal is sent to the daemons, effectively telling them to reinitialize. The net effect is that the /etc/exports file is read from disk by the NFS server and the filesystem table is regenerated. For some Linux distributions, the rcnfsserver command can be executed to update the filesystem table if changes have been applied to the /etc/exports file. A man page may not exist for this command, so do not count on using that method for verification of rcnfsserver. For example, for the installed version of SuSE Linux 6.3 (on my machine), no man entry exists for rcnfsserver, but executing the which command reveals the file’s existence, as shown in the following dialog: stimpy $ man rcnfsserver No manual entry for rcnfsserver stimpy $ which rcnfsserver /usr/sbin/rcnfsserver stimpy $ rcnfsserver Usage: /usr/sbin/rcnfsserver {start|stop|status|reload|restart} stimpy $ Another method of updating the filesystem table is to stop and start the daemons using the nfs command. The following dialog demonstrates this: stimpy $ cd /etc/rc.d/init.d stimpy $ nfs stop stimpy $ nfs start stimpy $ If the restart option is available for the nfs command, you can invoke the command that way, as in the following dialog. The previous section, “The mountd and nfsd Daemons,” discusses the nfs command in more detail. stimpy $ cd /etc/rc.d/init.d stimpy $ nfs restart stimpy $ Before you create any script to force a reread of the /etc/exports file, check to see if either the exportfs or rcnfsserver command exists. Using the NFS Client There is not much to using an NFS client. The only requirements are that an NFS server is running, that at least one filesystem exists to mount, and the proper restrictions are satisfied. You use the mount command to import a filesystem. This is what the term “NFS client” refers to. The mount command is used to execute a request to the NFS Server for importing a remote filesystem. The basic usage for the mount command is shown in the following: mount -t type device dir This tells the system to attach (or mount) the filesystem found on device (device), which is of type type, at the dir directory. Conversely, you use the umount command to unmount (or detach) the filesystem. The following dialog demonstrates the use of the mount command to import an NFS filesystem: stimpy $ mount -t nfs sillyhost:home/bill /home/bill Some distributions of Linux prefer that you execute the mount command with the -F option, as shown in the following dialog: stimpy $ mount -F nfs sillyhost:home/bill /home/bill Be sure to check the mount man page for the proper syntax for your Linux distribution. page 221 #BREAK# Inside Linux To enforce that the system mounts an nfs filesystem at boot, you should edit the /etc/fstab file as usual. You should ensure that the -t nfs type is specified. In the following dialog, the contents of the /etc/fstab file shows an entry to mount an nfs type filesystem. stimpy $ cat /etc/fstab /dev/hda7 swap swap defaults 0 0 /dev/hda6 / ext2 defaults 1 1 /dev/hdc /cdrom iso9660 ro,noauto,user,exec 0 0 /dev/hda5 /mnt/rh ext2 defaults 1 1 /dev/fd0 /flop auto noauto,user 0 0 sillyhost:home/bill /home/bill nfs rsize=8192,wsize=8192,timeo=14,intr 0 0 none /proc proc defaults 0 0 Using our previous example, the sillyhost… entry will be automatically mounted at system boot. This sample should work for most all Linux distributions. You should always check the documentation for your distribution to be certain. You can also easily mount a filesystem by specifying the mount point, if the device is listed in the /etc/fstab file. For example, referring to the previous /etc/fstab sample, if you want to mount the /dev/hda5 device, you simply issue the mount command as shown in the following dialog: stimpy $ mount /mnt/rh stimpy $ Because the entry exists in the /etc/fstab file, all the proper parameters are available to mount the device to the identified mount point. From here, all you do is access the filesystem as you normally would with any mounted filesystem. The mount Command The following section details the mount command. The mount command, these days, consists of many options. I hope to clarify the usage for mount. The official usage for the mount command is shown as follows: mount [-hV] mount -a [-fFnrsvw] [-t vfstype] mount [-fnrsvw] [-o options [,…]] device | dir mount [-fnrsvw] [-t vfstype] [-o options] device dir As you can see, four variant usages exist for the mount command, each one for a specific application. All UNIX and Linux files are organized within a filesystem that is a hierarchical tree starting at /, known as root. This is not to be confused with the root user. Normally, the filesystem consists of more than one device; the mount command is used to import (or attach) these devices to the root filesystem. To unmount a filesystem, you use the umount command. The most common form of usage for mount is as follows: mount -t type device dir This execution mounts the device device of type -t type onto the dir directory. The local directory (mount point) becomes the root of the mounted device. Ironically, four usages for the mount command do not perform a device mount. They are as follows: mount -h mount -V mount [-t type] mount The first form prints only help text associated with the mount command. The second form displays the version of mount and exits. The third form of mount lists all the filesystems of the type identified that are mounted. The last form lists all the filesystems that are mounted. The form of the identified device is a block special device by filename. Some examples are /dev/hdc for a CD-ROM and /dev/fd0 for a floppy disk. Another example is /dev/hdb11 representing the tenth logical drive on the second IDE hard drive or /dev/hda5 representing the fourth logical drive on the first hard disk (these do exist on my system). You are not restricted to identifying a device as previously shown. You can also identify devices as some.domain.name:/directoryName. page 222 #BREAK# Inside Linux You can add devices that are continually mounted at boot to the /etc/fstab file. The /etc/fstab file can be helpful in several ways. If an entry for a device exists in the file, you can mount it manually by specifying only the device or the mount point. The following example demonstrates this. The first dialog shows an entry in the /etc/fstab file: stimpy $ cat /etc/fstab … /dev/hda5 /mnt/rh ext2 defaults 1 1 … Assuming that the /dev/hda5 entry exists as shown, you can mount the device onto the /mnt/rh directory by issuing one of the two following mount commands: stimpy $ mount /dev/hda5 stimpy $ mount /mnt/rh You do not need to specify the device type, device, and mount points because this information is already specified in the /etc/fstab file. Customarily, the superuser (root) is the only user that can execute the mount command. With the /etc/fstab file, however, you can use the user option, allowing anyone to mount the corresponding device. You should know that only the user that mounted the device is allowed to unmount the device. If you want any user to be able to unmount a device, you should use the users option rather than the user option. Options for mount A whole host of options are available for the mount command. In this section, I explore the options available, providing descriptions for each. Table 12.4 outlines the various options available to you. Table 12.4. Options for the mount Command Option Description -V Show the version. -h Show a help message. -v Verbose mode. -F This option will fork an individual invocation of mount for each device. The advantage is speed. If you are mounting NFS devices, the timeouts will be concurrent. The downside is that the order of mounts is arbitrary. -f This option is a sort of “test” (or fake) mode. If you are having problems with mount, this option acts as a debugger (use with the -v option). -n Perform the mount and exclude writing the entry in /etc/mtab. -s Mainly used for the Linux autofs-based automounter. This tells mount to allow for awkward mount options versus failing. -r Mount the filesystem as read-only; synonymous with the -o ro option. -w Mount the filesystem as read/write; synonymous with -o rw. This is the default. -L label Mount the partition possessing the specified label. -U uuid Mount the partition possessing the specified uuid. -t vfstype This option identifies the filesystem type. The currently supported filesystem types are (shown in linux/fs/filesystems.c) adfs, affs, autofs, coda, coherent, devpts, ext, ext2, hfs, hpfs, iso9660, minix, msdos, ncpfs, nfs, ntfs, proc, qnx4, romfs, smbfs, sysv, ufs, umsdos, vfat, xenix, xiafs. The coherent sysv, and xenix types are equivalent. Both the coherent and xenix types will be removed sometime in the future. page 223 #BREAK# Inside Linux Option Description -o Options are specified with a -o flag, using a comma to separate the options. The options are: atime Update the inode access time for every access; the default. auto Specify that the mount is acceptable with the -a option. defaults Use the default options, which are rw, suid, dev, exec, auto, nouser, and async. dev Interpret character or block special devices. exec Allow execution of binaries. noatime Do not allow updates to the inode access times on the filesystem. noauto The filesystem can only be explicitly mounted. nodev Do not interpret character or block special devices. noexec Disallow the execution of binaries on the mounted filesystem. nosuid Disallow set-user-id or set-group-id bits to occur. nouser Prohibit a non-root user to mount the filesystem; this is the default. remount Used to attempt a remount of an already mounted filesystem. Used to change the mount flags for a filesystem. ro Mount the filesystem as read-only. rw Mount the filesystem as read/write. sync Synchronize I/O to the filesystem. user Permit an ordinary user to mount the filesystem; implies the options noexec, nosuid, and nodev. The man page for the mount command provides more level of detail for filesystem-specific mounts. Be sure to refer to it for any special needs you may have. page 224 #BREAK# Inside Linux Optimizing NFS on Low-Bandwidth Connections So many variables are at work when you analyze network activity that a whole chapter can be written about it. This section touches on only three options for adjusting the performance of NFS on low- bandwidth connections. The section is short and sweet to keep things simple. Admittedly, the NFS protocol is a sluggish protocol. Therefore, if you throw NFS over a sluggish line such as a modem or ISDN line, expect poor performance. Some of the TCP/IP protocols, such as FTP, are quicker than NFS. The advantage to using NFS is that you do not have to copy files back and forth as you do with FTP. You access the mounted filesystems as if they were native to the machine. You will have to adjust the NFS parameters to allow its use over sluggish lines. If you do not adjust the settings, NFS will report errors. First, you should refrain from using the soft mount option, because timeouts will begin to surface. Using the hard mount option will force retries. Two other options need to be altered: retrans and timeo. The format for retrans is retrans=n, in which n is a number. This number represents the number of times to repeat a request before the request is aborted. The format for timeo is timeo=n, in which n is a number. This number represents the RPC timeout period in tenths of a second. The default value is vendor specific, normally ranging from 5 to 10 tenths of a second. Under Linux, the default value is 7 tenths of a second. If a reply does not occur within the time identified by timeo, a minor timeout has occurred. At this time, the timeo value is doubled and the request is re-sent. This process continues until the retrans count is reached. If the client does not receive a reply, a major timeout has occurred. What, then, is the general rule? You should concentrate on varying the timeo value versus the retrans option. Increasing the retrans value will generate more requests to the NFS server, which creates a load on the server. Generally, doubling the timeo value will solve timeout issues. Summary In this chapter, you explored the use of the Network File System (NFS), beginning with an overview of NFS, developed by Sun Microsystems, which advertises an installed base of about eight million systems. NFS is a protocol used for file sharing. NFS consists of a client program and the server program. The NFS server responsibility is to export a file or directory. The NFS client then mounts the required filesystem. Next, I discussed the NFS client, including the automounter. The automounter, which is a client-side enhancement, provides the functionality to automatically mount a filesystem. When the operation is complete, the automounter unmounts the device. The NFS server was discussed next. The role of the NFS server is to make filesystems available by exporting them. I then covered setting up the NFS server, including the portmapper, mountd, and nfsd daemons. The /etc/exports file was covered, which contains the filesystems that the NFS server can export to clients. The NFS client was covered, consisting of the mount command. The success of the mount command is dependent on a running NFS server and a filesystem that can be mounted. Finally, the mount command was discussed in a fair amount of detail. page 225 #BREAK# Inside Linux Chapter 13. Dial-Up Networking Services: SLIP and PPP Linux provides two protocols for serial-line connectivity. Specifically, connectivity is through a modem, whether it is an asynchronous, an ISDN, or a synchronous modem. The two protocols are Serial Line Internet Protocol (SLIP) and Point-to-Point (PPP). Both protocols provide the functionality to establish connectivity with a remote system. The connection is made to an Internet service provider (ISP) or through a gateway. The first part of this chapter focuses on the SLIP protocol. The last part of the chapter examines PPP in detail. Serial Line Internet Protocol (SLIP) In this first section, we examine SLIP in detail. Although PPP is the more widely used dial-up protocol, SLIP continues to be a contender and is supported by most public and private ISPs. We begin the SLIP journey with a brief overview and then jump into the configuration and use of SLIP. SLIP Overview The only hardware requirements for SLIP are a serial port with a FIFO buffer and a modem. If you are using an older computer - an 80286 (or compatible), for example, you may want to check your serial port UART chip set. At a minimum, you want to have a 16550 UART. SLIP supports the TCP/IP protocols over a serial line, whether it’s over a dial-up phone line or a dedicated leased line. You should contact your ISP to obtain the configuration requirements for SLIP connectivity with their system. Configuring SLIP is a fairly straightforward task, and you should be up and running with a minimal amount of fuss. Logically, the network for a SLIP connection consists of only two machines: the SLIP server (provided by your ISP) and the SLIP host, which is your end. We refer to SLIP as a point-to-point network connection because only two endpoints are within the network. Think of SLIP (and PPP) in the same light as the phone system. You pick up your receiver and dial the destination phone number. When your party answers at the other end of the line, a network connection is established. This is also considered a point-to-point connection. If either end disconnects, the network connection is broken. When a connection is established from the host to the server, a logon sequence is initiated to verify your identity. After the verification process is complete, the server furnishes an IP address for your host. This IP address can either be dynamic or static. If the address given to your host is a static address, that address is the same every time you establish a SLIP connection. If your SLIP server provides for dynamic IP addresses, every time you establish a SLIP connection your host will receive a different IP address. The SLIP server will output the IP addresses (among other data) that are assigned for the current session. The Dial-Up IP Protocol (dip) program can capture the dynamic IP address and configure the SLIP driver automatically. The dip program is used to simplify connectivity to the SLIP server. We discuss the use of dip in a section that follows. Some information that you must have available, if you’re using a dial-up connection, includes the ISP’s phone number, the authentication type, whether your ISP provides static or dynamic IP addresses, the ISP domain name, the DNS address list, whether the ISP uses a default gateway or a static gateway, and the maximum connection speed provided by the ISP. If your ISP is using static IP addressing, you will need the IP address assigned to your host. Also, if your ISP is using a static gateway, be sure to obtain the address for it. Beginning with the next section, we discuss the specifics of SLIP configuration under Linux. page 226 #BREAK# Inside Linux SLIP Preflight Checklist Setting up your Linux system to enable SLIP is fairly easy. SLIP configuration is a one-time setup; you should not have to change any of your settings unless you switch to another service provider or your service provider’s configuration changes. In the following sections, we discuss the prerequisites that must be addressed before jumping into the actual use and setup of SLIP. We also examine the various configuration files and requirements of TCP/IP networking to enable SLIP. Verifying the Loopback Interface The loopback interface, sometimes called the dummy interface, is used to provide an IP address for your machine, provided that the only network interface you are using is SLIP or PPP. Also, some applications require the loopback interface in order to run. In addition, other TCP/IP services require an IP address to be functional. If your machine is part of a real ethernet network, the loopback interface is not required. The loopback interface is specified by the network name lo - that is, LO is lowercase. To activate the loopback interface, the ifconfig command is used. The IP address that is designated for loopback is 127.0.0.1; this is an address designated by the InterNIC as reserved for no entity. The syntax for the ifconfig command is ifconfig interface [aftype] options | address … To enable the lo interface with the address 127.0.0.1, you invoke the ifconfig command, as shown in the following dialog: stimpy $ ifconfig lo 127.0.0.1 This will execute ifconfig and its result will be to assign the IP address 127.0.0.1 to the loopback address. You can obtain the status of any active interfaces by invoking ifconfig without any arguments. Check the man page for ifconfig for a complete rundown of options. The following shows the output of an ifconfig inquiry: stimpy $ ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:3924 Metric:1 RX packets:25 errors:0 dropped:0 overruns:0 frame:0 TX packets:25 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 ppp0 Link encap:Point-to-Point Protocol inet addr:32.100.174.75 P-t-P:32.96.116.18 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:15 errors:0 dropped:0 overruns:0 frame:0 TX packets:17 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 stimpy $ The ifconfig command responds that two interfaces are active: lo and ppp0. Next, you should verify the contents of your /etc/hosts file for the loopback entry. The following is the contents of an /etc/hosts file: # hosts This file describes a number of hostname-to-address # mappings for the TCP/IP subsystem. It is mostly # used at boot time, when no name servers are running. # On small systems, this file can be used instead of a # “named” name server. # IP-Address Full-Qualified-Hostname Short-Hostname 127.0.0.1 localhost The name is not necessarily important as long as you map the corresponding interface name to the logical hostname. Verifying /etc/resolv.conf File The /etc/resolv.conf file is used for name resolution. Entries found in this file designate a DNS server and its associated IP address. More than one DNS server can be specified in this file. As mentioned previously, your ISP can provide you with the DNS server(s) and their associated IP address. The following is sample output from a /etc/resolv.conf file: # /etc/resolv.conf nameserver 165.87.194.244 nameserver 165.87.201.244 page 227 #BREAK# Inside Linux The /etc/resolv.conf file identifies the DNS servers that the resolver can contact to resolve hostnames. You can also set up your Linux to use DNS locally. Many Linux power users do this because it can cut down on name-resolution traffic from your host to the server (and vice versa). Doing this will provoke your DNS to cache DNS lookups, thereby decreasing accesses to the remote DNS for name resolution. Setting Up SLIP As mentioned previously, SLIP is used to establish a network connection between two machines: the server (remote machine) and the host (your machine). SLIP is so firmly entrenched that most ISPs support the protocol. A number of variations of SLIP exist, most notably CSLIP. CSLIP is a compressed version of SLIP that utilizes the Van Jacobson header-compression algorithm on outbound IP packets. The result is increased throughput, especially for interactive network sessions. Before implementing CSLIP, check with your ISP because most ISPs do not support CSLIP. Although SLIP is easy to configure and use, the core mechanism can seem complicated. For most distributions of Linux, the SLIP driver is an integral part of the kernel. This provides faster response and is more efficient. A special tty line discipline, SLIPDISC, is used to convert the specified serial line to SLIP mode. Under this discipline, the serial line cannot be used for any other purpose, other than to communicate with SLIP-aware applications. Effectively, any non-SLIP applications are blocked from using the device when SLIP is active. To establish a SLIP network connection, a pair of programs are utilized, specifically slattach and dip. You cannot use a generic communications application to dial up a remote SLIP server and establish a network connection. Both slattach and dip are used collectively to initiate and establish a SLIP network connection on a serial device using special system calls. The slattach command is used to convert a specified serial line to SLIP mode. Subsequently, the dip command is used to establish the network connection, login negotiation, and to initiate the SLIP connection on the serial line. Using slattach The following shows the syntax for the slattach command: slattach [option] [-c command] [-p protocol] [-s speed] [tty] Several options are available, such as enabling debug output and operating in quiet mode. Check the slattach man page for more details. The -c command switch is used to execute the specified command after the line is hung up (disconnected). This can be utilized to run one or more scripts or to automatically maintain (reestablish) a network connection if the line was severed. The -p protocol switch identifies the protocol to use for the serial line. For many versions of slattach, the default value is cslip (compressed SLIP). Other values that can be specified are adaptive (adaptive CSLIP/SLIP), kiss (a special protocol used to communicate with AX.25 packet radio terminal node controllers), ppp (Point-to-Point Protocol), slip (standard SLIP), and tty. The tty argument is used to return the serial device back into normal serial operation. Do not use the ppp argument to establish a PPP network connection, because PPP requires the pppd daemon to be active on the specified serial line. The adaptive option leaves it to the kernel to decide the type of SLIP protocol that the remote end uses. The -s speed switch simply designates a line speed to be used for the serial device. The following dialog switches /dev/cua3 to assume SLIPDISC line discipline and then attaches the device to the next active SLIP network interface: stimpy $ slattach /dev/cua3 & stimpy $ This assumes that the modem is on /dev/cua3. If no active SLIP connections exist, the line is attached to sl0 (that’s SL0, not S10). The second SLIP connection will be attached to sl1, and so on. Most Linux kernels support up to eight simultaneous SLIP links. page 228 #BREAK# Inside Linux As mentioned previously, the default protocol for slattach assumes CSLIP. The following dialog demonstrates invoking slattach to use normal SLIP: stimpy $ slattach -p slip /dev/cua3 & If you’re not sure which protocol option to use (SLIP or CSLIP), it is recommended to use adaptive because this leaves the decision to the kernel. You may have noticed in the dialogs that the ampersand (&) is used to put slattach into the background. Obviously, if you are invoking slattach from a terminal, you will want that terminal back. Otherwise, slattach will rob the terminal until such time that slattach is terminated. You can terminate slattach using the kill command - simply use the ps command to locate the process ID for slattach. The slattach command is not specific to SLIP. You can use slattach to enable other TCP/IP protocols such as KISS and PPP. Using ifconfig and route After we have a SLIP connection and we have associated our serial device for SLIP usage, we must configure the network interface. This is done the same as with any other (normal) network connection. The two commands we use for this purpose are ifconfig and route. The ifconfig command is used to configure the network interfaces. It is used at boot time to set up the required interfaces. The ifconfig command can be used from the command line, which is usually done only during debugging or testing, or during system tuning. If you execute ifconfig with no arguments, ifconfig shows the status of any active interfaces. If a single interface argument is given, it displays the status of the given interface only; if a single -a argument is given, it displays the status of all interfaces, even those that are down. If you recall from the earlier section “Verifying the Loopback Interface,” we used ifconfig to configure the loopback interface. We repeat the syntax here to jog your memory: ifconfig interface [aftype] options | address … The route command is used to manipulate the IP routing table. The core functionality of route is to set up the static routes to specific hosts or networks via an interface. This interface should have already been configured with the ifconfig command. To add a route to the table, use the following syntax for route: route [-v] [-A family] add [-net|-host] target [netmask Nm] [gw Gw] [metric N] [mss M] [window W] [irtt I] [reject] [mod] [dyn] [reinstate] [[dev] If] To delete a route from the table, use the following syntax for route: route [-v] [-A family] del [-net|-host] target [gw Gw] [netmask Nm] [metric N] [[dev] If] After control of the line is in possession of the SLIP driver, the network interface will have to be configured. You configure the network interface using the ifconfig and route commands. Let’s assume that the host is stimpy and we dialed a server with the name ren. The following dialog shows the commands to execute: stimpy $ ifconfig sl0 stimpy pointopoint ren stimpy $ route add ren As you can see, the first command configures the (first serial) interface as a point-to-point link to ren. The second command, route invocation, adds the machine ren to the routing tables. Some implementations of Linux may require that you identify the device (with the dev option) to the route command. To take down the interface, use the same commands but in reverse order. For example, you first execute route to remove the entries from the routing tables. Second, you execute ifconfig to take down the serial interface. Finally, you need to terminate the slattach process. You can run the ps command to locate the process ID for the running slattach process and then issue the kill command to terminate it. For example, the following dialog demonstrates the commands to execute and the order in which to execute them: stimpy $ route del ren stimpy $ ifconfig sl0 down stimpy $ ps a | grep slattach 4918 p1 S 0:00 slattach /dev/cua1 stimpy $ kill 4918 In the next section, we take a look at the dip command, which is the Dial-Up IP Protocol driver. page 229 #BREAK# Inside Linux Using dip for SLIP Automation Looking back on the last sections, you are probably thinking, “Getting connected is fairly easy, but I’d like to automate that whole process.” Well, that is what computers are all about, right? And Linux offers just the program for you; the program is called the Dial-Up IP Protocol (dip). In this section, we explore the use of dip and how it can help with automating the SLIP process. The dip command supports the processing of a chat script, allowing you to specify a command-response dialog to help with dialing, connecting, and the login process. You can also include commands to automate the setup of the SLIP network interface and establish entries to the kernel routing tables. The following shows the syntax for dip, in its most general form: dip [options …] [script file] A lot of supporting information is given in this section for the dip command. A sample dip script is supplied at the end of the section, preceded by a variables list and a command list. But first, Table 13.1 lists the most common command-line arguments to dip. Table 13.1. Common dip Command Arguments Switch Description -a Prompt for username and password. -i Act as a dial-in server. -k Kill the dip process that has locked the specified tty device or the most recent invocation of dip. -l line Indicate the line to be killed. -m mtu Set the Maximum Transfer Unit (MTU); the default is 296. -p proto Set the line protocol to be one of these: SLIP, CSLIP, SLIP6, CLSIP6, PPP, or TERM. -t Run dip in test (interactive or command) mode. -v Set verbose mode. This enables debug output to include echoing of each line of the script. As you can see, dip can also be used as a dial-in server, as represented by the -i switch. The dip command can also be invoked in interactive mode (or command mode), as designated by the -t switch. This allows you to participate in the dial-up and login process, allowing you to record the prompts and responses required to establish a modem connection. You can then use the results and establish a script file to automate the process. Table 13.2 lists the commands supported by dip. Simply type the command, plus any required arguments, and press Enter. These commands can be included in a chat script or executed while you are in command mode: Table 13.2. Common dip Commands Command Description label: Defines a label. beep [times] Beeps on user’s terminal [times] times. bootp [howmany [howlong]] Uses the BOOTP protocol to fetch both local and remote IP addresses. Break Sends a BREAK. chatkey keyword [code] Allows you to add to dip’s modem response words. config [interface|routing][pre|up|down|post] Stores interface configuration {arguments…} parameters. databits 7|8 Sets the number of data bits. page 230 #BREAK# Inside Linux Command Description dec $variable [decrementvalue|$ variable] Decrements a variable; the default is 1. Default Instructs dip to set the default route to the remote host it connected to. dial phonenumber [timeout] Transmits the string in the init variable as the modem initialization string and then dials the specified number. The default timeout is 60 seconds. Dip will parse any strings returned by the modem and will set $errlvl accordingly. The standard codes are as follows: 0 - OK, 1 CONNECT, 2 - ERROR, 3 - BUSY, 4 - NO CARRIER, 5 NO DIALTONE. You can change or add to these with the chatkey command. echo on|off Enables or disables the display of modem commands. exit [exit-status] Exits script leaving established [C]SLIP connection intact and dip running. flush Flushes input on the terminal. get $variable [value|ask|remote [timeout_value| $variable]] Gets the value for a specified variable. If the second parameter is ask, a prompt is printed and the appropriate value is read from standard input. If the second parameter is remote, the value is read from the remote machine. Otherwise, the second parameter is a constant or another variable that will supply the value. goto label Transfers control to the specified label within the chat script. Help Prints a list of commands. if expr goto label Tests a result code. The expr must have the form $variable op constant where op is one of the following: ==, !=, <, >, <=, or >=. inc $variable [incrementvalue|$ variable] Increments the specified variable. The default increment value is 1. init init-string Sets the initialization string to the indicated string (default is AT E0 Q0 V1 X4). Note that the initialization string is sent before the dialing command is issued. mode [SLIP|CSLIP|SLIP6|CSLIP6|PPP|TERM] Sets the line protocol. modem modem-name Sets the type of modem. netmask xxx.xxx.xxx.xxx Indicates the netmask address to use. onexit Executes the specified command upon dip’s exit. Works like the shell command, but is executed (only) when dip finishes. The onexit command that is executed is the last one encountered; any previous onexit commands are replaced by the new ones. parity E|O|N Sets the type of parity. password Prompts for a password and transmit it. proxyarp Requests Proxy ARP to set. print $variable Prints the contents of some variable. psend command [arguments] Sends the output of specified command to the serial driver, optionally passing arguments to command. The UID is reset to the real UID before running command. page 231 #BREAK# Inside Linux Command Description port tty_name Sets the name of the terminal port to use. (The path /dev/ is assumed.) quit Exits with nonzero exit status. reset Resets the modem. Does not work properly on several modems. securidfixed fixedpart Stores the fixed part of the SecureID password. securid Prompts for the variable part of the password generated by the ACE System SecureID card. The fixed part of the password must already have been stored using a secureidf command. The two parts are concatenated and sent to the remote terminal server. send text-string Sends a string to the serial driver. shell command [parameters] Executes command through the default shell (obtained from the shell variable) with parameters as the command-line arguments. dip variable substitution is performed before executing the command. If you don’t want a parameter beginning with a $ to be interpreted as a dip variable, precede it with a . skey [timeout | $variable] Tells dip to look for an S/Key challenge from the remote terminal server. dip then prompts the user for the secret password, generates the response, and sends it to the remote host. The optional parameter timeout sets how long dip is to wait to see the challenge. $errlvl is set to 1 if the skey command times out. If skey successfully sends a response, $errlvl is set to 0. Requires S/Key support to be compiled in. sleep time-in-secs Waits some time. speed bits-per-sec Sets port speed (default is 38400). Note that the actual speed associated with 38400 can be changed using setserial(8). Also, you should tell port’s real speed here because dip takes care of the set_hi and such bits by itself. Also, don’t be afraid, if you told the speed 57600 and it reports back 38400. Everything’s okay, the proper flags were applied, and the real port speed will be what you told it to be - that is, 57600. stopbits 1|2 Sets the number of stop bits. term Enters a terminal mode. timeout time-in-sec Sets timeout. This defines the period of inactivity on the line, after which dip will force the line down and break the connection (and exit). wait text [timeout_value | $variable] Waits for some string to arrive. page 232 #BREAK# Inside Linux The following table lists the special variables that can be used within a script file. Some of these variables can be set with a value and some are read-only; all variables can be read for their contents. Note that the variable names are lowercase and must begin with a dollar sign. Table 13.3 briefly describes each variable’s purpose. Table 13.3. Variables for a dip Chat File Variable Description $errlvl Holds the result of the previous command $locip IP Number of local host in dotted quad notation $local Fully qualified local hostname $rmtip IP Number of remote host in dotted quad notation $remote Fully qualified remote hostname $mtu Maximum Transfer Unit (maximum number of bytes that are transferred at once) $modem Modem type (at present, the only valid value is HAYES) $port Name of the terminal port to use $speed Transfer rate between the local host and the modem, in bits/sec Something to note: dip will resolve any hostname to its IP address if you supply the hostname in the local and remote special variables. Sample dip Script The following is a sample dip script: # bugs.dip # top: # define the name for connection.”ren.stimpy.net” get $local ren.stimpy.net # set up the remote end “bugs.bunny.net” get $remote bugs.bunny.net # set up the netmask 255.255.255.0 netmask 255.255.255.0 # define the serial port and speed. port cua02 speed 38400 # clean up the modem (reset it) reset flush # if your modem doesn’t respond properly to # the previous “reset”, then comment out # the reset or delete it altogether. then # uncomment the following two lines. # send ATZr # wait OK 3 # set the initialization string for modem, then dial get $init ATQ0V1E1X4 dial 123-4567 if $errlvl != 0 goto modem_ERR wait CONNECT 60 if $errlvl != 0 goto modem_ERR # if we got to here, we’re connected … # … log in to the remote system login: sleep 2 send rnrn wait ogin: 10 if $errlvl != 0 goto login_ERR send THE_USERNAMEn sleep 2 wait word: 10 if $errlvl != 0 goto pswrd_ERR send THE_PASSWORDn page 233 #BREAK# Inside Linux log-success: # we’re logged in, now wait for prompt wait SOMETEXT 15 if $errlvl != 0 goto prompt_ERR # if we’ve gotten here, then we’ve completed # all tasks required for SLIP connectivity fini: # set up SLIP get $mtu 296 # Ensure execution of route default print CONNECTED $locip == $rmtip mode CSLIP goto exit # prompt_ERR: print Time out waiting for login prompt goto error # login_ERR: print Time out waiting for logon goto error # pswrd_ERR: print Time out waiting for password prompt goto error # modem_ERR: print Problem with the modem goto general_ERR # general_ERR: print Could not connect with the remote system quit 1 exit: exit This sample script can be used to connect to bugs.bunny.net by invoking dip with the script name as its argument: # dip bugs.dip After successfully connecting to bugs and CSLIP has been engaged, dip will detach itself from the terminal and become a daemon process (or background process). Recall that if you invoke dip with the -k switch, dip will kill the dip process that has locked the specified tty device or the most recent invocation of dip. The following dialog demonstrates this: # dip -k Let’s take a look at the script file. The first statement in the script is a get command, which actually sets a variable to the specified value. In this script, the first statement, $local, is set to ren.stimpy.net. The second statement sets the variable $remote to bugs.bunny.net. Those lines follow: get $local ren.stimpy.net # set up the remote end “bugs.bunny.net” get $remote bugs.bunny.net The next line is the netmask statement; this statement and the next four statements (through reset) configure the terminal and reset the modem. You may experience a problem with the reset command; this command does not work with all modems. If you do have problems, either comment out the reset statement or remove the line altogether. Next, uncomment the two lines that read as follows: # send ATZr # wait OK 3 The statement following the reset statement, flush, purges any modem strings that may exist in the (receive) buffer. This ensures that no extraneous strings are in the buffer when the login sequence executes. The wait statement instructs dip to wait for the string specified as the first argument to wait. The second argument specifies a timeout as a number of seconds; if the string is not detected within the timeout range, the $errlvl variable is set to 1. The $errlvl variable is checked for success; if it is nonzero, the previous statement failed and we branch out to the appropriate error section. The following excerpt demonstrates the sequence: wait ogin: 8 if $errlvl != 0 goto login_ERR page 234 #BREAK# Inside Linux The concluding commands that are executed after the login is successful are default, which makes the SLIP link the default route to all hosts, and mode, which enables SLIP mode on the line and configures the interface and routing table for you. The next command, goto exit, routes the execution of the script around the error statements that follow. The following section of the script deals with exceptional conditions. Each label is used to deal with a specific error (exceptional) condition. A message is printed and then a goto statement is used to branch to the generic error message routine. Notice that the modem_ERR: section does not require a goto statement; it could just fall through to the general_ERR statement. The reason we use a goto statement is that we may need to add another error statement. If you insert the new statement after modem_ERR, you might forget to include the goto statement. prompt_ERR: print Time out waiting for login prompt goto general_ERR # login_ERR: print Time out waiting for logon goto general_ERR # pswrd_ERR: print Time out waiting for password prompt goto general_ERR # modem_ERR: print Problem with the modem goto general_ERR # general_ERR: print Could not connect with the remote system quit 1 The last statement in the script is exit, which is used as an unconditional egress of the script. The SLIP connection remains valid and dip continues to run. If you recall, the command dip -k is used to kill the running dip process. Remember to provide the script filename as an argument to the dip command. If you do not provide the filename extension, dip assumes an extension of .dip. Utilizing dip for Static IP Connectivity This section addresses using dip to establish a SLIP connection when the IP addresses for the local and remote are well-known (static). The following script is generic in nature and can be modified for your use. # static.dip top: get $local some.local.name get $remote some.remote.name netmask 255.255.255.0 # set up the modem port cua02 speed 38400 reset flush # if your modem doesn’t respond properly to # the previous “reset”, then comment out # the reset or delete it altogether. then # uncomment the following two lines. # send ATZr # wait OK 3 # set the initialization string for modem, then dial get $init ATQ0V1E1X4 dial 123-4567 if $errlvl != 0 goto modem_ERR wait CONNECT 60 if $errlvl != 0 goto modem_ERR login: sleep 2 send rnrn wait ogin: 10 if $errlvl != 0 goto login_ERR send USER_NAMEn sleep 2 wait word: 10 if $errlvl != 0 goto pswd_ERR send USER_PASSWORDn page 235 #BREAK# Inside Linux log-success: # we’re logged in, now wait for prompt wait CONFIRMATION_TEXT 15 if $errlvl != 0 goto prompt_ERR # if we’ve gotten here, then we’ve completed # all tasks required for SLIP connectivity fini: # set up SLIP get $mtu 296 default print CONNECTED $locip == $rmtip mode CSLIP goto exit # prompt_ERR: print Time out waiting for login prompt goto error # login_ERR: print Time out waiting for logon goto error # pswd_ERR: print Time out waiting for password prompt goto error # modem_ERR: print Problem with the modem goto general_ERR # general_ERR: print Could not connect with the remote system quit 1 exit: exit It is acceptable to use dotted-quad addresses for the get $local and the get $remote statements, but as always, you should specify the machine names because dip will resolve the names to IP addresses automatically. After name resolution, dip will perform its magic of dialing, connecting, log in, and finally, switching the line into SLIP mode and configuring the routing tables. In the section that follows, we will take a look at dip usage for dynamic IP connectivity. Utilizing dip for Dynamic IP Connectivity This section demonstrates the use of dip to establish a SLIP connection when the IP address is not known for the local and remote machines. The dip command will capture the IP addresses through the serial line after connectivity is established. The following sample script file demonstrates the functionality required: # dynamic.dip top: # set up the modem port cua02 speed 38400 reset flush # if your modem doesn’t respond properly to # the previous “reset”, then comment out # the reset or delete it altogether. then # uncomment the following two lines. # send ATZr # wait OK 3 # set the initialization string for modem, then dial get $init ATQ0V1E1X4 dial 123-4567 if $errlvl != 0 goto modem_ERR wait CONNECT 60 if $errlvl != 0 goto modem_ERR login: sleep 2 send rnrn wait ogin: 10 if $errlvl != 0 goto login_ERR send USER_NAMEn sleep 2 wait word: 10 if $errlvl != 0 goto pswd_ERR send USER_PASSWORDn get $remote remote 10 page 236 #BREAK# Inside Linux if $errlvl != 0 goto remote_ERR get $local local 10 if $errlvl != 0 goto local_ERR log-success: # we’re logged in, now wait for prompt wait CONFIRMATION_TEXT 15 if $errlvl != 0 goto prompt_ERR # if we’ve gotten here, then we’ve completed # all tasks required for SLIP connectivity fini: # set up SLIP get $mtu 296 default print CONNECTED $locip == $rmtip mode CSLIP goto exit # prompt_ERR: print Time out waiting for login prompt goto error # login_ERR: print Time out waiting for logon goto error # pswd_ERR: print Time out waiting for password prompt goto error # modem_ERR: print Problem with the modem goto general_ERR # remote_ERR: print Time out getting remote IP address goto error # local_ERR: print Time out getting local IP address goto error # general_ERR: print Could not connect with the remote system quit 1 exit: exit In this script, the modem is set up and initialized. Next, the remote SLIP server is dialed and a connection is established. After the username and password have been submitted and verified, the remote and local IP addresses are captured by the dip command. The dip command does this by examining the incoming data for anything that looks like an IP address. The dip command will time out after 10 seconds if it cannot find an IP address. Finally, if everything passes inspection, dip switches the line into SLIP mode and configures the routing tables. Running diplogin as a SLIP Server Using dip to act as a SLIP server is relatively easy. The basic course of attack is to set up the various configuration files and then execute the diplogin command. You need to create an account for each user that will need SLIP connectivity to your system. You will also need to add an entry for every user to the /etc/diphosts configuration file. Define Account Entry in /etc/passwd First, you need to supply an entry in the /etc/passwd file for each user requiring SLIP service. Be sure to define diplogin as the login shell for each user entry in the /etc/passwd file. The following is a sample entry: stimpy:x:1000:100:Stimpson J. Cat:/home/stimpy:/user/sbin/diplogin In this sample, after stimpy has logged in, the login program sets the current directory to the home directory specified in the /etc/passwd file, which is /home/stimpy. Next, the diplogin command is executed, which is a symbolic link to the dip command (dip is run in input mode). Finally, the dip command scans the /etc/diphosts file for the identified username. page 237 #BREAK# Inside Linux Define Username Entry in /etc/diphosts Each user must be described in the /etc/diphosts file. The following is the template for an /etc/diphosts entry: user : password : remote host : local host : netmask : comments : protocol,MTU The first field, user, is the user name. The entry here must match the logged in user. The second field permits you to define an encrypted password for the user. If this field is not the null (empty) string, dip will display a prompt and the user must supply a password. If the special entry s/key is specified, then S/Key authentication will be enforced. Note that dip must be compiled with the S/Key option enabled. The third field of the entry specifies the name of the remote host. This entry may also be the actual IP address. If the entry is a hostname, name resolution will take place using the name server or the /etc/hosts file. The fourth field identifies the name of the local host. Like the third field, this may be the actual IP address. If the entry is a name, then name resolution will take place using the name server or the /etc/hosts file. The fifth field identifies the netmask and must be in dotted notation. If this field is empty, as in this sample entry that follows, the address 255.255.255.0 is used. The sixth field is merely used for commentary - it can contain any text. The dip command will not try to interpret the entry. The seventh field contains comma-separated flags. Possible flags are as follows: SLIP - use the SLIP protocol. CSLIP - use the Compressed SLIP protocol. SLIP6 - use the SLIP6 protocol. CSLIP6 - use the Compressed SLIP6 protocol. PPP - use the PPP protocol. number - defines the MTU parameter of this connection. You must specify one of the first five entries, a comma, and finally specify the MTU required. The following is a sample entry from an /etc/diphosts file for the user named stimpy. stimpy::stimpynet:localHost::Stimpson J. Cat:SLIP,296 This specifies that stimpy is the username. A password prompt is displayed and awaits user input. The remote host name is stimpynet and the localhost is named localHost. The netmask is not identified, so the address 255.255.255.0 is used. The text Stimpson J. Cat only provides additional information for the reader of the file. The protocol to use is SLIP, with an MTU value of 296. Execute diplogin After dip locates the correct line entry for the user, dip sets the terminal into raw mode and sets up the serial line to the defined SLIP protocol. Finally, after the line is enabled, routing table entries are defined to complete the connection. The dip command then continues to run in the background until the connection is dropped. After the line drops, the entries are removed from the routing table, and the line is returned to normal mode. Starting with the next section, we begin our journey with Point-to-Point Protocol. Point-to-Point Protocol (PPP) As was mentioned in the opening of the previous section, Linux provides two protocols for serial-line connectivity: Serial Line Internet Protocol (SLIP) and Point-to-Point Protocol (PPP). Both SLIP and PPP provide facilities to establish connectivity with a remote system. PPP is a protocol that was developed after SLIP and is now the preferred protocol over SLIP for serial-line connectivity. page 238 #BREAK# Inside Linux PPP Overview PPP is a more powerful and robust protocol than SLIP. It provides features and capabilities that are lacking with SLIP. You should always prefer PPP to SLIP when establishing a network connection over a serial line. The hardware requirements for PPP are the same as for SLIP; a serial port with a FIFO buffer and a modem are all that is required. PPP is used to support the TCP/IP protocols over a serial connection, whether it’s over a dial-up phone line (or ISDN), a null modem cable, a telnet link, or a dedicated leased line. At the lower levels, PPP is divided into two parts: the High-Level Data Link Control (HDLC) and the Link Control Protocol (LCP) . HDLC defines the ground rules for the structure of the PPP frames. This allows the frame to contain packets from protocols other than IP. A field within the frame identifies the protocol type. In addition to handling IP datagrams, PPP can also use Van-Jacobson (VJ) header compression. Effectively, this compresses the TCP packets, allowing increased performance. At a higher level, PPP functionality is also split into two parts: the HDLC and the pppd daemon. The pppd daemon delivers the LCP, support for user authentication, and the Network Control Protocols (NCP) for establishing the IP Control Protocol (IPCP). Beginning with the next section, we discuss the specifics of PPP configuration under Linux. PPP Preflight Checklist This section outlines the prerequisites that must be addressed before jumping into the actual use and setup of PPP. Some prerequisites are obvious, and others require explanation. The following list identifies the requirements for PPP usage: PPP support is available, either as a loadable module or statically. The PPP software is installed on your system. Your Linux system provides TCP/IP support. You have a modem installed on a known serial port. You have gathered the following information from your ISP to support PPP connectivity. Be prepared, some ISP support staff do not understand PPP and what is required for PPP connectivity, especially if the ISP is Microsoft influenced. Yet other ISPs can provide excellent support, both verbally and with written documentation. The following is a list of attributes you should acquire from your ISP for PPP connectivity: o The phone number to the ISP. o If using static IP assignment, you will need the IP address for your machine. Otherwise, you will be using dynamic IP assignment. o Does the remote server use PAP/CHAP? If so, you will need to obtain the ID and SECRET entries required for connecting to the ISP. Normally, these entries are your username and password. o The Domain Name Service (DNS) server address(es) for hostname resolution. If PPP is not installed on your system, you should refer to the distribution documentation. To install support, running the installation program provided with your Linux distribution should install the necessary components for PPP use. For example, with RedHat, use RPM to install the package that supports PPP. Under SuSE Linux, you can use YaST to install the PPP package. For Caldera OpenLinux, you can use the KPackage program to install RPM-compatible packages. page 239 #BREAK# Inside Linux You can easily check for the existence of PPP support using the dmesg command. You can invoke it as shown in the following dialog: stimpy $ dmesg | grep PPP PPP: version 2.3.3 (demand dialing) PPP line discipline registered. PPP BSD Compression module registered PPP Deflate Compression module registered stimpy $ You will need to visit a number of configuration files to enable PPP; these will be examined in sections that follow. Verify DNS Support After the PPP connection is established, your Linux machine will need to use the facilities of hostname resolution - resolving hostnames into their respective IP addresses. Your ISP should provide you with the names of its DNS servers. After you have this information, you need to provide entries in the /etc/resolv.conf and /etc/hosts.conf files. The /etc/resolv.conf file is used for name resolution. Entries found in this file designate a DNS server and its associated IP address. More than one DNS server can be specified in this file. As mentioned previously, your ISP can provide you with the DNS servers and their associated IP addresses. The following is sample output from an /etc/resolv.conf file: domain the-isp.domain.name nameserver 19.265.15.5 nameserver 19.265.15.10 Your ISP will have one or more DNS servers; be sure to enter all DNS servers and their respective IP addresses. You can also set up your Linux to use DNS locally. Many Linux power users do this because it can cut down on name-resolution traffic from your host to the server (and vice versa). Doing this will provoke your DNS to cache DNS lookups, thereby decreasing accesses to the remote DNS for name resolution. The following is a sample entry from an /etc/host.conf file: order hosts,bind multi on The first line tells the resolver to query information (resolution) from the /etc/hosts file. If resolution is not found there, the resolver queries the DNS server(s). Using PPP To establish a PPP network connection, a pair of programs are utilized, specifically chat and pppd. In the next section, we discuss the chat program. The pppd program is discussed in the section that follows. Using chat The chat program provides the automation required to establish a connection between your local machine and the remote PPP server. The objective of chat is to establish the connection between the local pppd and the remote’s pppd process. The syntax for chat is as follows: chat [options] scriptFile Table 13.4 lists the options available for chat. Be sure to refer to the man page for chat for more detailed information. As mentioned previously, two programs are used to establish PPP connec-ivity: chat and pppd. With SLIP connectivity, we have to use only the dip program. Unfortunately, pppd does not provide for dial-up and logging facilities. The chat program implements UUCP-style chat script functionality. In a nutshell, a chat script consists of alternating expect-send string sequences, separated by spaces. Optionally, subexpectsubsend string pairs can be used, separated by a dash. The following example demonstrates this: ogin:-BREAK-ogin: ppp ssword: myPswd page 240 #BREAK# Inside Linux Table 13.4. Common chat Options Switch Description -f chat file Read the chat script from the chat file. Multiple lines are permitted in the file. To separate strings, use the space or the tab character. -t timeout Set a timeout for receipt of the expect string. If the expect string is not received within the timeout period, reply string is not transmitted. -r report file Set the filename for report string output. -e Echo will be enabled when chat starts up. The ECHO keyword can be used to subsequently toggle echoing on and off. Output is to stderr. -v Verbose mode will be enabled when chat starts up. The chat program will log both text received from the modem and output strings to the modem, plus the state of chat. See the -s flag for logfile options. -V The chat script is executed in stderr verbose mode. The chat program will output all dialog to the stderr device. -s Use stderr. All log messages will be sent to stderr. -S Do not use the SYSLOG for logging. Normally, error messages are sent to SYSLOG. If -S is used, neither log messages from -v nor error messages are not sent to SYSLOG. -T phone number Pass in a string, normally a phone number, that is substituted for the T meta-character in a send string. -U phone number Pass in a string, normally a phone number, that is substituted for the U meta-character in a send string. script If a script is not specified with the -f option in a file, the script is submitted to the chat program. We will now break down and analyze what is happening in this script. The first line tells chat to expect the string ogin:. If chat does not receive the login prompt within the timeout period, chat will send a BREAK to the remote end and again will wait for the string ogin:. If ogin: is received, the break is not transmitted. When the login prompt is received (ogin:), chat will send the string ppp and wait for the string ssword:. If the prompt is received, chat will transmit the password myPswd. You should note that a carriage return character is sent immediately after the reply string. Chat scripts are fairly straightforward. The previous script is not a comprehensive one because it does not include the expect-send strings required to perform modem initialization, dial-up, and the login dialog. The following demonstrates a more comprehensive script, from start to finish. stimpy # chat -v ‘’ ATZ OK ATDT1234567 CONNECT ‘’ ogin:-BREAK-ogin: ppp word: stimpy3 The chat program anticipates that the first string is an expect string, but because the modem won’t expel text before we have sent something to it, the empty string (”") is specified as the (first) expect string. The first send string is ATZ, which is a modem reset for Hayes-oriented modems. Next, we expect to see the string OK as a response to the reset command. We follow up by submitting the dial command and the phone number to dial. The chat program then waits for the CONNECT string to return from the modem. The empty string is transmitted because we want to wait only on the login prompt. Finally, the login sequence is executed as shown in the previous example. You have probably noticed that most expect strings are not complete words. For example, instead of expecting the string Login, the string ogin: is used. Or, instead of expecting Password, the string word: is identified. The main reason to do this is expectation of the incoming text. It is possible that instead of Login, the text string is actually login (with a lowercase l). Or, instead of Password, the text string is actually password (with a lowercase p). You have to think about these seemingly insignificant details when developing chat scripts. Even if you are positive that your PPP server is sending Password, nothing prevents them from changing the text string. Suffice it to say that standard practice dictates using the few letters of the expect string. page 241 #BREAK# Inside Linux The chat program offers a number of escape sequences. Table 13.5 lists the escape sequences offered by chat. Any of the escapes can be in the send string. Table 13.5. Escape Sequences for chat Switch Description ‘’ Expects or sends the null (empty) string. Although no characters are transmitted, the implied return character is still sent. b Represents a backspace character. c Suppresses the newline character at the end of the reply string. Use this to send a string without a trailing return. It must be at the end of the send string. d Delays for one second. K Inserts a BREAK n Sends a newline (linefeed) character. N Sends the null character. p Pauses for 1/10 of a second. q Suppresses writing the string to SYSLOG. r Sends or expects a carriage return. s Represents a space character in the string. t Sends or expects a tab character. \ Sends or expects a backslash character. ddd Used to represent an ASCII character using the equivalent octal digits. ^C Substitutes the sequence with the control character represented by C. Some of the escape sequences may not be identified in the expect string. Be sure to consult the man page for chat for more information. We need to touch on the subject of security. Executing the chat program with the script dialog is subject to inspection by other users on the system. Anyone can execute the ps -ef command sequence and view the complete command line. You say you have not tried these switches to the ps command? Try it now to see the results. So, how do you deflect any users from examining the chat script? The solution is rather simple - you put the chat dialog into a file and then tell chat to use the contents of the file for the dialog. Referring back to Table 13.1, you will see that using the -f switch and supplying the script file as an argument will instruct chat to use the file’s contents for the chat dialog. The following demonstrates the syntax: stimpy $ chat -f chat_script_filename It is also easier to modify and maintain a script within a file, rather than modifying the command line. You cannot identify a chat file (with -f) and specify a chat dialog on the command line, because they’re mutually exclusive. The following is a sample chat script file: ‘’ ATZ OK ATDT1234567 CONNECT ‘’ ogin:-BREAK-ogin: ppp word: stimpy3 The expect-send pairs reside on the same line. This makes maintenance and troubleshooting much easier. It is always good to expect potential failure and to be able to recover from it. You can specify that a script should be aborted if some failure is detected. For example, chat cannot determine the difference between CONNECT and BUSY; chat does not know that the string BUSY is considered an exceptional condition. So, how do you inform chat of exceptional conditions? You do this by specifying abort strings. page 242 #BREAK# Inside Linux The chat keyword ABORT is used to specify an abort sequence. The following sample script demonstrates the use of ABORT: ABORT BUSY ABORT ‘NO CARRIER’ ‘’ ATZ OK ATDT5551212 CONNECT ‘’ The chat will abort execution of the script if it detects any of the identified ABORT sequences as an expect string. Using pppd The pppd command is the Point-to-Point Protocol Daemon. The syntax for pppd is as follows: pppd [tty_name] [speed] [options] Table 13.6 lists the more common options for the pppd command. Table 13.6. Common Options for pppd Option Description asyncmap Sets the async character map to . The map describes that control characters cannot be successfully received over the serial line. auth Specifies that the peer is required to authenticate itself before network packets can be sent or received. connect script Uses the executable or shell command specified by script to set up the serial line. crtscts Uses hardware flow control (RTS/CTS) on the serial port. defaultroute Adds a default route to the system routing tables. disconnect script Runs the executable or shell command specified by script after pppd has terminated the link. escape xx,yy,… Causes the characters to be escaped on transmission. The characters escaped are specified as hex numbers, delimited by commas. file name Reads the options from file name. lock Uses UUCP-style lock file for the serial device to ensure exclusive access to that device. mru n Sets the MRU value to n. The minimum value is 128 and the default is 1500. mtu n Sets the MTU value to n. passive Specifies that the passive option be used in the LCP. debug Enables connection debugging facilities. local Does not use the modem control lines; ignores the state of CD (Carrier Detect) and pppd will not change the state of DTR. login Utilizes the system password database for authenticating the peer using PAP. Also, records the user in the system wtmp file. modem Uses the modem control lines, which is the default. The pppd command will wait for the CD from the modem to be asserted when opening the serial device, and it will drop the DTR when the connection is terminated. netmask n Sets the interface netmask to n. nodetach Doesn’t detach from the controlling terminal. xonxoff Uses software flow control (that is, XON/XOFF) on the serial port. Be sure to refer to the man page for pppd for an exhaustive list of commands available. page 243 #BREAK# Inside Linux Option Files for pppd After pppd executes and before it scans the arguments on the command line, it scans a number of configuration files for default options. These files contain any of the valid command-line arguments. Comments can be included in the files and are delineated by the # sign. One file is the options file and is found in the /etc/ppp directory. This file is always searched and parsed when pppd first executes. It is accepted practice to use this file for any global defaults. Doing this can help with any potential security issues that could arise. For example, you could specify that PAP authentication be used from the peer; to do this, you include the auth option in the /etc/ppp/options file. The user cannot override this option. The following is an excerpt from a sample /etc/ppp/options file: # /etc/ppp/options # The name of this server. name # Enforce the use of the hostname usehostname # If no local IP address is given, # noipdefault # Specify which DNS Servers the incoming # Win95 or WinNT Connection should use #ms-dns 192.168.1.1 #ms-dns 192.168.1.2 # enable this on a server that already # has a permanent default route #nodefaultroute # Increase debugging level (same as -d). The # debug output is written to syslog LOG_LOCAL2. debug # Require the peer to authenticate itself before # allowing network packets to be sent or received. noauth # Use hardware flow control (i.e. RTS/CTS) to # control the flow of data on the serial port. crtscts # Specifies that pppd should use a UUCP-style # lock on the serial device lock # Use the modem control lines. modem # Set the MRU #mru 542 # Set the MTU to n #mtu # Set the interface netmask to , a 32 bit netmask in “decimal dot” # notation (e.g. 255.255.255.0). netmask 255.255.255.0 # Don’t fork to become a background process nodetach # Specifies that pppd should disconnect # if the link is idle for n seconds. idle 600 # —— A second file that is read after the /etc/ppp/options file is parsed is .ppprc. This file is found in the user’s home directory. Users have the ability to establish their own sets of default options by merely supplying the required options in the file. Script Files for pppd Connections In this section, we introduce a set of scripts to help automate log-in and PPP startup. After these files are set up, you have to execute only a single command to establish a PPP connection. The following files are used for version 2.1.2 of PPP: /usr/sbin/pppd /etc/ppp/options / etc/ppp/ppp-on / etc/ppp/ppp-off For version 2.2 of PPP, we add a third file to the list, as shown in the following: /usr/sbin/pppd /etc/ppp/options /etc/ppp/ppp-on /etc/ppp/ppp-off /etc/ppp/ppp-on-dialer page 244 #BREAK# Inside Linux The following is a sample ppp-on script. You should use this script file no matter whether you are using version 2.1.2 or 2.2 of PPP. #!/bin/sh # Script to initiate a PPP connection. # Change as required. TELEPHONE=123-4567 # The telephone number to the remote ACCOUNT=theAccount # Account name PASSWORD=thePassword # Password to use LOCAL_IP=0.0.0.0 # Local IP addressl; if dynamic = 0.0.0.0 REMOTE_IP=0.0.0.0 # Remote IP address; usually 0.0.0.0 NETMASK=255.255.255.0 # Netmask, if required # Export export TELEPHONE ACCOUNT PASSWORD # Location of the script which dials the phone and logs DIALER_SCRIPT=/etc/ppp/ppp-on-dialer # Initiate the connection exec /usr/sbin/pppd debug /dev/ttySx 38400 $LOCAL_IP:$REMOTE_IP connect $DIALER_SCRIPT You will have to modify the ppp-on script; the script previously shown is really a template. Starting from the top and moving down, you first have to supply the proper phone number to your ISP. Next, the ACCOUNT field is your username that is registered with your ISP. The field that follows ACCOUNT, PASSWORD, is the password you use for login purposes. You may need to alter the following lines: DIALER_SCRIPT=/etc/ppp/ppp-on-dialer … exec /usr/sbin/pppd debug /dev/ttySx 38400 If your pppd executable and ppp-on-dialer file exist in a different directory path, you will need to change those paths in the script file. Next, a sample ppp-on-dialer script is supplied as follows: #!/bin/sh # /usr/sbin/chat -v TIMEOUT 3 ABORT ‘nNO CARRIERr’ ABORT ‘nNO ANSWERr’ ABORT ‘nBUSYr’ ‘’ rAT ‘OK-+++c-OK’ ATH0 TIMEOUT 60 OK ATDT$TELEPHONE CONNECT ‘’ ogin:–ogin: $ACCOUNT sword: $PASSWORD The ppp-on-dialer script file contains the actual dialog that is required to dial up and log in to the remote PPP server. In this sample, three ABORT sequences are identified; be sure to add any other abort sequences you may require. Check your modem manual for any exceptional conditions (error strings) that may need to trigger an abort sequence. Also, pay close attention to the value for the TIMEOUT variable - you may need to extend this time. Finally, a sample ppp-off script is supplied as follows: #!/bin/sh # Find device to kill. if [ “$1″ = “” ]; then DEVICE=ppp0 else DEVICE=$1 fi # If the ppp0 pid file exists, then it’s running if [ -r /var/run/$DEVICE.pid ]; then kill -INT `cat /var/run/$DEVICE.pid` # If kill didn’t work, then no process # is running for this pid if [ ! “$?” = “0″ ]; then rm -f /var/run/$DEVICE.pid echo “ERROR: Deleted pid file” exit 1 fi # echo “Terminated PPP link: $DEVICE” exit 0 fi # # ppp not running echo “ERROR: Invalid PPP link: $DEVICE” exit 1 This last script is used to shut down PPP in a graceful fashion. You should not have to alter this file. page 245 #BREAK# Inside Linux And now, the moment of truth. After you have made all the required adjustments to the scripts, it is time to execute and test for success. First, you need to execute the ppp-on script file, as the following dialog demonstrates: stimpy $ ppp-on & stimpy $ The trailing ampersand (&) puts the execution of the script into the background and returns the command prompt. Testing the PPP Scripts At the end of the previous section, we executed the ppp-on script. An effective method of debugging the fruits of our labor is to examine the /var/log/messages file (or /var/adm/messages). You use the tail command to reveal the last messages written to the log. In the example that follows, I have requested an extract of the previous 200 messages written to the log file. I have parsed out only the lines that pertain to the PPP dialog. stimpy $ tail -200 /var/log/messages Oct 11 04:24:26 stimpy pppd[13718]: pppd 2.3.5 started by root, uid 0 Oct 11 04:24:26 stimpy pppd[13718]: Using interface ppp0 Oct 11 04:24:26 stimpy pppd[13718]: Connect: ppp0 <--> /dev/modem Oct 11 04:24:26 stimpy pppd[13718]: sent [LCP ConfReq id=0×1 … Oct 11 04:24:26 stimpy pppd[13718]: rcvd [LCP ConfAck id=0×1 … Oct 11 04:24:26 stimpy pppd[13718]: rcvd [LCP ConfReq id=0×1 … Oct 11 04:24:26 stimpy pppd[13718]: sent [LCP ConfAck id=0×1 … Oct 11 04:24:26 stimpy pppd[13718]: sent [PAP AuthReq id=0×1 user=”user” … Oct 11 04:24:29 stimpy pppd[13718]: sent [PAP AuthReq id=0×2 user=”user” Oct 11 04:24:32 stimpy pppd[13718]: sent [PAP AuthReq id=0×3 user=”user” Oct 11 04:24:34 stimpy pppd[13718]: rcvd [PAP AuthAck id=0×3 “”] Oct 11 04:24:34 stimpy pppd[13718]: Remote message: Oct 11 04:24:34 stimpy pppd[13718]: sent [IPCP ConfReq id=0×1 ] Oct 11 04:24:34 stimpy pppd[13718]: sent [CCP ConfReq id=0×1 … Oct 11 04:24:34 stimpy pppd[13718]: rcvd [IPCP ConfReq id=0×2 … Oct 11 04:24:35 stimpy pppd[13718]: sent [CCP ConfReq id=0×2] Oct 11 04:24:35 stimpy pppd[13718]: rcvd [IPCP ConfReq id=0×3 ] Oct 11 04:24:35 stimpy pppd[13718]: sent [CCP ConfRej id=0×4 < 04 02>] Oct 11 04:24:35 stimpy pppd[13718]: rcvd [CCP ConfReq id=0×5] Oct 11 04:24:35 stimpy pppd[13718]: sent [CCP ConfAck id=0×5] Oct 11 04:24:41 stimpy pppd[13718]: rcvd [IPCP ConfReq id=0×6 ] Oct 11 04:24:41 stimpy pppd[13718]: sent [IPCP ConfAck id=0×6 ] Oct 11 04:24:41 stimpy pppd[13718]: sent [IPCP ConfReq id=0×4