The other day I found myself with no internet connection at home. A storm had come through that night, and knocked the whole area out. So, I had to find another location to work for the day. I found solace at a nearby Starbucks, and I figured all would be fine. The problem was, the type of work I do requires that I have a handful of virtual machines on my laptop with some non-standard networking between them, and enabling the firewall on macOS broke it all. Normally, when I'm at home, I just have the macOS firewall disabled because I'm located safely behind my home firewall on my own network segment.
That was the moment that I realized that my work was not as mobile as I thought it was. I needed a solution.
I happened to have an extra Raspberry Pi Model B+ laying around, along with a couple of USB wifi adapters for it. I decided to see what I could do with it to create my own wifi bridge/firewall, and it works quite well! The overall idea is to have one wifi adapter acting as an access point that my computer connects to, and the other acting as a client connected to whichever wifi network is available. Supporting services include dnsmasq for DHCP and a local caching DNS server, and some iptables rules to safely glue the two interfaces together.
The base system is simply the latest Raspbian Lite, found at https://www.raspberrypi.org/downloads/raspbian/. At the time of this writing, the latest stable version was Jessie, or 8.0. After installing the base image, install all of the available patches.
sudo apt-get update sudo apt-get upgrade
I chose to use wlan0 as the wifi client, and wlan1 as the access point. The iptables rules are relatively simple, so something like ferm was overkill. I just put the rules directly in the network interface configuration. I chose 192.168.9.0/24 because I have 8 other networks allocated at home, and this one would not conflict. Any RFC-1918 subnet will work just fine, though. Just keep in mind that if you choose a common network, like 192.168.0.0/24 or 192.168.2.0/24 or even 10.0.0.0/8 (more common than I like to think about), you will end up with trouble routing, and will have to choose a new internal network on the fly to make things work.
auto lo iface lo inet loopback pre-up iptables -P INPUT DROP pre-up iptables -P FORWARD DROP pre-up iptables -A INPUT -f -j DROP pre-up iptables -A INPUT -i lo -j ACCEPT pre-up iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT iface eth0 inet manual allow-hotplug wlan0 iface wlan0 inet manual wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf pre-up echo 1 > /proc/sys/net/ipv4/ip_forward pre-up iptables -A FORWARD -i wlan1 -o wlan0 -j ACCEPT pre-up iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT pre-up iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE post-down echo 0 > /proc/sys/net/ipv4/ip_forward post-down iptables -D FORWARD -i wlan1 -o wlan0 -j ACCEPT post-down iptables -D FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT post-down iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE allow-hotplug wlan1 iface wlan1 inet static address 192.168.9.1/24 pre-up iptables -A INPUT -i wlan1 -j ACCEPT post-down iptables -D INPUT -i wlan1 -j ACCEPT
Wi-FI Access Point
I used the hostapd package to provide access point capabilities. Install it with
sudo apt-get install hostapd
Add the following line to
And, configure the access point in `/etc/hostapd/hostapd.conf. I chose the super-original SSID of "Raspberry", but name it whatever you want. Also, be sure to set a proper WPA passphrase.
interface=wlan1 driver=nl80211 hw_mode=g channel=6 ieee80211n=1 ap_isolate=1 ssid=Raspberry own_ip_addr=192.168.9.1 wpa=2 wpa_passphrase=supersecretWPApassword wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP CCMP rsn_pairwise=CCMP
DHCP and DNS
Both DHCP and DNS services are provided by dnsmasq. Install it with
sudo apt-get install dnsmasq
Configure DHCP for wan1 by creating a file at
/etc/dnsmasq.d/raspberry.conf with the following content
Getting wlan0 to connect to a wifi network can be done a few different ways. Either add the network manually to
/etc/wpa_supplicant/wpa_supplicant.conf, or use a combination of the followingwpa_cli` commands. Start by running wpa_cli from an ssh session to the raspberry pi
ssh firstname.lastname@example.org wpa_cli
View available networks
> scan OK <3>CTRL-EVENT-SCAN-STARTED <3>CTRL-EVENT-SCAN-RESULTS > scan_results bssid / frequency / signal level / flags / ssid 00:0f:60:05:01:70 2437 -19 [WPA2-PSK-CCMP][ESS] Raspberry 30:85:a9:6b:66:52 2412 -49 [WPA2-PSK-CCMP][ESS] chavet.net 32:85:a9:6b:66:53 2412 -49 [WPA2-PSK-CCMP][ESS] chavet.guest 32:85:a9:6b:66:55 2412 -49 [WPA2-PSK-CCMP][ESS] tweedles 32:85:a9:6b:66:57 2412 -49 [WPA2-PSK-CCMP][ESS] chavet.kids
Use one of the available networks
> add_network 2 > set_network 2 ssid "tweedles" OK > set_network 2 psk “XXXXXXXXXXXX” OK > select_network 2 OK <3>CTRL-EVENT-DISCONNECTED bssid=30:85:a9:6b:66:52 reason=3 locally_generated=1 <3>CTRL-EVENT-REGDOM-CHANGE init=CORE type=WORLD <3>CTRL-EVENT-SCAN-STARTED <3>CTRL-EVENT-SCAN-RESULTS <3>WPS-AP-AVAILABLE <3>CTRL-EVENT-SCAN-STARTED <3>CTRL-EVENT-SCAN-RESULTS <3>WPS-AP-AVAILABLE <3>SME: Trying to authenticate with 32:85:a9:6b:66:55 (SSID='tweedles' freq=2412 MHz) <3>Trying to associate with 32:85:a9:6b:66:55 (SSID='tweedles' freq=2412 MHz) <3>Associated with 32:85:a9:6b:66:55 <3>WPA: Key negotiation completed with 32:85:a9:6b:66:55 [PTK=CCMP GTK=CCMP] <3>CTRL-EVENT-CONNECTED - Connection to 32:85:a9:6b:66:55 completed [id=2 id_str=]
Show saved networks
> list_networks network id / ssid / bssid / flags 0 chavet.guest any [DISABLED] 1 chavet.net any [DISABLED] 2 tweedles any [CURRENT]
Save current config
Saves the current list of networks, and their passphrases to
/etc/wpa_supplicant/wpa_supplicant.conf. Only do this if you really want to remember the network(s) you just configured. Typically, I don't save the networks because I only use this in public wi-fi locations, and don't need to remember any passphrases, etc.
> save_config OK
One last thing that is generally good practice is to add your SSH public key to the raspberry pi, and disable password authentication by adding the following to
The firewall rules added above prevent SSH access from anywhere except the internal network, but it never hurts to be safe.
The Raspberry Pi runs on a simple USB connection. Either use an external battery and keep this in your bag, or plug it in to your laptop's USB port. I typically do the latter.
I've only done a little testing with this setup so far, and it seems to work pretty well. I imagine that a Raspberry Pi 2, or 3, would provide better performance, but I didn't have an extra one of either of those for tinkering. If this becomes a go-to tool for me, I'll likely upgrade it to a Raspberry Pi 3.
Another thing I want to tinker with as time allows is to have the raspberry pi automatically connect to a VPN so all of my traffic is automatically protected from would-be local snoops. From what little I've read, though, the Raspberry Pi 1 B+ can only handle about 3MB/s of throughput using OpenVPN, which is probably not going to cut it. So, for now, I'll let my laptop do the VPN heavy lifting, and let the Raspberry Pi just push packets around.