My Home Router – Alix 6e1

Introduction

This home router is online 24/7 and serves as a local server for various non-private services (i. e. it's not encrypted) such as radvd, CUPS, DHCP, DNS etc.

The hardware

I'm using an Alix 6e1 (256 MB RAM, 500 MHz AMD Geode LX) with a 4 GB Kingston CF-card and a Wistron DCMA81 802.11 a/b/g Wifi-card. The hardware is sufficient for my tasks, although a faster CF-card might be useful sometimes. As a modem, I was using a „congstar DSL zwei“ which needs to be powered off regularly but otherwise worked fine.
After replacing this modem with my original Fritz!Box 3030 – which can be configured to work as a modem – everything really is fine. I suggest you don't buy the „congstar DSL zwei“.

The services

Wifi: Hostapd

Hostapd is used to provide me with a Wifi-network and works fine, though I didn't get to make it run at 5 GHz (802.11 a) instead of 802.11 g, but this seems to be a limitation due to the combination of my card and Debian's hostapd. Here is my configuration (say hello if you ever come across the "a2017"-SSID):

ssid=a2017
interface=wlan0
bridge=br0
driver=nl80211
channel=9
hw_mode=g
ctrl_interface=/var/run/hostapd
country_code=EU
ieee80211d=1

logger_syslog=-1
logger_syslog_level=3

macaddr_acl=0
accept_mac_file=/etc/hostapd/hostapd.accept
deny_mac_file=/etc/hostapd/hostapd.deny
wpa=2
wpa_passphrase=42
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP

IPv6: Hurricane electric endpoint and radvd

Please note that I updated the configuration of this slightly. See below.

radvd's configuration was pretty easy but I needed some time to fiddle out the best script to put in /etc/ppp/ip-up.d/ to set up my local endpoint for Hurricane Electric. Here it is:

#!/bin/bash
IPv4=`ip addr | grep -A 3 ppp | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -n 1`
wget -O /dev/null --no-check-certificate 'https://ipv4.tunnelbroker.net/ipv4_end.php?ipv4b=AUTO&pass=G3TUR0WN4CCOUNT&user_id=42&tunnel_id=23'
ip link set he-ipv6 down
ip tunnel del he-ipv6
ip tunnel add he-ipv6 mode sit remote $otherip local $IPv4 ttl 255
ip link set he-ipv6 up
ip addr add 2001:db8:a:2 dev he-ipv6
ip route add ::/0 dev he-ipv6
ntpdate-debian

Don't forget to add a route and an IP to your local bridge as well, for example via:

ip -6 route add 2001:db8:b::/64 dev br0
ip addr add 2001:db8:b::1 dev br0

Printing: CUPS

Unfortunately, the processor is far to weak to process files and serve directly as a CUPS server. Therefore, I outsourced computing to the clients (i. e. let them run their own printing server), use something like socket://203.0.113.1:12345 as location of the printer and then use the following line in the inetd.conf of the "server":

12345 stream tcp nowait lp /usr/bin/lp lp -d EXPRINTER -o raw

Which takes everything coming in on port 12345 and adds it "raw" to the local CUPS-queue. Of course, this needs protection, because you don't want everyone to be able to print to your printer (or even exploit CUPS by sending malicious data | Also compare this post).

DHCP & DNS: dnsmasq

This was again pretty straightforward, using the following configuration:

domain-needed
listen-address=203.0.113.1,2001:db8:b::1 # IPv6 address added later. If you do this, you have to use ip6tables to prevent the public from using your DNS server
no-dhcp-interface=ppp0
all-servers
domain=foo.example.com
strict-order
dhcp-range=203.0.113.100,203.0.113.120,1h

interface-name=ppp0,foo.example.com

Miscellaneous

This is my rc.local:

#!/bin/bash
/etc/setup-iptables & # iptables-rules

ifconfig eth0 up
ifconfig eth1 up
ifdown br0
ifup br0 # I didn't quite manage to set this up automatically, see my interfaces-files further down if you want to help
openvpn --mktun --dev-type tap --dev tap45 # creates the tap45-device which is bridged with my local network
ifconfig tap45 up
brctl addif br0 tap45 # Adds said device to the bridge

echo 0 > /sys/class/leds/alix:1/brightness # Notification: Till now, LED 1 was burning and 2 & 3 off
/etc/init.d/openvpn start 45 # Attempts to start the "45"-VPN

ip -6 route add 2001:db8:b::/64 dev br0 # Adds an IPv6-IP to the local bridge device
ip addr add 2001:db8:b::1 dev br0 # Adds the corresponding rule

echo 1 > /sys/class/leds/alix:2/brightness # We are now mostly set up for the local LAN:)

ip addr show ppp0 # Test if there is already IPv4 connectivity, i. e. if pppd started nicely which sometimes does happen and sometimes doesn't.
if [ $? -eq 255 ]; then
	poff -a
	pon dsl-provider
fi # if not, start the PPPd

/etc/ppp/ip-up.d/setup.sh # Sometimes, this script which sets up IPv6 connectivity to the rest of the world doesn't finish or isn't started.
			  #I call it again to be sure.

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding # Enable forwarding

echo 1 > /sys/class/leds/alix:3/brightness # We can now act as a router and should be reachable
/etc/init.d/hostapd restart # Hostapd has sometimes problems when its device (wlan0) is added to a bridge after it was started :/
/etc/init.d/radvd restart # radvd sometimes only restarts nicely the second time and also needs to be restarted
/etc/init.d/radvd restart # after I set up a bridge
echo 0 > /sys/class/leds/alix:2/brightness # We do work now
/bin/testnet & # a script that tests wether there is connectivity or not
echo 0 > /sys/class/leds/alix:3/brightness # Ich habe fertig™ (I'm done)
exit 0

My /etc/network/interfaces:

auto lo br0
iface lo inet loopback

iface br0 inet static
        bridge_ports eth1 wlan0 #adding tap45 here doesn't work, because tap45 doesn't exist yet :/
        address 203.0.113.1  # there is only one IPv4-address possible, but I didn't manage to add IPv6-addresses
        broadcast 203.0.113.255
	netmask 255.255.255.0

auto dsl-provider
iface dsl-provider inet ppp # This should work but sometimes doesn't
pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf
provider dsl-provider

auto eth0
iface eth0 inet manual # same goes here.

As you can see, my network configuration does work and also reboots nicely – but it's not really satisfying yet. If you have great ideas on how to improve it, I'm happy to hear your comments via the provided contact details. :)

Update 2010/08

I wasn’t happy with the crappy mess /etc/rc.local is and decided to clean things up a little bit. First, I put as much network-related configuration as possible into /etc/network/interfaces:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface

auto lo
iface lo inet loopback
	pre-up	ip6tables-restore < /etc/network/ip6tables-save
	pre-up	iptables-restore < /etc/network/iptables-save

auto br0
iface br0 inet static
        bridge_ports 	eth1 wlan0 tap45
        address 	203.0.113.1
        broadcast 	203.0.113.255
	netmask		255.255.255.0
	pre-up		openvpn --mktun --dev tap45
	pre-up		sysctl -w net.ipv6.conf.br0.autoconf=0 > /dev/null || true
	up		ip -6 route add 2001:db8:b::/64 dev br0
	up		ip addr add 2001:db8:b::1 dev br0

auto alice
iface alice inet ppp
	pre-up 		/sbin/ifconfig eth0 up # line maintained by pppoeconf
	provider 	dsl-provider
	down		ifdown 426
	down		ip link set 426 down
	down		ip tunnel del 426
	down		poff -a
	pre-up		ifdown 426
	up		sleep 5 && ifup 426

auto 426
iface 426 inet6 v4tunnel
	endpoint 	203.0.113.42
	address 	2001:db8:a::1
	local		any
	netmask		64
	gateway		2001:db8:a::2
	ttl		255
	up		ip link set mtu 1472 dev $IFACE
	up		wget -4 -t 0 -T 2 -w 1 -O /dev/null --no-check-certificate 'https://203.0.113.23/ipv4_end.php?ipv4b=AUTO&pass=1&user_id=1&tunnel_id=1'

auto eth0
iface eth0 inet manual

You can see that this declares the bridge br0, the PPP device alice and the tunneling device 426 (yes, that’s a valid name). To ease things a little bit (not needing the current IP of alice in the configuration file) I set local to “any”. I unfortunately don’t know if this might be a problem or not, but till now, it definitely works.
As you can also see, I update he.net’s information regarding my tunnel here – the options passed to wget are quite aggressive but shouldn’t be a serious problem. It usually fails twice before succeeding.

Using this network interfaces configuration, I only need the following lines in /etc/rc.local (and was able to drop the extra script completely):

echo 0 > /sys/class/leds/alix:1/brightness # turns the LED off

/bin/testnet &                             # starts my network testing script. This could be an extra script in /etc/rc2.d as well.
/etc/init.d/noip2 restart                  # restarts noip2 since it fails to start for no apparent reason sometimes.
/usr/sbin/ntpdate-debian                   # gets the current time from a server

exit 0

Update 2010/08: Summary

Till now, everything seems to be working fine and I don’t have to reboot the box anymore. Looks as if it was really working now :)