Want to build a WiFi Repeater? Well it’s pretty sweet, and I’ll show you one way to make it happen.
Why I Built it
But to give a back history, my sister is in the hospital. She’s doing okay, but she’s having twins and they need to keep an eye on them.
No big deal, right?
Actually, for my sister it can be boring. I can tell. Each time I go over she’s happy for a visit. But she tells me “there’s only so much you can do in a hospital room”.
So I decide to get her a ChromeCast (well, my other sister came up with the idea). And I thought I’d just get it, plug it in, and off we go. Except that ChromeCast has no idea of how to connect to a wifi that requires you to accept a terms page before it’s allowed on the Internet. Epic fail….
Unless… you build yourself a repeater that can accept that pesky terms page and deliver the Internet to the ChromeCast!
The Plan
So the plan is really simple. We will setup a Raspberry Pi to connect to the internet, and then deliver that Internet either to a router, or to another wireless interface running Hostapd or some other broadcasting system that will allow others to connect to us. So the list is:
- Raspberry Pi (2 or 3. A or B may work, but I didn’t try).
- Wireless Card (unless you’re using 3 I suppose)
- Router
- Ethernet cable
Starting out
Ok. The first thing you got to do is to take the Raspberry Pi and install Raspbian on it.
Then you need to either connect to it via a serial cable, ssh, touchscreen, whatever so we can run commands on it….
(And if you are connected to it via a serial cable, use these commands to connect to it:)
# chmod 666 /dev/ttyUSB0
$ screen /dev/ttyUSB0 115200
Setting it up
Now we need to setup the interfaces. Now the Ethernet port is where the router will connect to it and we will set the router to a static ip. This is simpler than having yet another program/gear to go wrong.
So here’s the /etc/network/interfaces file:
# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
# The loopback network interface
auto lo
iface lo inet loopback
# the internal (wired) network interface
allow-hotplug eth0
auto eth0
iface eth0 inet static
address 192.168.33.1
network 192.168.33.0
netmask 255.255.255.0
broadcast 192.168.33.255
# wlan0 will be handled by Network-Manager, so take that out
# And the firewall rules and forwarding options
pre-up iptables-restore < /etc/network/iptables
pre-up ip6tables-restore < /etc/network/ip6tables
pre-up echo 1 > /proc/sys/net/ipv4/ip_forward
For the /etc/network/ip6tables
# forward the packets
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [3:486]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o wlan0 -j MASQUERADE
COMMIT
*filter
:INPUT DROP [10000:10000]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [10000:10000]
# for internet forwarding
-A FORWARD -i eth0 -o eth0 -s 192.168.33.1 -j ACCEPT
-A FORWARD -i eth0 -o wlan0 -s 192.168.33.1 -j ACCEPT
-A FORWARD -i wlan0 -o eth0 -d 192.168.33.1 -j ACCEPT
# log and drop
-A FORWARD -m limit --limit 1/min --limit-burst 1 -j LOG --log-prefix "Forward: Drop"
-A FORWARD -j ACCEPT
# Input
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p udp --sport 67 --dport 68 -j ACCEPT
-A INPUT -p udp --sport 68 --dport 67 -j ACCEPT
# Log and drop
-A INPUT -m limit --limit 3/m --limit-burst 1 -j LOG --log-prefix "Input Drop "
-A INPUT -j DROP
COMMIT
And now the /etc/network/ip6tables
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [3:486]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o wlan0 -j MASQUERADE
COMMIT
*filter
:INPUT DROP [10000:10000]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [10000:10000]
# for internet forwarding
-A FORWARD -i eth0 -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o wlan0 -j ACCEPT
-A FORWARD -i wlan0 -o eth0 -j ACCEPT
-A FORWARD -m limit --limit 1/m --limit-burst 1 -j LOG --log-prefix "Forward6 Drop"
-A FORWARD -j ACCEPT
# Input
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p icmpv6 -j ACCEPT
-A INPUT -p udp --sport 67 --dport 68 -j ACCEPT
-A INPUT -p udp --sport 68 --dport 67 -j ACCEPT
# Log and drop
-A INPUT -m limit --limit 1/m --limit-burst 1 -j LOG --log-prefix "Input6 Drop "
-A INPUT -j DROP
COMMIT
Network Manager
The next thing to do is to get Network Manager installed and setup
sudo apt-get install network-manager
sudo dnf install network-manager
pacman -Sy networkmanager
And to get it to connect to the WIFI. First we can show the ssid in the area, and then connect to the right one.
# nmcli c show
# nmcli c add ssid <SSID>
Now we just have to connect to it:
# nmcli d connect wlan0
Little fixes
Now I had to disable the dhcpcd service. It kept on trying to get another ip for each interface, along with the one from the dhclient:
# ip addr
...
inet 192.168.22.1/24 brd 192.168.22.255 scope global eth0
inet 169.58.45.1/24 brd 169.58.45.1.255 scope global eth0
...
But disabling (and then restarting the machine):
# systemctl disable dhcpcd
# shutdown -r
---
# ip
...
inet 192.168.22.1/24 brd 192.168.22.255 scope global eth0
...
Bring the Interwebs Online
Next, we want the repeater to always have access to the internet. By default it won’t due to that pesky terms page. So what we have to do is take our laptop and connect to the internet and pull up a page. And of course it pulls up the “Accept our terms” page. Using Firebug or our web browser developer tools we can see the html form:
<form action="http://<auth-server>" method="POST">
<input type="hidden" name="accept" value="true">
<input type="SUBMIT" value="I Accept All Terms">
</form>
And if we make the tools keep all the input and output, when we accept the terms we will see something like this being submitted as POST data:
accept=true
Well isn’t that nice. Just a simple post and we are verified and can access the internet.
Best of all, we can do the same thing with curl on the Raspberry Pi. It has no web (unless you install links or something). But simply using the following command we can post the data right to the wifi authentication server:
curl -i -H 'Content-Type: text/xml' --data 'accept=true' 'http://<auth-server>'
And with that, the repeater should now be able to access the internet (do not use ping to test, as it may allow that to go though even when it’s blocking access to the internet. Instead use curl:)
pi@raspberrypi:~# curl -I supertechcrew.com
Server: nginx/1.10.0
Date: Fri, 27 May 2016 05:11:55 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://www.supertechcrew.com/
Cache-Control: max-age=3600
Expires: Tues, 17 May 2016 06:11:55 GMT
Vary: Accept-Encoding
X-Cacheable: YES
X-Served-From-Cache: Yes
And that’s the simple way to see if it’s actually up.
All you have to do now is have a program running in the background that can verify that it can access the internet, and if not, then re-authenticate. Something like this:
/usr/local/bin/accept
#!/bin/bash
# just so we don't start too soon
sleep 180
_reauth() {
echo "Reauth"
logger "Reauth with server"
# put your auth command here:
curl -i -H 'Content-Type: text/xml' --data 'accept=true' 'http://<auth-server>'
}
_check() {
up=1
# you may want to customize this. It's just looking for a string in a site.
# return values will always be good, as the auth page is an actual page too.
if [ -z "$(curl -s --max-time 5 --retry 2 --retry-max-time 15 \
www.google.com \
| grep '<title>Google</title>')" ] ; then
up=0
fi
}
while [ 1 ] ; do
_check
if [ $up -eq 0 ] ; then
_reauth
sleep 5
_check
if [ $up -eq 0 ] ; then
_reauth
sleep 5
_check
if [ $up -eq 0 ] ; then
# still down
echo "still down"
logger "Still down"
nmcli d disconnect wlan0
sleep 5
nmcli d connect wlan0
sleep 10
# if still down we reboot
_reauth
sleep 30
_check
if [ $up -eq 0 ] ; then
echo "prob rebooting"
logger "prob needs to Rebooting due to still down"
#shutdown -r now
#exit
fi
fi
fi
fi
sleep 60
done
Just add it to your /etc/rc.local before the ’exit 0’ line:
setsid /usr/local/bin/accept &
Router
Now just plug in your router, and be sure to set the static ip to something in the same subnet as the ethernet adapter was set to (you can just use 192.168.33.2 if you just used the above configs). Then set a password, and set all that up. Connect the ChromeCast and it should now work without a hitch!
Final Touches
Well, now that it is setup, and working, you prob want to be able to keep an eye on it. You can easily do this by setting it up to connect to you OpenVPN network so you can manage it from anywhere.
Just be sure not to mention that to your pregnant sister. They are already paranoid enough, and it might just send them over the edge, even though you have no interest in their latest habits of watching ‘whatever western chick flick’ they keep getting all happy about.
(That must be what they think when I geek out one of my favorite things….)