I found a good document at http://kristof.vanhertum.be/?p=3 and used it as a base for building up my Linux Router. I bought a CompactFlash to IDE adapter several years ago from http://cfd.linnix.com and a 4 port 10/100 network interface on ebay.
Build the distribution
I will walk through the steps I used, and they do deviate from the original author on some points. Because of the limited write cycles on flash memory, it is important to limit paging, journaling and files that are constantly updated. I used a Debian virtual machine that I had handy to build up the filesystem.
mkdir /cf
apt-get install debootstrap
debootstrap –arch i386 etch /cf http://ftp.debian.org
Now that the base OS is present we can chroot.
mount -t proc none /cf/proc
mount –bind /dev /cf/dev
LC_ALL=C chroot /cf /bin/bash
I’m not sure what the LC_ALL=… is for because you can “chroot /cf” and it will work too. I needed a kernel, bootloader, udev and ssh. I chose dropbear for ssh because it is a little more compact.
apt-get install dropbear linux-kernel grub udev
Since this will be my gateway router I chose to put a few network utilities on it so they would be available to track, and provide additional functionality.
apt-get install dhcpd ntop iptraf ngrep tshark dnsmasq screen less dnsutils ethtool
Now it is clean-up time. mtab gets written to frequently, and the proc filesystem reports the same information. resolve.conf needs to be writeable and our filesystem will be read-only most of the time so we will move it and create a link.
rm /etc/mtab
ln -s /proc/mounts /etc/mtab
mv /etc/resolv.conf /var/log/
ln -s /var/log/resolv.conf /etc/
We need to create some config files. From the link at the top, with a modification to fstab to use labels instead.
- /etc/fstab
LABEL=/root / ext2 defaults,noatime 0 0
proc /proc proc defaults 0 0
tmpfs /var/run tmpfs defaults 0 0
tmpfs /var/lock tmpfs defaults 0 0
tmpfs /var/log tmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /var/lib/dhcp3/ tmpfs defaults 0 0
|
- /sbin/dhclient-script
Set new_resolv_conf to “/tmp/resolv.conf.dhclient-new”.
Change “mv -f $new_resolv_conf /etc/resolv.conf” to “cat $new_resolv_conf > /etc/resolv.conf”
- /etc/network/interfaces
auto lo eth0
allow-hotplug eth0
iface eth0 inet dhcp
iface lo inet loopback
|
- /etc/hosts
127.0.0.1 localhost.localdomain localhost your_hostname
|
- /etc/syslog.conf
Comment the lines where /dev/xconsole is mentioned
- /etc/init.d/checkroot.sh
Change ROOTMODE to ro
- /etc/init.d/bootlcean.sh
Add the following lines before the line stateing [ -f /tmp/.clean ] && … (located at the end of the file)
touch /var/log/resolv.conf
touch /var/log/dmesg |
A lot of the more active directories for writes are created in a ram disk. This will prevent errors.
Kristof suggests a couple of aliases to make changing read-only to read-write and back easier. Edit /root/.bashrc and at the end add:
alias ro=”/sbin/cleanup all;mount -o remount,ro /”
alias rw=”mount -o remountrw /”
The cleanup file is available on the link at the top of this post. It removes man pages, doc files and cleans up Debian cached packages so your filesystem will stay compact. I’ve quoted it below.
#!/bin/bash
function doc() {
echo "Removing documentation ..."
find / -type d -regex '.*\(/doc/\|/info/\).*' -exec rm -r {} \; 2>/dev/null
}
function man() {
echo "Removing man pages ..."
find / -type d -regex '.*\(/man/\).*' -exec rm -r {} \; 2>/dev/null
}
function deb() {
echo "Removing Debian packages and cleaning apt-cache ..."
find / -type f -regex '.*\(\.deb$\).*' -exec rm -r {} \; 2>/dev/null
rm /var/cache/apt/*.bin
rm /var/lib/apt/lists/*dists*
}
if [ $# -ne 1 ]; then
echo "Usage: $0 doc|man|deb|all"
exit 1
fi
if [ $1 == "all" ]; then
echo "remove all"
doc
man
deb
else
eval \$1
fi
When you have finished building the installation, exit the chroot (type “exit” and hit enter). Unmount the dev and proc in /cf and this is a good time to tar a backup copy. Then use fdisk to remove existing partitions and make a single partition (default is type “Linux” which is correct).
umount /cf/dev
umount /cf/proc
tar czvf ~/cf.tar.gz /cf
fdisk /dev/sda
(d for delete, n for new, primary partition 1)
mkdir /mnt/cf
mount /dev/sda1 /mnt/cf
cp -aR /cf/* /mnt/cf
mount -t proc none /cf/proc
mount –bind /dev /cf/dev
After you have finished copying, cd /mnt/cf and create a chroot. Then we will install grub on the MBR and configure the bootloader.
cd /mnt/cf
chroot ./
grub-install /dev/sda
update-grub
When it offers, create a new config file. Because we are using labels instead of dev nodes, we will edit /boot/grub/menu.lst
Make sure that hdd(0,0) and not 1,0. Find the kernel lines and locate the section (your device name may vary):
root=/dev/sda1
Change it to:
root=LABEL=/root
You should now be able to boot to the new flash memory OS.
A little more configuration
# vi /etc/hostname
router
# vi /etc/resolv.conf
nameserver 192.168.0.36
# vi /etc/network/interfaces
auto lo eth0 eth1 eth2 eth3
#allow-hotplug eth0
#iface eth0 inet dhcp
iface lo inet loopback
# outside
iface eth0 inet static
address 151.x.y.z
netmask 255.255.255.252
gateway 151.x.y.z
# dns-search somedomain.org
dns-nameservers 192.168.0.36
# dmz
iface eth1 inet static
address 64.x.y.z
netmask 255.255.255.0
# inside (lan)
iface eth2 inet static
address 192.168.0.1
netmask 255.255.255.0
I used firewall builder from fwbuilder.org to build an iptables script. With my complex internal network it was fairly easy to create objects for each network segment and host, then build rules to allow limited network access in and out. I put the script in /etc/firewall/router.fw, used chmod to make it 500 (executable, read-only for root) and then added it to rc.local. I have the default behavior setup to not forward packets so until the firewall is active there is limited exposure - incoming ssh from the outside for a period of 30 seconds on a reboot.
resolv.conf is not persistent. I will revisit this later if it starts to matter. There would be negative effects on dnsmasq I believe, but I’m not using it at this time. It is also required for apt-get to work. As a side note, once cleanup runs you will need to run “apt-get update” again to download the package database.
Ringing in my ears?! Turn off the bell!
I had to turn off the bell before it drove me nuts. I used the blacklist method, but here are several that all work.
xset -b
in ~/.bashrc
Most easier is to set in ~/.inputrc
set bell-style none
sudo modprobe -r pcspkr
vi /etc/modprobe.d/blacklist
blacklist pcspkr