Projects

This, Jen, is the Internet

Last updated: Nov. 2, 2013, 2:22 p.m.

This, Jen, is the internet.

The Internet: This, Jen, is the internet.

For OggCamp this year I had the idea of taking along a replica of The Internet from the British TV series The IT Crowd. If you haven't seen the episode, it revolves around a clueless IT manager being selected as the employee of the month. As employee of the month she is expected to make a presentation to the shareholders about her area of expertise. Keen to show her up, the two support guys manage to convince her that a small black box with a red flashing light is actually the Internet.

The box has become a favourite amongst fans of the program with dozens of versions of it having been built. It even made a brief appearance in the final episode of the series broadcast earlier this year.

WiFi access point

To make the black box a bit more interesting I decided to build it around a Raspberry Pi and a WiFi adapter so that it could act as a wireless hot spot. To power the unit for an extended period I needed a decent power supply, a small WiFi adapter and suitable code to serve up something when people connected and to blink the red LED on the top of the box.

Inside the box is a laptop battery, a voltage regulator circuit, a Raspberry Pi and a lot of wires.

Inside the Internet: Inside the box is a laptop battery, a voltage regulator circuit, a Raspberry Pi and a lot of wires.

The power supply solution is based on my camping phone charger which uses an old Asus EeePC 701 battery and a regulator to provide a USB power supply. I added an external switch to the end of the box to turn off the power connection between the battery and the regulator. This was important because there was no way to charge the battery without getting out a screwdriver and dismantling the box.

The WiFi adapter I used was an Edimax Nano USB Adapter which seems to be a really popular choice with the Raspberry Pi and was really easy to fit in the case.

I used the latest version of Raspbian from the Raspberry Pi website, I went for the latest raw image as that's the way I've always used my Pi and I was working from a Linux laptop so imaging an SD card is easy. Once installed I chose the options to expand the file system, start the SSH server automatically and boot to console since I had no need for a graphical interface in this project.

Once the hardware was up and running I installed:

So the basic setup was hostapd running as a wireless access point, udhcpd providing devices that connected with an IP address and providing the Raspberry Pi's own IP address as the DNS server, dnsmasq running as the DNS server with a catch-all that directs all domains to the local IP address. Once a request was made to the local server it served the same content for all URLs (using a custom 404 that points to index.php) which presented viewers with a screen-shot from the IT crowd episode and a random quote from the same episode. In the background I had a process running which toggled the LED on the top of the box once a second.

To get the access-point working I followed the procedure I found on the Raspberry Pi forums, building the source from Realtek which was really easy to do, just download the source file and make sure you have run sudo apt-get install build-essential then it's just a case of typing make and waiting a while for it to finish and then sudo make install. Like it says in the forum post I installed the hostapd package from the repository first, then used sudo apt-get remove to un-install it again. This leaves the startup file in place if you copy the binaries as it says. I have found that there is a problem with USB wi-fi adapters and hostapd when I did something similar with the Beaglebone, if hostapd starts before the interface is brought up by the kernel the access point will be active (you can see the network when you browse wireless networks from another device) but the WiFi adapter has no IP address. This means the DHCP and DNS servers won't work. I added sleep 15 to the hostapd startup script to give the interface time to come up and this seems to have made startup rock solid.

I used udhcpd as the DHCP server as that is what I used in the Beaglebone project, I used the same config file but with a full 256 address range for clients. I also added a line to indicate that the Raspberry Pi should be used as DNS server. I could have just used dnsmasq as that includes both DHCP and DNS but by the time I got as far as DNS I'd already setup the DHCP and didn't bother to change it.

I really wanted to have the device intuitive, the access point was just called "the internet" and I hoped that if anyone came past and saw the box sitting on the table they'd be able to find the access point and view the amusing quotes. I realised to get that to work the box would have to redirect requests for other pages so that no matter what address you entered you'd end up on the landing page. To do this I needed to set up a DNS server that replied with the IP address of the access point to any domain name lookup. This only took a one line config and the dnsmasq package from the Raspbian repositories.

The easiest bit was serving up some content, all I did was install apache2 and php5, replaced the default index.html in /var/www/ with a custom index.php and put the screen shot I wanted in that folder too. I added a line to the default config file to make the 404 page point to index.php so if people tried to connect to somesite.com/foo the DNS wildcard would direct them to the local server but would still request /foo which didn't exist. I just added the line:

ErrorDocument 404 /index.php

under the ErrorLog line in /etc/apache2/sites-available/default.

Finally I stole the daemon code and startup procedure from my server monitor project and replaced the run() method with a simple function that sets GPIO 7 to output and then toggles it once a second. To control the GPIO pins on the Pi I followed the instructions on openmicros.org. It took me a while to figure out why I couldn't use the GPIO pin I thought I was but it turns out that on the early run of Raspberry Pis the pins were numbered differently, and this one had been sat on a shelf for a long time. Since the daemon is running in the background and is started as root there are no privilege issues with accessing the GPIO.

Config Files

Probably the most tricky bit about setting up something like this is getting all the config settings right so I'm including as many of the files as I can here as examples of how to get something working.

/etc/udhcpd.conf

# The start and end of the IP lease block start 192.168.10.20 #default: 192.168.0.20 end 192.168.10.254 #default: 192.168.0.254 # The interface that udhcpd will use interface wlan0 #default: eth0 option subnet 255.255.255.0 option dns 192.168.10.1

Notes:

This configures the DHCP server, make sure that you select your WiFi adapter and use a different subnet (here its 192.168.10.x) from your main network, then you can still plug the Raspberry Pi into your LAN with a cable to download software or troubleshoot via SSH.


/etc/hostapd/hostapd.conf

#change wlan0 to your wireless device interface=wlan0 driver=rtl871xdrv ssid=the-internet channel=1

/etc/network/interfaces

auto lo iface lo inet loopback iface eth0 inet dhcp auto wlan0 iface wlan0 inet static address 192.168.10.1 netmask 255.255.255.0

Notes:

You need to make sure that the WiFi adapter is set up with a static IP address as it will be running the DHCP server and can't assign itself an address. Obviously it needs to be in the same subnet as the DHCP range (shown above).


/etc/init.d/hostapd

#!/bin/sh

### BEGIN INIT INFO
# Provides:             hostapd
# Required-Start:       $remote_fs
# Required-Stop:        $remote_fs
# Should-Start:         $network
# Should-Stop:
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    Advanced IEEE 802.11 management daemon
# Description:          Userspace IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
#                       Authenticator
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON_SBIN=/usr/sbin/hostapd
DAEMON_DEFS=/etc/default/hostapd
DAEMON_CONF=/etc/hostapd/hostapd.conf
NAME=hostapd
DESC="advanced IEEE 802.11 management"
PIDFILE=/var/run/hostapd.pid

[ -x "$DAEMON_SBIN" ] || exit 0
[ -s "$DAEMON_DEFS" ] && . /etc/default/hostapd
[ -n "$DAEMON_CONF" ] || exit 0

DAEMON_OPTS="-B -P $PIDFILE $DAEMON_OPTS $DAEMON_CONF"

. /lib/lsb/init-functions

case "$1" in
    start)
        sleep 15
        log_daemon_msg "Starting $DESC" "$NAME"
        start-stop-daemon --start --oknodo --quiet --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE" -- $DAEMON_OPTS >/dev/null
        log_end_msg "$?"
        ;;
    stop)
        log_daemon_msg "Stopping $DESC" "$NAME"
        start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE"
        log_end_msg "$?"
        ;;
    reload)
        log_daemon_msg "Reloading $DESC" "$NAME"
        start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \
                --pidfile "$PIDFILE"
        log_end_msg "$?"
        ;;
    restart|force-reload)
        $0 stop
        sleep 8
        $0 start
        ;;
    status)
        status_of_proc "$DAEMON_SBIN" "$NAME"
        exit $?
        ;;
    *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2
        exit 1
        ;;
esac

exit 0

Notes:

The only bits changed here are the config file and I added the line sleep 15 as discussed above just under "start)"


/etc/dnsmasq.conf

address=/#/192.168.10.1

Notes:

That's it, the whole thing in one line. The # matches any sequence of characters as domain name and directs them to the local IP address as set in interfaces above.


blinker

#!/usr/bin/env python

import time
from daemon import Daemon
import RPi.GPIO as GPIO
import sys

class MyDaemon(Daemon):
  def run(self):
    GPIO.setup(7,GPIO.OUT)
    while True:
      GPIO.output(7,False)
      time.sleep(1)
      GPIO.output(7,True)
      time.sleep(1)

if __name__ == "__main__":
  daemon = MyDaemon('/tmp/monitor_daemon.pid')
  daemon.test = False
  if len(sys.argv) == 2:
    if 'start' == sys.argv[1]:
      daemon.start()
    elif 'stop' == sys.argv[1]:
      daemon.stop()
    elif 'restart' == sys.argv[1]:
      daemon.restart()
    elif 'test' == sys.argv[1]:
      daemon.test = True
      daemon.run()
    else:
      print "Unknown command"
      sys.exit(2)
    sys.exit(0)
  else:
    print "usage: %s start|stop|restart" % sys.argv[0]
    sys.exit(2)

Notes

This is the daemon that runs to keep the LED flashing in the background. It relies on the same daemon.py that I've used in my server monitor which you can download from that article. To get this to run, I created a symbolic link to blinker in /etc/init.d and then added /etc/init.d/blinker start to a new line in /etc/rc.local.

Section:
Projects
Tags:
linux,
wifi,
The internet,
IT Crowd,
fun,
Raspberry Pi

Comments

Posting comments is not currently possible. If you want to discuss this article you can reach me on twitter or via email.


Contact

Email: nathan@nathandumont.com

Twitter: @hairymnstr

Links