I have been informed that my article, “Building DIY Community Mesh Networks,” has been published in the Autumn 2016 issue of 2600: The Hacker Quarterly.
Please feel free to reach out for any additional information.
I have been informed that my article, “Building DIY Community Mesh Networks,” has been published in the Autumn 2016 issue of 2600: The Hacker Quarterly.
Please feel free to reach out for any additional information.
Now that we have OpenWRT installed and ensured that we have enough space to experiment and install packages, we can proceed to install and configure cjdns.
I have opted to install a GUI package to allow for easier configuration (though I also wanted to see what it had to offer over editing configuration files). The package used here is luci-app-cjdns, relying on the LuCI interface that comes default in most OpenWRT images. If you want to install cjdns without the GUI or do not use LuCI, you can install the regular cjdns package. Note: The standard cjdns package was left out of OpenWRT 15.05.1, but should be in the older 15.05 image. The luci-app-cjdns package should be available in both versions, so you won’t have any issue with the remainder of this guide.
Now we are ready to install cjdns for LuCI. SSH into the access point and run the following command to update and install luci-app-cjdns.
opkg update && opkg install luci-app-cjdns
After this finishes, leave the SSH session open and then load up the OpenWRT web console in a browser and log in. By default, this interface can be reached via http://192.168.1.1. Now that we’re in the console, select cjdns from the Services dropdown on the top menu. An Overview page for cjdns will load (and look rather empty). Now, click the Peers sub-tab link near the top of this page.
Now, we can enter in the peering information for any number of peers to connect to. You will likely want to populate the Authorized Passwords and Outgoing UDP Peers sections as I have below.
When finished, press the Save & Apply button to commit any changes and restart cjdns. These steps can be repeated to add as many peers as needed.
Now, navigate back to the Overview page by clicking on the Overview sub-tab link.
After loading, we should now have connection information about the configured peers as shown below.
That’s all there is to it! Back in our SSH session, we can try pinging a machine on Hyperboria to confirm a connection:
ping6 h.peer0.famicoman.com PING h.peer0.famicoman.com (fc9f:990d:2b0f:75ad:8783:5d59:7c84:520b): 56 data bytes 64 bytes from fc9f:990d:2b0f:75ad:8783:5d59:7c84:520b: seq=0 ttl=42 time=4072.631 ms 64 bytes from fc9f:990d:2b0f:75ad:8783:5d59:7c84:520b: seq=1 ttl=42 time=3800.924 ms 64 bytes from fc9f:990d:2b0f:75ad:8783:5d59:7c84:520b: seq=2 ttl=42 time=4594.193 ms 64 bytes from fc9f:990d:2b0f:75ad:8783:5d59:7c84:520b: seq=3 ttl=42 time=4329.846 ms ^C --- h.peer0.famicoman.com ping statistics --- 9 packets transmitted, 4 packets received, 55% packet loss round-trip min/avg/max = 3800.924/4199.398/4594.193 ms
If all went as expected, you now have cjdns running on your OpenWRT router! This can be expanded in the future by copying an OpwnWRT configuration onto several routers, and then linking them together wirelessly.
If you have any low-memory OpenWRT device (4MB of flash) you will probably fill up any free space quickly after the initial OpenWRT install and need more room to grow. Luckily, you can transfer your root file system to a flash drive and boot off of it as long as your access point has a USB port.
If you are following along with our Western Digital N600, you probably don’t need to do this. The N600 comes equipped with 12MB of built-in flash, more than enough to accommodate the software packages we will install in the future. If you have less than this or want to have a nice learning exercise, read on!
You are going to need a Linux machine and a flash drive. The flash drive size shouldn’t matter too much. A lot of people run OpenWRT off of 8MB of internal flash, so any small drive should have plenty of room.
On your Linux machine, plug in the flash drive (mine is a ~10 year old 64MB), and run dmesg to get the kernel message buffer.
You should get a lot of output, but importantly at the end, we should see our flash drive being recognized.
[26913.782811] usb 1-1.4: new high-speed USB device number 4 using dwc_otg [26913.883754] usb 1-1.4: New USB device found, idVendor=0457, idProduct=0151[26913.883779] usb 1-1.4: New USB device strings: Mfr=0, Product=2, SerialNumber=3 [26913.883796] usb 1-1.4: Product: USB Mass Storage Device [26913.883812] usb 1-1.4: SerialNumber: 00000000004FDE [26913.884913] usb-storage 1-1.4:1.0: USB Mass Storage device detected [26913.887282] usb-storage 1-1.4:1.0: Quirks match for vid 0457 pid 0151: 80 [26913.887450] scsi host0: usb-storage 1-1.4:1.0 [26914.884185] scsi 0:0:0:0: Direct-Access Staples 0.00 PQ: 0 ANSI: 2 [26914.886688] sd 0:0:0:0: [sda] 124000 512-byte logical blocks: (63.4 MB/60.5 MiB) [26914.887210] sd 0:0:0:0: [sda] Write Protect is off [26914.887235] sd 0:0:0:0: [sda] Mode Sense: 00 00 00 00 [26914.887748] sd 0:0:0:0: [sda] Asking for cache data failed [26914.887771] sd 0:0:0:0: [sda] Assuming drive cache: write through [26914.916959] sda: sda1 [26914.920057] sd 0:0:0:0: [sda] Attached SCSI removable disk [26914.922645] sd 0:0:0:0: Attached scsi generic sg0 type 0
We see that our physical device is sda, with one partition sda1. Your drive/partition may be labeled differently depending on how many drives you have installed or plugged into your machine, and how many partitions your flash drive has. We can verify we are looking at our flash drive by listing via fdisk.
fdisk -l /dev/sda
You will get a lot of informative output about the device:
Disk /dev/sda: 63 MB, 63488000 bytes 16 heads, 32 sectors/track, 242 cylinders, total 124000 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x91f72d24 Device Boot Start End Blocks Id System /dev/sda1 * 32 123999 61984 b W95 FAT32
Now we will go ahead and format the drive as ext4. First however, we need to create a partition by running the fdisk command on the drive (without the -l option).
This is an interactive utility, so when prompted, enter d to delete the current partition on the drive. Then enter n for a new partition (taking the defaults by pressing the return key). Finally, enter w to apply the changes to the disk and exit.
Now, we can make a file system on the partition we just created, formatting it as ext4:
Afterwards we can list with fdisk again to see our changes:
fdisk -l /dev/sda Disk /dev/sda: 63 MB, 63488000 bytes 3 heads, 32 sectors/track, 1291 cylinders, total 124000 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x91f72d24 Device Boot Start End Blocks Id System /dev/sda1 2048 123999 60976 83 Linux
You can now remove your USB drive from your Linux machine and plug it into your OpenWRT device.
Next, we ssh into our OpenWRT device and login as root. We need to install a few utilities with opkg before we can switch over the root filesystem.
opkg update && opkg install block-mount kmod-fs-ext4 kmod-usb-storage fdisk nano
Now we will run fdisk to see that our drive is recognized:
root@OpenWrt:~# fdisk -l Disk /dev/mtdblock0: 256 KiB, 262144 bytes, 512 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock1: 64 KiB, 65536 bytes, 128 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock2: 64 KiB, 65536 bytes, 128 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock3: 64 KiB, 65536 bytes, 128 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock4: 15.5 MiB, 16252928 bytes, 31744 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock5: 1.3 MiB, 1310720 bytes, 2560 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock6: 14.3 MiB, 14942208 bytes, 29184 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock7: 12.1 MiB, 12648448 bytes, 24704 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mtdblock8: 64 KiB, 65536 bytes, 128 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/sda: 60.6 MiB, 63488000 bytes, 124000 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x91f72d24 Device Boot Start End Sectors Size Id Type /dev/sda1 2048 123999 121952 59.6M 83 Linux
My drive registers as /dev/sda1, and this is used through the commands below. Make sure you take note of yours and make the necessary changes when running additional commands.
Next, we will copy our filesystem over and set the device to boot from the flash drive. If you are squeamish about making this change via a terminal, scroll down and view the sources referenced at the end of this tutorial. There is a way to perform this configuration using OpenWRT’s default graphical interface: LuCI. If you prefer to issue commands over ssh, read on.
Now, we will actually mount the drive, and copy the root filesystem to it:
mkdir /mnt/sda1 mount /dev/sda1 /mnt/sda1 mkdir -p /tmp/cproot mount --bind / /tmp/cproot tar -C /tmp/cproot -cvf - . | tar -C /mnt/sda1 -xf - umount /tmp/cproot
After we have moved the filesystem over, we can modify the fstab with our editor of choice.
Paste the following at the top the file and save it. This will use the flash drive as the primary filesystem and preserve this configuration even after reboot.
config mount option device '/dev/sda1' option target '/' option fstype 'ext4' option enabled '1'
Finally, we reboot the device by issuing the reboot command:
After the system comes back up, ssh into it once more and run the df command.
In the output, pay attention to the Size column to make sure it matches up closely to your flash drive’s capacity to verify that you are actually running off of the flash drive.
Filesystem Size Used Available Use% Mounted on rootfs 53.7M 9.7M 39.8M 20% / /dev/root 2.3M 2.3M 0 100% /rom tmpfs 61.6M 628.0K 61.0M 1% /tmp /dev/sda1 53.7M 9.7M 39.8M 20% / tmpfs 512.0K 0 512.0K 0% /dev
That’s all there is to it! Now, you are booting directly off of the flash drive and have more room to install packages. Additionally, you may want to save an image of your drive for future use. You never know when you will be trying something out and need to restore from a backup!
For $10, I didn’t think I was getting a whole lot, but these devices sport a popular Atheros chipset and are perfectly compatible with OpenWRT’s latest version (Chaos Calmer 15.05 at the time of writing). For the uninitiated, OpenWRT is an alternative firmware for routers that allows for an advanced set of features and more customization.
The first (and sometimes daunting) task in this process is to flash the firmware on to the device, but this is easy to accomplish with the help of the OpenWRT Wiki page for the N600.
One issue I’ve found is that the page states that the web updater doesn’t work on most N600 devices and that it is preferable to use telnet. Being the console junkie I am, I tried the telnet method first but had no way to configure or enable it! I found I couldn’t use telnet but ultimately was able to flash via the web interface.
Adapted from the wiki, here are the steps I took to flash my device. Any additions/modifications by me are in bold:
0) Turn on and configure the device. I couldnt do anything until i completed the initial setup.
1)Download the file openwrt-ar71xx-generic-mynet-n600-squashfs-factory.bin. I pulled it down from
2) Configure your computers IP address to 192.168.1.10 and connect to a LAN port in the router.
3) Turn the router off.
4) Using a paperclip, press and hold the reset button on the bottom of the router and turn it on. Hold the reset button for at least 15 seconds. Wait until the power light on the front is slowly flashing on and off.
5) On your computer, visit http://192.168.1.1 NOTE: You will not be able to ping this address.
6) Upload the file openwrt-ar71xx-generic-mynet-n600-squashfs-factory.bin as downloaded earlier.
7) The router will now flash OpenWRT. This will take a couple of minutes to achieve. You can ping 192.168.1.1 and watch for ping replies to see when your router has rebooted into OpenWRT.
That’s all there is to it. After OpenWRT boots for the first time, youll be able to configure it to work on your local network. At most,I suggest setting a root password!
This process is pretty adaptable to other hardware, and the OpenWRT wiki is invaluable when it comes to specific steps to flash OpenWRT on any device you may have around. Dont feel like you have to get an N600 because I did, a lot of hardware is supported (I would recommend something with two radios and 8MB of flash for maximum hackery)!
This tutorial is just the first in a series where we will get cjdns configured on your OpenWRT router. The more meshing, the merrier!
If you have not heard yet, Adam Longwill of Meta Mesh has discovered that TP-Link, a prominent wireless access point vendor, has started to lock down firmware on some of their routers resulting in routers that are difficult or impossible to flash with open firmware such as OpenWRT. Ubiquiti, another popular vendor, is also on track to follow suit.
You can find a full write-up from Meta Mesh, titled The Lockdown is Here, on their website. It is an important read.
Currently on the BattleMesh mailing list, there are discussions of alternative hardware that can still be used, and even potential plans for small orders of “unlocked” hardware to benefit the community as a whole.
As I was planning on getting a low-tier TP-Link device to experiment with, this delays my plans. However, I am looking at hardware from other vendors to continue my work, and hope to provide updates and create new tutorials as soon as I have the ability.
Hopefully this issue is only a small speed bump on the road to more accessible wireless mesh networking.
If you host a node at a residential location, you probably do not have the comfort of a static IP address, one which does not change. Residential Internet accounts usually have the unfortunate side effect of occasional public-facing IP address changes, meaning you have a dynamic IP address. If you give out your peering information to others with your IP address and it changes, these credentials will fail until you are able to supply all of your peers with an updated IP address. Even after you discover the issue, it could take a while for all of your peers to adopt the new information, causing plenty of broken connections.
To solve this problem, we can use dynamic DNS, and get you a domain name to use in place of your IP address by acting as a pointer to it. There are many providers that do this including Duck DNS and FreeDNS. Almost all of them allow you to create subdomains (like yoursupercoolsub.duckdns.org) which behind the scenes point to your IP address. In DNS lingo, this is called an A record (or AAAA record if you have an IPv6 address). Most of these services also allow you to download a client to automatically update your IP address for the record if it changes, so you can just distribute the subdomain’s name to your peers and not worry about unexpected changes.
This works well, but I (and possibly some of you) have a paid domain set up through CloudFlare’s DNS. Instead of famicomans-node.duckdns.org, I would prefer to use my own domain and configure something like node.famicoman.com to act as a pointer to my IP address. Now, I could make a record with a dynamic DNS provider (like famicomans-node.duckdns.org) and have node.famicoman.com point to it instead of the IP address directly (this is called a C record) but that would require me to sign up for another service and configure the two to work together.
Instead of this, I decided to use CloudFlare directly, working with their API, some scripting, and a cron job.
The following assumes that you have registered at CloudFlare and have already added your domain to its care. We also assume that your cjdns installation is on a Linux machine, or you have access to one on your home network.
Before doing anything else, you need to retrieve your CloudFlare API key. Log into the CloudFlare console and navigate to My Settings. Scroll down until you find the API Key item and press the button labeled View API Key. After your API key displays, record it for use later.
Now, navigate to the DNS tab for your domain name. Create a new A record for your public IP by specifying a name (I chose “node”) and a dummy IP address (I used “22.214.171.124”). It doesn’t matter what IP address you supply as it will be updated later. Afterwards, press the green Add Record button.
The record should now display below with a gray cloud icon next to it. This shows that CloudFlare’s CDN services are not active for the record (which is what we want) and that this sub domain name will resolve the IP address directly.
Now on your cjdns node, we can start to configure automatic updates.
First, we need to set up some directories. Log into a non-root account and execute the following to create and change into our new directory. I like to put each of my scripts in its own folder under a ‘scripts’ folder in my home directory, but feel free to use a different location.
mkdir -p ~/scripts/cloudflare-update-record cd ~/scripts/cloudflare-update-record
Now, we will download a gist with a CloudFlare update script, saving it as ‘cloudflare-update-record.sh’. As always, it is unwise to blindly execute something from a random script on the Internet, so review the code to check for any funny business. You can see updates to and comments on this script here.
Now we will edit the script to supply credentials for connecting to and updating our CloudFlare record.
Near the top of the file, there are four fields you need to set with some values. Enter your email as the auth_email, your API key from earlier as the auth_key, your root domain as the zone_name, and your subdomains name as the record_name. Below is an example of what these fields might look like filled out.
auth_email="email@example.com" auth_key="a456a7b68cb9ac65b34c2b43b3c6bc4c2b4" # found in cloudflare account settings zone_name="famicoman.com" record_name="node.famicoman.com"
Now we want to change permissions so only you can read, write, and execute the script (we wouldn’t want any other users peeking at your API key), and finally execute the script to test it out.
chmod 700 cloudflare-update-record.sh ./cloudflare-update-record.sh
If all goes to plan, you should receive output similar to the following in your console:
>>> IP changed to: 127.112.6.34
If you don’t get a message that your IP is changed, go back and check the credentials you entered into cloudflare-update-record.sh and make sure they are correct.
Additionally, we can check cloudflare.log to see a time-stamped account of our execution.
cat cloudflare.log [Tue 9 Feb 22:32:30 UTC 2016] - Check Initiated [Tue 9 Feb 22:32:33 UTC 2016] - IP changed to: 127.112.6.34
Now, we want to have this script run automatically to reduce downtime. I’ve opted to set this script up to run every 10 minutes and schedule it with cron.
Bring up your crontab with the following command:
Scroll to the bottom of the file in your editor and paste the below command on a new line. Every 10 minutes, every hour, every day of the month, every month, and every day of the week this job will run by changing to your cloudflare-update-record directory and then executing cloudflare-update-record.sh.
*/10 * * * * cd ~/scripts/cloudflare-update-record && /bin/bash ~/scripts/cloudflare-update-record/cloudflare-update-record.sh
After saving (C-x), the new job will become active. We can watch the job go off by tailing the cloudflare.log file.
tail -f cloudflare.log
It will take some time depending on when you first save the crontab, but you should see records written to the log in realtime, every 10 minutes starting on the hour.
[Tue 9 Feb 22:32:30 UTC 2016] - Check Initiated [Tue 9 Feb 22:32:33 UTC 2016] - IP changed to: 127.112.6.34 [Tue 9 Feb 22:40:02 UTC 2016] - Check Initiated [Tue 9 Feb 22:50:02 UTC 2016] - Check Initiated [Tue 9 Feb 23:00:02 UTC 2016] - Check Initiated
That’s all there is to it, you can now distribute your connection details using a subdomain on a registered domain name instead of your IP address. Keep in mind that this can be scaled to multiple nodes by giving them multiple subdomain names (node1, node2, etc.) for easy rememberability.
Yesterday, I deployed two nodes running cjdns, ready to peer with other nodes nearby! These nodes will be online 24/7 and are backed by different Internet service providers, which will hopefully provide a reasonable level of redundancy.
While these nodes currently lack wireless connectivity, I am looking into options to either configure them for wireless access, use them as Hyperboria gateways which other networking equipment can route through, or acquire new wireless hardware to run cjdns directly. That said, these nodes are fully functional and able to peer with others wishing to connect to Hyperboria over the Internet, lending a hand in creating a new mesh in the area after such a long absence.
If you’re in the region (PA, NJ, DE, MD) and want to connect, I am more than willing to offer you peering credentials for both nodes. You can check out the location of each node and add your own potential node on the map below.
Feel free to contact me with any questions or comments. The official installation instructions can be found here for a variety of operating systems, but I’m happy to help as well. Typical installation takes anywhere between five minutes and an hour, only requiring a dozen or so commands. Peering requests from anyone ready to connect may take a few days, but I’ll be sure to get to each one!
I hope this helps breathe new life into the Philly Mesh community, and I’ve already reached out to a few people interested in participating.
If you’re interested in joining the mesh and have been holding out, now is the time!
If you’re like me, you have a few Raspberry Pis kicking around, waiting for a job to do. I adopted early and purchased (at least one) original Model B with 256MB of RAM. This was a nifty little box four years ago, but has since been overshadowed by its older brother, the revised Model B with 512MB of RAM, and its cousins: the B+ and RPi 2. These originals still have life left in them, and can often be found below the original $35 price tag. When it comes to running cjdns, they do a fantastic job!
This post assumes you have a Raspberry Pi, power adapter, sd card, and enough smarts to hook the Pi up to your network and feed it a Raspbian image. This should work for any Model B Raspberry Pi, from the original up to the Raspberry Pi 2.
The Hyperboria documentation offers a guide on installing for Debian Jessie, but it fails on the Raspberry Pi out of the box. Prior to this, I was running Raspbian Wheezy with few issues in relation to cjdns, but other work I wanted to do had me yearning for a more up-to-date distribution. I grabbed Raspbian Jessie from the official download site (Release date 2015-11-21), loaded it onto my SD card, and booted up.
On an original Raspberry Pi, this process takes a while. At this point, start yourself a pot of coffee and then log on to your pi using the default username and password, pi/raspberry. I run headless, so everything will be done from the console over ssh, but that shouldn’t matter too much.
We are going to install cjdns as a service, so let’s change over into root to make this a little more comfortable.
If you have a fresh installation, be sure to run config and expand to fit the full size of your SD card, overclock if you want, and restart the pi when done. After restarting, log in again and change back to root.
I also cannot express how important it is to change the default user and root passwords.
passwd pi passwd root
Now, we want to update, upgrade, and install some dependencies.
apt-get update apt-get upgrade apt-get install nodejs build-essential git
Somewhere during these commands, your coffee should have finished. Go pour a cup and come back to watch the console until everything is tidied up.
Afterwards, we are going to start building cjdns by pulling down the latest code and building.
cd /opt git clone https://github.com/cjdelisle/cjdns.git cd cjdns NO_TEST=1 Seccomp_NO=1 ./do
Pay close attention to this last line. We need to execute ./do in this fashion because of a current issue with the kernel on Raspbian Jessie.
After a little wait, the build should finish successfully. Now we want to configure cjdns to run as a daemon, so let’s create a link to the binary, generate a configuration file, and copy over the service file.
ln -s /opt/cjdns/cjdroute /usr/bin (umask 077 && ./cjdroute --genconf > /etc/cjdroute.conf) cp contrib/systemd/cjdns.service /etc/systemd/system/
All that’s left is to enable the service and start it up. Afterwards, it should start on every boot-up automatically.
systemctl enable cjdns systemctl start cjdns
If you want to edit your cjdroute.conf for adding peers or… well… anything else, simply edit the file in /etc/cjdroute.conf and restart the service.
nano /etc/cjdroute.conf systemctl restart cjdns
At any point, you can check the status of the service:
In the output, you should see the following:
cjdns.service loaded active running cjdns: routing engine designed for sec...
Troubleshooting & Debugging
If at any point you want to check the output generated by starting cjdns, stop the service and run cjdroute manually.
systemctl stop cjdns /opt/cjdns/cjdroute < /etc/cjdroute.conf
Ocasionally, you may get a Configurator error like this below:
1454470218 CRITICAL Configurator.c:97 Failed to make function call [Timed out waiting for a response], error: [UDPInterface_beginConnection]
If this happens, run the following before starting cjdroute again to ensure that the ipv6 kernel module is loaded:
That's all it takes, you now have a node capable of connecting to Hyperboria! Now, all you need to do is find some peers, add them to your configuration file, and join the network!
The first time I remember hearing about mesh networks was sometime around 2005. Through rigorous searches, I had finally tracked down a complete run of Seattle Wireless TV, a proto-podcast that ran from July of 2003 until June of 2004. This hunt was undergone for my own personal interests; I was and am something of an online-video-series junkie, and I have since posted all the episodes for download on Archive.org where they will be preserved for anyone to watch for years to come. The topics of these episodes varied from interviews with operators, to wardriving tips, and even antenna creation. Pretty popular topics back then, but now the show serves as a fantastic time capsule from a technologically-simpler time. Even ten years ago, “getting into” wireless networking seemed radically different. Everyone tried their hand at wardriving, embraced 802.11g, and wired cantennas to their Orinoco cards. Here is a prime example of the times — some Seattleites setting up their own mesh network in 2002. Essentially, Wi-Fi was king and you could have it in your own home. I didn’t end up jumping into the mix until years later. I got my first laptop in 2006 and even then I usually embraced a wired connection. Watching these video shows was my own little outlet into what the cool kids were doing. It wasn’t until a little later that I decided it was time to play.
In 2007, I received a La Fonera router from Fon courtesy of a free giveaway (I actually managed to snag one on the very last day they offered the promotion). I thought it might be cool to join their Wi-Fi collective, but I was much more interested in what else I could do with the device. The day it came in the mail I promptly researched what others were doing with it and joined in on the popular act of flashing dd-wrt firmware onto the little device to get some expanded functionality. This process was harder than I expected and my lack of knowledge on the subject at the time showed. After many frustrating hours — flipping back and forth between telnet, tftp, and IRC chatter — I had a fully functioning dd-wrt router of my very own. While this was a feat all in itself, it went on to inspire me to see what I could do with other routers. I soon grew a little collection of second-hand Linksys WRT54G routers to tinker with and take up space on my work bench. I tried out different firmwares like OpenWrt and Tomato and always tried to keep something new running on a separate network for me to play with so I didn’t accidentally bring down the whole house’s internet access with a bad flash or misconfiguration.
Years later, I ended up working with wireless technology in a professional capacity. However, I was no longer handling everyone’s favorite suite of 802.11 protocols but the new-fangled 802.15.4 for low-rate wireless personal area networks. I focused on the ZigBee specification and its derivatives, which were and are a popular choice for technologies like home automation systems, wireless switches, electrical meters, etc. I spent months toying with the technology, working to understand the encryption, capture and dissect the traffic, and create and transmit my own custom packets. While the technology itself was enough to hold my interest, I felt a draw toward the technology’s use of wireless mesh networking to create expansive networks.
This wasn’t my first foray into the world of mesh networking per se. Prior to my work with ZigBee, I focused on meshing briefly to combat network interruption when creating the topology for a hobby-run IRC network I was administrating. This was, however, my first time applying mesh ideas wirelessly. I quickly learned the ins and outs of the Zigbee specification and the overarching 802.15.4 standard, but I couldn’t help thinking about how these technologies applied to Wi-Fi and how much fun an 802.11 mesh network would be.
Soon, I discovered the existence of Philly Mesh, a Philadelphia-based mesh network in its infancy that connected with Hyperboria: a global decentralized network of nodes running cjdns. I made a few posts to its subreddit, added my potential node to the map, and ordered some TP-Link routers to play with. While the group seemed to be gathering support, it ultimately (and much to my dismay) stagnated. Expansion stopped and communication dwindled. People disappeared and services started to fall apart. Over the next year I tried to work through getting my own node up but hit several setbacks. I bricked a router, ran into configuration problems, suffered from outdated or missing documentation, and then bricked another router. Eventually, after a seemingly endless process of torment and discovery, I connected to the network using a Raspberry Pi. My first cjdns node was up.
After this, I made a push to revive the Philly Mesh project. I constructed a new website, revived some of the services, and started my push for finding community involvement. Though it stands to be a slow process, things are coming together and people are coming forward. Whether or not we will have a thriving mesh network in the future is unknown, but the journey in this case interests me just as much as the destination.
As of now, I’m embracing wireless mesh as a hobby. I still have a pile of routers to play with and test firmware on, and am getting new hardware every so often. As for the bricked TP-Links, I’ve picked up USB/TTL adapter in an attempt to correct my wrongdoings and get cjdns set up properly. I’m also constantly playing with my settings on the Raspberry Pi installation as I have to firewall things off, assure reliability for an application crash, and generally make sure things are running smoothly. Additionally, I’ve been toying around with different technologies to set up an access point through the Raspberry Pi such as a USB/Ethernet adapter to bridge a connection between an old router and the Pi, and a USB dongle to create an access point in a more direct model. Aside from the Raspberry Pi and assorted routers, I’m also interested in getting cjdns installed and configured on plug computers like the Pogoplug and single board computers like the BeagleBone Black.
Where will all of this take us? Hopefully this is a stepping stone on the way to building a thriving local mesh, but the future is unknown. I’d love to get some nodes set up wirelessly within the city, but I’m only one person out in the suburbs tinkering away. While I’m sitting here learning about setting up devices, I only hope to share what I find with others who might benefit from having someone else carve out an initial path. I, by myself, can work to build a local mesh but it wouldn’t be nearly as robust or expansive as if I worked within a team sharing ideas and experience.
If you’re reading this, you have the interest. You may not have the know-how, the money for high-tech equipment, or a location nearby other potential operators, but you have the desire. If there’s anything that I’ve learned throughout my ongoing mesh adventure, it’s that good things take time and nothing happens overnight.
Tomorrow, we can work to build a strong mesh for our city. As for today, why don’t we get started?