Create Your Own WiFi Repeater

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:

  • Raspberrry 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 Rasbian 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

# apt-get install network-manager

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….)