or why you should run Linux on your coffee maker
(updated May 2019)
All my computers run Linux. It gives a shared common platform, which is easy to secure and update. The investment in understanding workstations and servers (both physical and in the, so called, Cloud) is a one time event. I (secretly) smile when people struggle with Windows.
In 2010 I had to replace an old wifi router. I opted for Netgears running OpenWrt and they are still running today (2019). These small devices are so powerful that they can act as little servers. The Netgear WNDR3700 or WNDR3800/N600 runs Linux, even from factory, and I can use it for computing, as well as data storage (it has USB 2.0). Apart from wifi, firewalling, NATing, QoS, I use it the Netgear to control with heyu the lights and waterbed through the X10 over USB. At last count I have five WNDR3700s and WNDR3800s, doing odd jobs and programmed with Coffeescript/Javascript! If your device has enough storage space (internal or external), you may even run Ruby or Python on it, openwrt has binary packages for these scripting languages. Today I updated a router (Aug. 2016). I am still running OpenWrt on five Netgears.
So, why do I want to replace perfectly good software that comes with a device? The reason is that I want predictable systems that I can upgrade and program! Upgrades are important, both for security and features. Recently we got IPv6 out of the box, and it works even on the oldest routers.
As an aside, it may be interesting to know that the Netgears come with a MIPS 24K CPU (680 MHz, 450 bogomips) that runs at low power. The same chip instruction set that has been used in super computers and SGI graphics work horses. The history of MIPS is an interesting read. The WNDR3800 has 12 Mb of flash storage space for software on board and up to 128Mb RAM. An external storage can be hooked up through USB. That is a lot of computer for that money! And it has a lot more computing power than one of the first computers I owned (a 386 having 0.57 bogomips).
My wifi routers are always on devices which handle some traffic load. Sometimes I have them open for outsiders. Some advantages I may have with OpenWRT is to provide a closed and open network. I can combine wifi and LAN networks to appear as one. In addition I may be able to close down a humming backup server in the house, as well as control heating and play music from the router itself. And then, because the router has 2 radios, I can use it as a cheap and generic wifi repeater. Is that all? Probably not. One major advantage of a Linux system is that I get the programmable command prompt. A web interface for managing a device is nice, but being able to program repetitive tasks is much nicer. And you get useful tools, such as nmap, iw and traceroute.
OpenWRT is a Linux distribution for Wireless routers. Googling 'openwrt install WNDR3700' returned a number of useful sites. In particular the instructions on the OpenWrt Wiki. But, do make sure your device is supported by OpenWRT! The 3rd make of the 3700 is not supported - therefore avoid WNDR3700v3. Sometimes the chipset changes even under one model name (blame the manufacturer). Do double check those details.
First I hooked the Netgear up on the network, booted, and attached a laptop through the wifi. The web interface came up. I decided not to worry about saving the standard firmware, as Netgear has it for download and you can rescue this device into failsafe mode even when 'bricked'.
Choose a binary download for the relevant CPU, in this case something like openwrt-ar71xx-wndr3700-squashfs-factory.img from http://downloads.openwrt.org/ and upload it through the web interface (login admin:password, choose router or firmware upgrade, make sure the image matches your device, e.g. wndr3700, wndr3700v2, or wndr3800) using a local cable to the router (could it be that easy?).
After the reboot there was no wireless, so I had to hook up a cable to the router itself and use telnet to 192.168.1.1, but first on the laptop
ifconfig wlan0 down dhclient eth0 # or alternatively set up a virtual interface: ifconfig eth0:1 192.168.1.10 netmask 255.255.255.0 telnet 192.168.1.1
Man! That was easy. Note more recent editions of OpenWrt require you to start with a browser interface http://192.168.1.1/
BusyBox v1.28.4 () built-in shell (ash) _______ ________ __ | |.-----.-----.-----.| | | |.----.| |_ | - || _ | -__| || | | || _|| _| |_______|| __|_____|__|__||________||__| |____| |__| W I R E L E S S F R E E D O M ----------------------------------------------------- OpenWrt 18.06.2, r7676-cddd7b4c77 ----------------------------------------------------- root@OpenWrt:~#
A command prompt!
After changing the root password with 'passwd' you can login with ssh. Your public ssh key can be copied into /etc/dropbear/authorized_keys.
At this point it is probably a good idea to record settings/configuration in /etc and /overlay/etc. I do that with git and (on the smallest routers) with scp and git (on the workstation).
After downloading some packages, as described on the OpenWRT wiki (note later versions apparently don't need this):
root@OpenWrt:~# opkg update root@OpenWrt:~# opkg install wpad-mini kmod-ath9k kmod-leds-wndr3700-usb root@OpenWrt:~# wifi up
a diff shows
--- a/etc/config/wireless +++ b/etc/config/wireless @@ -0,0 +1,36 @@ +config wifi-device radio0 + option type mac80211 + option channel 5 + option macaddr 30:46:9a:0b:91:59 + option hwmode 11ng + option htmode HT20 + list ht_capab SHORT-GI-40 + list ht_capab DSSS_CCK-40 + # REMOVE THIS LINE TO ENABLE WIFI: + option disabled 1 + +config wifi-iface + option device radio0 + option network lan + option mode ap + option ssid OpenWrt + option encryption none + +config wifi-device radio1 + option type mac80211 + option channel 36 + option macaddr 30:46:9a:0b:91:5b + option hwmode 11na + option htmode HT20 + list ht_capab SHORT-GI-40 + list ht_capab DSSS_CCK-40 + # REMOVE THIS LINE TO ENABLE WIFI: + option disabled 1 + +config wifi-iface + option device radio1 + option network lan + option mode ap + option ssid OpenWrt + option encryption none
Remove the disable line and reboot. Done!
Note: if opkg is not working you may need to change the network settings in /etc/config/network.
There even is a web interface. I used it to install an open and a private network - and you know what, I like it.
At this point you should have a fully functional wifi router.
A fresh install has
root@OpenWrt:~# uci show network.wan network.wan=interface network.wan.ifname=eth1 network.wan.proto=dhcp root@OpenWrt:~# uci show network.lan network.lan=interface network.lan.ifname=eth0 network.lan.type=bridge network.lan.proto=static network.lan.ipaddr=192.168.1.1 network.lan.netmask=255.255.255.0
When connecting the WAN it came on and only etc/ppp/resolv.conf was modified. The LAN is a perfect pass through.
My main change is the essid. After editing etc/config/wireless restart
wifi down wifi up
At this stage the wlan is combined with the lan.
One of the brilliant uses of OpenWrt is standard iptables. Here we only allow some hardware MAC addresses to use the WIFI. First list the connected MAC adresses with
cat /proc/net/arp
next add the following rules
iptables -A forwarding_rule -i br-lan -j DROP iptables -I forwarding_rule -i br-lan -m mac --mac-source 00:1f:e2:14:1f:68 -j ACCEPT iptables -I forwarding_rule -i br-lan -m mac --mac -source 00:1d:e0:01:5c:07 -j ACCEPT
These rules can be stored in /etc/firewall.user or /etc/init.d/firewall.
This way you can find MAC addresses without even having to look them up on clients.
opkg update opkg install wpad-mini uci set wireless.@wifi-iface[0].encryption=psk2 uci set wireless.@wifi-iface[0].key="your_password" uci set wireless.@wifi-iface[1].encryption=psk2 uci set wireless.@wifi-iface[1].key="your_password" uci commit wireless wifi
if you see 'WPA: Not enough entropy in random pool for secure operations' on 'wifi' you may want to add to /etc/init.d/boot:
rm /dev/random ; ln -s /dev/urandom /dev/random
Port forwarding is easy too. Edit /etc/config/firewall, or better /etc/firewall.user.
For using ssh on the router from a designated IP address:
config 'rule' option '_name' 'ssh' option 'src' 'wan' option 'target' 'ACCEPT' option 'proto' 'tcp' option 'dest_port' '22' option src_ip '143.99.162.150'
For forwarding a service on a desktop in the network using port 8080:
config 'redirect' 'torrent' option 'src' 'wan' option 'proto' 'tcp' option 'src_ip' '' option 'src_dport' '8080' option 'dest_ip' '192.168.1.21' option 'dest_port' '8080' config 'rule' option 'src' 'wan' option 'proto' 'tcp' option 'src_ip' '' option 'dest_ip' '' option 'dest_port' '8080' option 'target' 'ACCEPT'
and restart the firewall
root@linuxwifi01:~# /etc/init.d/firewall restart &
The netgear has two radios. Therefor it can be used as a repeater.
One one router I use radio0 as a receiver, and radio1 as a transmitter (this also works with a mobile phone tethering). Surprisingly with little speed loss. This page contains instructions for setting up a receiver. What I did:
config wifi-device 'radio0' option type 'mac80211' option channel '11' option hwmode '11ng' option path 'pci0000:00/0000:00:11.0' option htmode 'HT20' list ht_capab 'SHORT-GI-40' list ht_capab 'TX-STBC' list ht_capab 'RX-STBC1' list ht_capab 'DSSS_CCK-40' option mode 'sta'
Not much to it. Now you can have a strong signal everywhere by adding these little boxes running OpenWrt. Make sure every box has it's own unique subnet - conflicting networks are no fun. Also make sure the password is correct - I have been caught out twice that way.
The settings for radio1 are the same as the default wifi. If you screw up, simply move /etc/config/wireless somewhere and run 'wifi detect'.
opkg install kmod-usb2 opkg install kmod-usb-storage opkg install kmod-fs-ext3 opkg install kmod-fs-ext4
Add this to /etc/config/fstab
config mount option target /mnt/extdrive option device /dev/sda2 option fstype ext3 option options rw,sync option enabled 1
and
mount /dev/sda1 /mnt/extdrive
Even better, when you want to use a mobile phone as an uplink you can tether USB.
opkg install kmod-usb-net-rndis ip a
and you'll see usb0 appearing
Modify /etc/conf/network to include
config interface 'usb_wan' option ifname 'usb0' option proto 'dhcp'
That way you'll have both radio's available.
When you are using your router with an uplink it may pay to monitor the network for failure. This script simply does a ping and restarts the network when the ping fails. Run it in CRON as described above.
\#! /bin/sh ping -c 2 nu.nl if [ $? -ne "0" ]; then # echo problem /etc/init.d/network restart fi
To monitor the network you can install tcp
opkg install tcpdump tcpdump -i eth1
An interesting tool is
opkg install iftop iftop -i br-lan
Which shows the network load for each computer. Weed out those torrent users!
And there is nmap. Problem with nmap is that it needs space. But you can install it on an external drive with opkg! So after mounting the USB drive
tell opkg where install in /etc/opkg.conf, add the line
dest usb /mnt/export
and
opkg -dest usb install nmap
now run
/mnt/export/usr/bin/nmap -sP 10.0.0.1/24
it'll complain about a few libraries, which can be symlinked, e.g.
cd /usr/lib ln -s /mnt/export/usr/lib/libdnet.so.1
and I needed to get /etc/services from somewhere.
Even though above looks a bit tedious, it is very exciting that it just works:
Starting Nmap 4.20 ( http://insecure.org ) at 2011-03-29 18:31 CEST Host 10.0.0.11 appears to be up. Host 10.0.0.12 appears to be up. Host 10.0.0.128 appears to be up. Host 10.0.0.132 appears to be up. Nmap finished: 256 IP addresses (4 hosts up) scanned in 4.890 seconds
Having an external USB drive opens tons of possibilities!
When someone maximizes router upload speed, other users may get very slow network speeds. Effectively denial of service. One of the great facilities of OpenWRT is quality of service (QoS). I use qos-scripts currently. For example:
opkg install qos-scripts uci set qos.wan.upload=800 # Upload speed in kBits/s ~ 100 Kbs uci set qos.wan.download=16000 # Download speed in kBits/s uci commit qos
Start
/etc/init.d/qos start
On reboot
/etc/init.d/qos enable
The Internet is running out of the IPv4 address space. OpenWRT is ready for IP6, and can be accessed from outside, provided your ADSL modem can pass it through. See, for example, this tutorial.
Note that IPv6 comes out of the box now (see below).
The next phase required rebuilding the OpenWRT image which you can do by downloading an upgrade image. I wanted serial-usb support for one and use a pcsensor temperature device on another which requires a rebuild. That turned out to be straightforward too - and brought back the days of Linux kernel configuration; so rare these days. Basically, download the source, configure modules and tools using menuconfig and build (all described on mentioned wiki page).
git clone git://git.openwrt.org/openwrt.git cd openwrt vi feeds.conf.default ./scripts/feeds update -a ./scripts/feeds install -a make defconfig make menuconfig make -j 2
Next upload the built img with scp
scp openwrt-ar71xx-generic-wndr3700-squashfs-sysupgrade.bin root@192.168.1.1:
(note the /tmp dir may have more space) and install the image with one command
sysupgrade -v openwrt-ar71xx-generic-wndr3700-squashfs-sysupgrade.bin
The system saves config files (if you remove /etc/config they will get rewritten), flashes the new image, and reboots. This can also be done through the web interface.
Amazingly it just comes up as before. Even the logins are retained.
If you intend to write your own compiled software you'll need to use the OpenWrt SDK. A quick useful HOWTO can be found here. The quickest way to get going is to download an SDK binary for the target architecture. Note that you do not need to do this for the common interpreted languages, including Ruby, Python and JavaScript.
The package system is 'opkg', and is highly inspired by Debian's apt-get. To list all available packages
opkg update opkg list
To make the wifi work again, don't forget to upgrade the earlier packages.
Standard packages I use are
opkg install wpad-mini kmod-ath9k kmod-leds-wndr3700-usb nmap git iftop
For programming OpenWrt comes with Ruby (600K), Python (2 Mb) and Javascript (300K). So I do
opkg install ruby js
Note: rebuilding your image is probably not required as most kernel modules (drivers) are available through opkg. I mounted a USB drive successfully and use it as a backup device now using secure rsync.
For years I have X10 to switch on the house lights and control the heating and waterbed. For this the 'heyu' command line tool does the job and can be installed with OpenWRT
opkg update opkg install kmod-usb-serial-pl2303 opkg install setserial opkg install heyu
Heyu uses the USB to communicate with an X10 device, so first disable the serial terminal by commenting out in /etc/inittab
# ttyS0::askfirst:/bin/ash --login
Restart inittab
sync kill -HUP 1
Heyu has a help system - try 'heyu help' - and configuration is in /etc/heyu/x10.conf. Modify the line
TTY /dev/ttyUSB0
To run on ttyS0 you may need to move it to IRQ 3 with
setserial /dev/ttyS0 irq 3
When you plug in the X10 USB connector, the log should show:
dmesg [ 382.390000] pl2303 2-1:1.0: pl2303 converter detected [ 382.410000] usb 2-1: pl2303 converter now attached to ttyUSB0 heyu info
if above does not show, something is wring with the kernel/modules.
starting heyu_relay 09/08 15:51:50 Poll received unknown value (1 bytes), leading byte = a5 Heyu version 2.9.1 Configuration at /etc/heyu/x10.conf Powerline interface on /dev/ttyUSB0 Firmware revision Level = 8 Interface battery usage = Unknown Raw interface clock: Thu, Day 250, 15:51:51 (--> Civil Time: Thu 08 Sep 2011 15:51:51 UTC) No schedule has been uploaded by Heyu. Housecode = A 0 = off, 1 = on, unit 16.......8...4..1 Last addressed device = 0x0000 (0000000000000000) Status of monitored devices = 0x0000 (0000000000000000) Status of dimmed devices = 0x0000 (0000000000000000)
Now add an alias
ALIAS light1 A1 StdAM
and switch it on from the command line with
heyu on light1
The rest is up to you - read the Heyu documentation. Because Heyu/X10 is command line driven you can use any type of scheduler and web interface to drive your electronics! I wrote a Coffeescript/Javascript state machine for Heyu, which runs on OpenWRT. See the source code on github.
The default dropbear ssh allows you to connect from outside through a reverse ssh server, as described here. Basically
cd mkdir ~/.ssh dropbearkey -t rsa -f ~/.ssh/id_rsa dropbearkey -y -f ~/.ssh/id_rsa | grep '^ssh-rsa' >> authorized_keys
copy that key to the server and you should be able to login the server without a password with 'ssh -i ~/.ssh/id_rsa'. Next, set up a tunnel
ssh -i .ssh/id_rsa -L 42424:localhost:22 -f -N pjotr@myserver.org
now you can login with
ssh -i .ssh/id_rsa -p 42424 pjotr@localhost
Next we try a reverse tunnel
ssh -i .ssh/id_rsa -R 42424:localhost:22 -f -N pjotr@myserver.org
this time login on the remote with
ssh -p 42424 root@localhost
Awesome!
Add the reverse tunnel to a CRON job. Make sure to enable the CRON daemon
/etc/init.d/cron enable /etc/init.d/cron start
The CRON job (adapted from this blog) runs
% 10 * * * * ps |grep thebird|grep -v grep ; test \$? -ne 0 && ssh -i /root/.ssh/id_rsa -R 3702:localhost:22 -f -N pjotr@myserver.org root@OpenWrt:~# cat watch_tunnel.sh #! /bin/sh USERHOST=pjotr@myserver.org RPORT=22 FPORT=3702 CONN=localhost:22 COMMAND="ssh -i /root/.ssh/id_rsa -f -N -R $FPORT:$CONN $USERHOST -p $RPORT" pgrep "ssh" > /dev/null 2>&1 || $COMMAND ssh -i /root/.ssh/id_rsa $USERHOST -p $RPORT netstat -an | egrep \ "tcp.*:$FPORT.*LISTEN">/dev/null 2>&1 if [ $? -ne 0 ] ; then # pkill -f -x "$COMMAND" killall ssh $COMMAND fi
which makes sure only one tunnel is running at a time.
The CRON entry reads:
1 * * * * /root/watch_tunnel.sh 0 */6 * * * killall ssh
Test cron with
crond -c /etc/crontabs -l 0 -f
To get CRON to work correctly, make sure ntpd works! In /etc/config/system
config rdate list server 'ptbtime1.ptb.de' list server 'ntp.xs4all.nl' list server 'ptbtime2.ptb.de'
config timeserver 'ntp' list server 'ntp.xs4all.nl' list server 'ptbtime1.ptb.de' option enable_server '0'
Note, this does not start ntp at reboot. You may want to add
/sbin/ntpd -g -u ntp:ntp -p /var/run/ntpd.pid
to /etc/rc.local.
Even git is supported on openwrt, and takes only 2Mb of your drive! Very useful when you start tweaking settings.
opkg update opkg install git cd /etc git init git add . git commit -a -m 'first commit'
To tell it to use an ssh key, you need to wrap the ssh command
cat /usr/bin/sshwkey #! /bin/sh ssh -i /root/.ssh/id_rsa \$* chmod a+x /usr/bin/sshwkey
Test it by logging in to your remote server. Next tell git to use this script for ssh access
export GIT_SSH=/usr/bin/sshwkey
The following are the stats of a freshly installed OpenWrt WNDR3700 (v1) router with 64Mb of RAM. This is after a full day of use using two wifi radios and LAN to access the internet:
Mem: 31996K used, 29072K free, 84K shrd, 2080K buff, 6088K cached CPU: 0% usr 0% sys 0% nic 98% idle 0% io 0% irq 0% sirq Load average: 0.00 0.01 0.05 1/37 1688 PID PPID USER STAT VSZ %VSZ %CPU COMMAND 1544 1 root S 1648 3% 0% /usr/sbin/hostapd -P /var/run/wifi-ph 1688 1353 root R 1364 2% 0% top 1558 1 root S 1648 3% 0% /usr/sbin/hostapd -P /var/run/wifi-ph 838 1 root S 1568 3% 0% /sbin/netifd 804 1 root S 1532 3% 0% /sbin/rpcd 1 0 root S 1408 2% 0% /sbin/procd 1366 1 root S 1364 2% 0% /usr/sbin/ntpd -n -S /usr/sbin/ntpd-h 1353 1352 root S 1364 2% 0% -ash 1603 1602 root S 1364 2% 0% -ash 1230 838 root S 1360 2% 0% udhcpc -p /var/run/udhcpc-eth1.pid -s 1352 896 root S 1244 2% 0% /usr/sbin/dropbear -F -P /var/run/dro 1602 896 root S 1244 2% 0% /usr/sbin/dropbear -F -P /var/run/dro 863 1 root S 1164 2% 0% /usr/sbin/odhcpd 896 1 root S 1152 2% 0% /usr/sbin/dropbear -F -P /var/run/dro 795 1 root S 1044 2% 0% /sbin/logd -S 16 1284 1 nobody S 952 2% 0% /usr/sbin/dnsmasq -C /var/etc/dnsmasq 455 1 root S 892 1% 0% /sbin/ubusd 1228 838 root S 800 1% 0% odhcp6c -s /lib/netifd/dhcpv6.script 456 1 root S 772 1% 0% /sbin/askfirst /bin/ash --login qd^C3 2 root SW 0 0% 0% [ksoftirqd/0] root@huuske-fb:~# df Filesystem 1K-blocks Used Available Use% Mounted on rootfs 4224 1424 2800 34% / /dev/root 2304 2304 0 100% /rom tmpfs 30532 84 30448 0% /tmp /dev/mtdblock5 4224 1424 2800 34% /overlay overlayfs:/overlay 4224 1424 2800 34% / tmpfs 512 0 512 0% /dev root@huuske-fb:~# free total used free shared buffers Mem: 61068 32068 29000 84 2080 -/+ buffers: 29988 31080 Swap: 0 0 0 root@huuske-fb:~# df -h Filesystem Size Used Available Use% Mounted on rootfs 4.1M 1.4M 2.7M 34% / /dev/root 2.3M 2.3M 0 100% /rom tmpfs 29.8M 84.0K 29.7M 0% /tmp /dev/mtdblock5 4.1M 1.4M 2.7M 34% /overlay overlayfs:/overlay 4.1M 1.4M 2.7M 34% / tmpfs 512.0K 0 512.0K 0% /dev root@huuske-fb:~#
One router was installed over 4 years ago (in 2012) and faithfully running since(!). Upgrading the device to a recent 'chaos_calmer' (not least to get IPv6 support) it is probably wise to wipe the configuration in /etc. After doing a system upgrade as described above run 'firstboot' to erase all settings. After a reset/reboot the clean system should come up on telnet 192.168.1.1 again. To get a minimal system I did additionally
opkg update opkg install nmap iftop tcpdump curl opkg install wget git ruby js kmod-usb-storage kmod-fs-ext3 kmod-fs-ext4
note that many modules are already included these days. Also, the oldest WNDR3700 may not have the space to include largish git, nmap, ruby etc.
Set the root password with
passwd
so ssh opens and telnet closes (the device is fully firewalled from the outside), and from the remote copy the fresh configuration with
scp -r root@192.168.1.1:/etc . cd etc git init git add . git commit -a -m 'init'
now we can keep track of changes with git on your work station which also acts as a backup.
opkg remove --force-removal-of-dependent-packages luci uhttpd
reboot and check the ps table.
After setting the password ssh is open through the lan and wifi, but not from the wan. I prefer to disable password access too. Create an RSA key (I keep one for the routers) and cp it into /etc/dropbear/authorized_keys. Make sure the file has 0600 permission.
When that works set passwordAuth to 'off' in /etc/config/dropbear.
Coming from another computer you should no longer have ssh password access. With key access I opened the wan also, so in /etc/conf/firewall
config rule option src wan option dest_port 22 option target ACCEPT option proto tcp
If you brick a router, openwrt has a failsafe mode which will allow telnet access again.
You should try it. Switch the router off and then on. When the broadcast light blinks hit a button. It should start blinking faster. Next you can telnet to 192.168.1.1. Reboot to get out of failsafe again.
IPv6 comes out of the box! 'ifconfig' should show inet6 addr for all network devices, including the ones that get connected to the wifi. Awesome. Check the router wan interface with
route -6 ping6 fd57:348:5d34:0:3246:9aff:fe0b:915a nmap -6 fd57:348:5d34:0:3246:9aff:fe0b:915a ssh -i openwrt_key -v -6 root@fd57:348:5d34:0:3246:9aff:fe0b:915a
and we have a shell prompt. From the lan you can do
ssh -6 -i openwrt_key root@fd2b:e412:1d9a::1