Archive for May, 2008

embedded Debian

Sunday, May 11th, 2008

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