In my house I have Debian Linux running on an old laptop acting as my router with a Netgear WNDR3700 acting as an access point (WAN port on this is unused). The AP is configured with WPA2 security, but recently I wanted to connect my Nintendo DS to the wifi network. Now the Netgear has guest networks, which is pretty much what I wanted, but it only allows the guest wifi access to the WAN port, which was useless to me. I also wanted to be able to conveniently enable and disable the insecure network with a button on the access point. Knowing that the hardware supported what I wanted to do, and having had good experiences with OpenWRT on another router in the past, I set out to see if I could make it work.
Now the Netgear factory firmware actually is a heavily stripped down old version of OpenWRT. After reading a few of forum posts and wiki pages I decided that I should go for a bleeding edge snapshot version of OpenWRT (r27153). It’s all working very well now :)
First thing, I grabbed openwrt-ar71xx-generic-wndr3700-squashfs-factory.img from the website and flashed it onto the router using the stock firmware’s upgrade page. This process went smoothly and rebooted the router. I then used telnet to connect and was prompted to set a password. That disabled telnetd and enables the dropbear ssh server. I also put an ssh public key into /etc/dropbear/authorized_keys. So far so good.
OpenWRT uses a squashfs as the base read-only filesystem, with jffs2 set up as an overlay filesystem so you can write to anywhere. You can use the builtin opkg package manager to install a bunch of useful software beyond what is built in. Currently I have 2.3M used with 4.2M free :)
I didn’t bother installing a web interface, instead preferring to do all the configuration using the UCI config files in /etc/config. See the UCI docs for a description of what to put in all these files. Whenever you start a service, eg dnsmasq using the /etc/init.d/dnsmasq script, the appropriate UCI files are read, a temporary native config file for the service is created (if appropriate) and any necessary command line args are generated to start the service.
If you’re trying to debug something, you can view the syslog on the device using the logread command. The logger command will echo its arguments to syslog.
Most of the /etc/config/wireless settings are automatically detected. Just set the encryption to psk2 (WPA2 AES) and put in your preferred passphrase and ssid.
The radios on this device support multiple SSIDs. Each of these shows up as a separate network interface in Linux. I chose ‘guest’ as the name for this interface.
config wifi-iface option device radio0 option network guest option mode ap option wmm 0 option encryption none option ssid 'your-guest-ssid'
Quick note, I discovered that leaving wmm (Wireless MultiMedia extensions?) enabled (the default) made SIP VoIP calls from my Nokia wifi clients unusable. It’s easy to disable as seen above.
Now we have our guest wifi network interface, lets set up some firewall rules to isolate it from the main lan.
I’m not using the WAN port on my WNDR3700. There are three interfaces that are relevant. The ethernet switch and my main wifi are both bridged as ‘lan’. This network is served by DHCP and DNS from my Debian router. It is 192.168.1.0/24. I also have the ‘guest’ network, which is not bridged, and gets DHCP and DNS from dnsmasq on the WNDR3700, it uses 192.168.2.0/24. dnsmasq is set to forward DNS requests onto my main router and to explicitly ignore the ‘lan’ interface.
The firewall policy is to disallow everything on the guest network except:
- DHCP/DNS requests to dnsmasq on the WNDR3700
- Packets from 192.168.2.0/24 not addressed to 192.168.0.0/16
That last rule ensures that anything coming from the guest network must be using one of the expected addresses, and also that the guest network cannot send packets to hosts on my main lan. By default OpenWRT allows all related,established packets using Linux iptables’ conntrack module.
Here’s the complete firewall config I’m using: /etc/config/firewall.
My Debian router also needs to know how to route back to the guest wlan subnet.
# route add -net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.3
This can be put into /etc/network/interfaces as a post-up line. It tells the Debian router that whenever it needs to forward traffic from the internet back to the guest wlan it should do so through 192.168.1.3. This is the address of my WNDR3700.
Cron and Button events
I wanted to be able to turn the guest network on and off with the push of a button. I also wanted it to automatically disable itself each night at 3am if I forgot to turn it off.
First thing was to write a simple /root/guest-wifi script to enable/disable the guest wifi network from the command line. Then I’d hook this up to the button hotplug system and cron.
Cron is installed but not enabled by default:
cat > /etc/crontabs/root <<EOT # m h dom mon dow command 0 3 * * * /root/guest-wifi disable EOT ln -s /etc/crontabs/root /etc/crontab /etc/init.d/cron enable /etc/init.d/cron start
Finally, set up the push button:
mkdir /etc/hotplug.d/button cat > /etc/hotplug.d/button/guest-wifi-toggle <<EOT #!/bin/sh if [ "$BUTTON" = "BTN_2" -a "$ACTION" = "pressed" ]; then /root/guest-wifi toggle fi EOT chmod +x /etc/hotplug.d/button/guest-wifi-toggle
You can update and install new packages with opkg, however at some point you may want to upgrade the kernel. Also if you’re using the squashfs images, anything you upgrade is taking up valuable space on the squashfs and the jffs2 overlay.
OpenWRT has a neat solution: sysupgrade. Always make sure to add any files that you want to keep across upgrades to the /etc/sysupgrade.conf file. Any files or directories listed here will be preserved by sysupgrade.