Monthly Columns
 

Help, I've Fallen

Copyright © 1999 Gary Kline, David Leonard, and Dirk Myers

This issue of Help, I've Fallen welcomes the OpenBSD expertise of David Leonard who contributed to our last column.

David Leonard first encountered Unix on an Apple IIe. He vaguely recalls only a very terse, cryptic prompt and a strange-sounding program called grep, at which his high school teacher just frowned and muttered, "bloody Unix."

David is a PhD student with the DSA group at UQ, and uses Python. He lives with his wife, Kylie, and cat, \mu, in humid Brisbane, Australia.

David has only three computers (mac68k, sparc, pmax) and contributes to the OpenBSD project.

Dirk and Gary have been Unix enthusiasts for a while now; both live in the Pacific Northwestern U.S.



How do I rebuild a new kernel for my *BSD machine?

Each of the steps is simple by itself. With care and deliberation, everything should go smoothly.

First, be certain that you have backed up you entire system before installing or the new kernel. It is a good idea that you do this periodically anyway.

Let's assume that you are doing this for the first time and that the configuration files in CONF are untouched.

cd to the directory which contains the kernel configuration files. If you're unsure of exactly what name your system is using to refer to <your-architecture>, use 'uname -m'. For example:

% uname -m
mac68k


FreeBSD: /sys/<your-architecture>/conf
NetBSD:  /sys/arch/<your-architecture>/conf
OpenBSD: /sys/arch/<your-architecture>/conf


For all three flavors, the default kernel configuration file is called "GENERIC". The easiest way to set up a configuration file is to use the GENERIC file as a base. Copy the generic file to another filename. By convention, this file should be the name of your system. If your system is called thyme, then

% cp GENERIC THYME

If you want a configuration other than the GENERIC configuration, edit the file at this point. A complete rundown on all the changes you could possibly make to a kernel configuration would make for a long discussion, a possible future question for this column -- for now, we're going to assume that you want to rebuild the kernel with the default GENERIC file as a starting place.

NetBSD and OpenBSD have a manual page describing the kernel config options: options(4).

Now, use the 'config' program to set up a compilation directory, based on the settings you've specified in the configuration file.

% config THYME

This will create a directory with the same name as the config file. If a directory for this configuration already exists, config will update the existing directory. The location of the directory varies slightly by flavor:


FreeBSD: /sys/<your-architecture>/compile/THYME
NetBSD:  /sys/arch/<your-architecture>/compile/THYME
OpenBSD: /sys/arch/<your-architecutre>/compile/THYME
 

cd to the directory config has just created.

% cd ../compile/THYME

Cautionary note: If you've built a kernel in this directory before, run a 'make clean' at this point.

Create the dependencies with the make command:

% make depend

This will take anywhere from 'a few seconds' to 'a good, long time' depending on how fast your machine is. This command will also generate a lot of output which is highly dependent on *BSD flavor, your architecture, and your kernel configuration.

Once the dependencies have been generated, you're ready to compile the kernel itself. Use the make command again, this time without arguments.

% make

Typically, a kernel build will take somewhat longer than generating dependencies does. Again, you'll see a lot of output.

The new kernel file will appear in the compile directory. The actual name of the file is set by the "config" line in the config file.

The default name varies slightly by *BSD flavor:


FreeBSD:    kernel
NetBSD:     netbsd
OpenBSD:    bsd
 

Now, as root, move your old kernel. The name your system uses for the kernel is exactly the same as the defaults for new kernels above.

For example, in FreeBSD:

# mv /kernel /kernel.old

The reason for doing this is that the boot loader will try the <kernel-name>.old file if the default kernel file doesn't work-- that is, is the new kernel loads and crashes, the most common scenario, the loader will choose <kernel-name>.old if <kernel-name> is deleted or corrupted.

Now you are ready to move the kernel to the root directory.

# cp kernel /kernel

Last, but not least, you'll need to reboot your machine to use the new kernel.

# reboot

Because open source unix is an ever-moving target you will eventually find yourself with an outdated config file. i.e. GENERIC will evolve and the parts of THYME that came from GENERIC will no longer be in sync. Keeping THYME in sync with GENERIC is normally done by hand, since changes to GENERIC are infrequent and often small.

One way to ease this process is to keep a copy of GENERIC (maybe called GENERIC.THYME) that is the same vintage as THYME. Whenever you feel the need to update THYME, you can use 'diff -u GENERIC.THYME GENERIC' to see what has changed. Don't forget to 'cp GENERIC GENERIC.THYME' after you have merged any needed changes into THYME.

How do I set up my (fake-net) networked home computers to the (real) Internet?

[ for FreeBSD | for NetBSD | for OpenBSD ]
For FreeBSD

This used to be called ``IP-Masquarading'' since your pseudo- network needs to pretend to be a legit internet IP address.

In the BSD realm you want natd a program that translates the network addresses of the ``real'' (internnet IP address) to your ``fake-net''. natd stands for the Network Address Translation Daemon, which, running in the background, intercepts and translates addresses transparently. natd has built-in firewalls hooks so that you can allow or deny whomever you wish from your private network.

What follows is adapted with very few changes from the FreeBSD docs, so kudos and acknowledgements for a great job.

Setting up NATD in FreeBSD

The following steps are necessary before attempting to run natd:

1. Get FreeBSD version 2.2 or higher. Versions before this do not support divert(4) sockets.

2. Build a custom kernel with the following options:

In your /usr/src/sys/i386/conf directory is your kernel configuration file, normally named what your system-name is named. The default name is GENERIC. In this file add:

options IPFIREWALL
options IPDIVERT

In /sys/i386/conf, after you have added the two lines to your KERNEL configuration file, rebuild your kernel. If you have never rebuilt your kernel, see Question #1 above, rebuilding your kernel.

  ## above

After rebuilding your kernel, edit /etc/rc.conf to enable your system to act as a gateway:

gateway_enable=YES

3. If you wish to use natd's -n or -interface flags, make sure that your interface is already configured. If, for example, you wish to spec_ ify tun0 as your interface, and you're using ppp on that inter_ face, you must make sure that you start ppp prior to starting natd.

For the purpose of this discussion, let's assume that your personal workstation is linked to the internet via a ppp connection through your ISP. And further, that your IP is dynamic.

4. Create an entry in /etc/services:

natd   8668/divert  # Network Address Translation socket

This gives a default for the natd -p or -port flag.

5. You will need to adjust the /etc/rc.firewall script to taste. If you're not interested in having a firewall, the following lines will do:

/sbin/ipfw -f flush
/sbin/ipfw add divert natd all from any to any via tun0
/sbin/ipfw add pass all from any to any

The second line depends on your interface (change tun0 as appropri_ ate) and assumes that you've updated /etc/services with the natd en_ try as above. If you specify real firewall rules, it's best to specify line 2 at the start of the script so that natd sees all packets before they are dropped by the firewall. The firewall rules will be run again on each packet after translation by natd, minus any divert rules.

6. Enable your firewall by setting

firewall_enable=YES

in /etc/rc.conf. This tells the system startup scripts to run the /etc/rc.firewall script. If you don't wish to reboot now, just run this by hand from the console. NEVER run this from a virtual session unless you put it into the background. If you do, your connection will be cut after the flush takes place, and execution of /etc/rc.firewall will stop at this point - blocking all network accesses. Running the script in the background should be enough to prevent this disaster.

Running natd is fairly straight forward. The line

natd <-interface> tun0

should suffice in most cases (substituting the correct interface name).

7. Edit /etc/rc.conf and make sure that this line is there, too, to enable packet forwarding.

net.inet.ip.forwarding=1

and if avoiding rebooting, run the `sysctl' command as root:

# sysctl -w net.inet.ip.forwarding=1

Running natd is fairly straight forward. The line

natd <-interface> tun0

If you are running a 2.2 version of FreeBSD prior to 2.2.7, to start up natd, in your /etc/rc.local, put the following entry:

echo "firing up natd"
natd -use_sockets -same_ports -unregistered_only -interface tun0

If your IP is dynamic, add `-dynamic' to the <-interface> designation and natd will dynamically change the alias address.

If you find this write-up on IP-aliasing clear and to the point it is due very largely the following authors' work, from which this section borrows heavily. The FreeBSD man page of natd ('man natd') has an even more in-depth discussion about this utility.


Archie Cobbs <archie@whistle.com> (divert sockets)
Charles Mott <cmott@srv.net> (packet aliasing)
Eivind Eklund <perhaps@yes.no> (IRC support & misc additions)
Ari Suutari <suutari@iki.fi> (natd)
Brian Somers <brian@awfulhak.org> (glue)
Setting up IPNAT in NetBSD or OpenBSD

To use IPNAT on NetBSD or OpenBSD, simply place the translation rules in the file /etc/ipnat.rules, and turn on 'ipf' and 'ipnat' in /etc/rc.conf. This will activate the IP packet filter (ipf) and IP network address translation (ipnat) functions in the kernel at the next reboot. Instead, you could start ipf and ipnat without rebooting, by running 'ipf -E' and 'ipnat -f /etc/ipnat.rules'.

In both NetBSD and OpenBSD, the kernel options needed for IPNAT to work are turned on in GENERIC kernels. If you've compiled your own kernel, make sure you've got the following options turned on:


NetBSD

options INET                  # IP + ICMP + TCP + UDP
options PFIL_HOOKS            # pfil(9) packet filter hooks
options IPFILTER_LOG          # ipmon(8) support
...
pseudo-device ipfilter         # IP filter (firewall) and NAT


OpenBSD

option INET                   # IP + ICMP + TCP + UDP
option IPFILTER               # IP packet filter for security
option IPFILTER_LOG           # use /dev/ipl to log ipf
      
  

Running IPNAT

Once you've got IPNAT installed, you'll need to create a rule file. Here's a quick rundown on some sample rule files:

Example 1. Dialing into an ISP from a machine at home.

map ppp0 203.3.131.8/29 -> 0/32 portmap tcp/udp 10000:20000
map ppp0 203.3.131.8/29 -> 0/32 

My dialout interface is always ppp0, and my home network's address is 203.3.131.8/29. So I wish to do translation 'at' interface ppp0, converting all outgoing 203.3.131.8/29 tcp and udp packets onto the outgoing interface's (dynamically assigned) IP address. I don't know the address ahead of time, so I specify 0/32 which is shorthand for 'this interface's address'.

Example 2. Setting up a dial-in machine at work.

map ed0 203.3.131.192/29 -> 0/32 portmap tcp/udp 10000:20000
map ed0 203.3.131.192/29 -> 0/32

This dial-in machine is connected to the LAN via ed0. When dialled in, routes are established to the private network 203.3.131.192/29 over ppp. We don't need to mention ppp, since translation occurs only at the ed0 interface. We wish to map outgoing packets at ed0 from the private network onto ed0's address (0/32 for short.)

For further tricks (like using 'rdr' to redirect incoming traffic) and the meaning of the 10000:20000 port range, you are encouraged to read ipnat(1). Examples are provided on the system in the following directories:

NetBSD: /usr/share/examples/ipf OpenBSD: /usr/share/ipf

Some caveats

Note that IPNAT only translates the packet *headers* as they pass through the interface. It does not translate IP addresses carried *within* the packet payload.

This means that these programs (among others) won't work through IPNAT:
* FTP in non-passive mode (because of the PORT command)
* Quake (because its establishment protocol contains raw IP addresses)

Basically, anything that mentions your 'inside' IP address, and does not get translated, will cause grief. The correct way to fix this is to get and run protocol gateways (i.e. proxies).

WARNING: IPNAT is not a firewall. It may mask the existence of IP addresses on the 'inside' of your network but cannot be reliably used to prevent network attacks in the same way that ipf can.

What are my backup options?

Let's continue the discussion of backing up your files that we began in the December, 1998 column.

Sooner or later, you're bound to lose some files, whether due to an accidental rm or a hard disk failure. If the data was worth the hours it took to create it is probably worth a few minutes safeguarding by having a backup.

In the December issue we discussed several means of saving copies: by creating tape or floppy backups to using RCS to store versioned level.

We'll begin with a brief discussion of dump and restore.

If you want nightly backups and have a tape drive, you may find the dump(8) utility much more flexible than tar or rcp. Its companion program, restore, is an interactive program that allows you to search the dumps and recover your data. Both have the capability to work across the network.

Following are some possible cron scripts using dump.


#!/bin/sh
/usr/bin/mt -f /dev/rst0 rewind
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /home
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /usr
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /usr2
/usr/bin/mt -f /dev/rst0 rewind

#!/bin/sh
/usr/bin/mt -f /dev/rst0 rewind
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /home
/usr/bin/mt -f /dev/rst0 rewind

#!/bin/sh
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /     # NO rewind
/sbin/dump -0uBbf 4194304 32 /dev/rst0 /home     # rewind

#!/bin/sh
/usr/bin/mt -f /dev/rst0 rewind
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /home

#!/bin/sh
/sbin/dump -0uBbf 4194304 32 /dev/nrst0 /usr  # days later
/usr/bin/mt -f /dev/rst0 rewind

Since you will need to restore what you have dumped to tape, here are a few examples that use restore.


# restore -t       # prints to stdout the contents of the whole tape
# restore -t XXX   # prints to stdout the file `XXX' iff on the tape
                   #       (format)
                   #  inode  <file>     e.g.:
                   #   4581  ./XXX


# restore -x <filename filename2 filename3>
# restore -h <directory_name> restores entire directory.
# restore -i       # gives you interactive capability.


% man restore
will give you many options for the -i interactive mode as well as many more features of the restore program. Both dump and restore could use a tutorial overview. These few paragraphs ought to get you started.

rdump and rrestore.

For remote dumps and restore over any network you can access, the following two examples demonstrate the network versions. As you can see, the orthogonality is nearly one-to-one. The notable difference is, in rrestore where the -f <file> is one of "-f host:file" or "-f user@host:file". Here, "file" is /dev/rst0; but it could also be an ordinary filename, a disk drive (say, /dev/sd1s1a), or even stdin (-).


rdump 0uBbf 2000000 10 thyme.thought.org:/dev/rst0 /

rrestore -t -f thyme.thought.org:/dev/rst0 /

It's also possible to back up tar files to a remote machine, or a drive attached to a remote machine. The trick here is to use 'rsh' (remote shell), which allows you to execute commands on a remote machine. The command executed is 'dd', which writes the data to a drive on the remote machine.


(1)  # tar -cf - / | rsh thyme.thought.org dd of=/dev/nrst0

(2)  # tar -cvfb - 20 . | rsh thyme.thought.org dd=/dev/rst0 obs=20b

   It boils down to the following general syntax:

(3)  # tar -cf - <directory> | rsh <hostname> dd of=/dev/rst0 obs=20b

The 'tar -cf - <directory>' command means to create an archive, of the directory, and write the archive to standard output. (Notice that rather than a filename after the 'f' flag, there's a '-'. This indicates standard output rather than an actual file). The archive is then piped to the dd command running on the remote machine.

To restore files from a remote machine, you can use the following command:

% rsh -n host thyme.thought.org dd if=/dev/rst0 bs=20b | tar -xvBfb - 20\ <list_of_files>

In this case, the 'dd' command running on the remote host reads from the drive. The 'B' flag to tar forces tar to read from the pipe until blocks are entirely full. The 'f' flag is the everpresent 'file' flag. The 'b' flag indicates the block size which will be used. The parameter for the 'f' flag is the '-', which (in this context) means that tar should read from standard input. The parameter for the 'b' flag is 20, which indicates the block size for tar to read. Note that the '20' here matches the '20' for the block size specified in the dd command.

I'm always running out of xterms because I have too many pseduo-ttys open. How can I increase my number of ptys?

First, you'll need to set up your kernel to handle more pseudo-terminals. In the configuration file for your kernel (see the question above) change the line:

	pseudo-device          pty          16

to:

	pseudo-device          pty          128

(You can also use 32 or 64, if you don't need 128 pseudo-terminals.)

Rebuild and reinstall your kernel, and reboot your machine.

The kernel is now configured to handle up to 128 pseudo-devices. The

next step is to create the device files that the system will use for each pseudo-terminal.

As root, use the MAKEDEV script in the /dev directory to create the device files. As root.

# cd /dev
# ./MAKEDEV pty1
# ./MAKEDEV pty2
# ./MAKEDEV pty3

You will have created 128 pseudo-ttys.

At this point, you should add entries for your new ttys to your /etc/ttys file. beneath the "# Pseudo terminals" column if they are not already listed.

You will find at least ttyp0 through ttypv, and you need to edit in the rest. For this example, ttyq0 through ttyqv; ttyr0 through ttyrv; and ttys0 through ttysv.


ttyq0   none            network
ttyq1   none            network
ttyq2   none            network
ttyq3   none            network
ttyq4   none            network
ttyq5   none            network
ttyq6   none            network
   .
   .
   .
ttysp   none            network
ttysq   none            network
ttysr   none            network
ttyss   none            network
ttyst   none            network
ttysu   none            network
ttysv   none            network

Without the additional ptys in /etc/ttys you may run out of pseudo-ttys to use for rlogin and telnet.

I just upgraded my system and now ps has quit working. How do I fix ps?

Because the 'ps' program needs intimate knowledge of the kernel's most private data structures, it is important that is compiled at or about the same time as the kernel. If this isn't the case, it doesn't find what it expects in the kernel, and stops functioning.

If your upgrade consisted solely of installing a new kernel, you will need to either download a new base distribution or recompile the system utilities that have stopped working. (In the latter case you will need the source code, and it is highly likely that you will need to re-build and install libkvm first.)

If your upgrade involved installing a newer ps, but not a newer kernel, you will need to either download a new kernel image (with a date that is about the same as 'ps'), or rebuild your kernel with the newer sources.

Look here for information on rebuilding your kernel.

Tip of the month

It's fairly obvious, even to new BSD users, to be extra-careful when doing anything as root. As obvious as it may seem to build-in extra caution into your /root/.cshrc, this is not yet a default. Adding the following alias will almost invariably save your hide -- or at least time in recovering files from your backup, sooner or later.

If you are deleting entire directories or a great number of files, and you are certain that you wish to do this, it is a trivial amount of addition effort to type /bin/rm over simply rm

alias   rm      '/bin/rm -i \!*'

This alias assumes that you are using the csh as your root shell. If you are using another shell, this must be modified accordingly.

If you do much development work in your personal account this rm alias is a good idea there as well.

Gary Kline kline@tao.thought.org,
David Leonard, and
Dirk Myers dirkm@buster.dhis.org