My Ultimate Network Monitor/Enumeration Tool – Putting It All Together

Finally, all the parts come together. Look at my previous posts for all the pieces to building the LilDevil network monitor and enumeration tool.

The LilDevil

So this tool I created sits on a Raspberry Pi. Its purpose is to monitor and enumerate all devices currently connected to a network. In this case, it sits on my Guest network. Tomato Shibby is running on my router and I used its web interface to setup the network, along with limiting access. For all guests jointing this network, they are warned by the router’s splash page that tools such as this will be running. Its a free network and they really can’t expect anything different going on. In this case, its not malicious, but it is good practice to be wary of guest networks.

To be less suspicious, the hostname of the Raspberry Pi is RainbowDash ūüėČ This amuses me so much, the perfect disguise! If I saw a device named LilDevil running on a guest network I would be totally alarmed. I also themed the Pi accordingly, see the below screenshot. The coloring isn’t perfect, I blame VNC.


The Pi runs a Django Restful server that stores mmap scan information about detected machines on the network. The Python 2.7 scripts for this are here. I had to make a few versions in order for things to work on Django 1.6.

In, change

encoded = json.loads(request.raw_post_data)


encoded = json.loads(request.body)

Also, I had to make some changes in, in order to get the ping sweep to work appropriate.

Change MIN and MAX to an integer instead of a string.




Here is a copy of the new main function.

def main():
    global results
    while 1:
        new = ""
        for x in range(MIN,MAX):
            new = new + commands.getoutput("ping -c 1 -t 1 "+PREFIX+"."+str(x) + " | grep 'from'") #Ping sweep the network to find connected devices
        tmp = re.findall(PREFIX+".(d+)", str(new)) #Pull out IP addresses from the ping results
        if tmp != results:
            for ip in tmp:
                if ip not in results:
                    gotcha = commands.getoutput('nmap -v -A -Pn '+PREFIX+'.'+ip)
            for r in results:
                if r not in tmp:
            results = tmp

The information is up to date on all devices currently connected. It may be nice in the future to include a log of all scans but for now, I’m really only interested in connected machines.

Data is then displayed in a visible GUI. The below screenshot shows the tool windows along with the GUI. Currently, no devices were connected to the network.

Screen Shot 2014-01-17 at 9.27.49 PM


Ahhh it detected a device… in this case, itself.

Screen Shot 2014-01-19 at 7.58.55 PM

There you have it! A portable network enumeration tool. There are so many versions of this everywhere, but this is just something I coded up for fun. I plan to add to the Pi later for kicks.

Build Your Own Wireless Access Point

Why buy an expensive router when you can build a cheap one from old hardware?


This is what I used:

  • Ubuntu Desktop 12.04
  • hostapd v0.7.3
  • dhcp3-server
  • HP Compaq DC 7800 Small Form Factor PC
  • Penguin Wireless N PCIe Card v3 SKU NPCIEV3 ($50-$70)
  • Ethernet cable
  • Monitor, VGA cable, mouse and keyboard



  1. The Wireless network card must first be installed. Open up the computer and locate the PCI slot. Insert the network card into the PCI slot.
  2. PC Slot

  3. Ensure the two cables are reachable to the outside of the case. The antennas should be connected to these points. In the picture, the wireless network card‚Äôs plate did not fit the chassis and was removed because I didn’t feel like punching holes through the original plate.
  4. Antennas

Software Install

These directions specifically apply to a machine that is running the Ubuntu 12.04 operating system. I feel this goes without mentioning but have a monitor, keyboard, etc connected to the PC for the next install steps. Install SSH in order to shell into the device later without all that necessary crap. In order to create the wireless access point two packages need to be installed.

  1. sudo apt-get install hostapd
  2. sudo apt-get install dhcp3-server

Hostapd provides the hosting services of an access point. It is a daemon for wireless access and authentication servers. Dhcp3-server provides a network service that automatically assigns IP addresses to clients.


The hostapd configuration file needs to be created and edited to contain access point information. The below settings utilize WPA2-PSK authentication.

  1. sudo vim /etc/hostapd/hostapd.conf
  2. Add
  3. interface=wlan0 #wireless network interface
    driver=nl80211 #802.11 standard
    ssid=TheShire #The hotspot name, I'm a sucker for Lord of the Rings :)
    wpa_passphrase=secretPassword #access point password
    wpa_pairwise=TKIP CCMP
  4. Configure the interface for the DHCP server.
  5. sudo vim /etc/default/isc-dhcp-server
  6. Set
  7. INTERFACES=‚ÄĚwlan0‚Ä≥
  8. The next configuration is in the DHCP conf file. Set the range of IP addresses allowed to be allocated to connecting machines.
  9. sudo vim /etc/dhcp/dhcpd.conf
  10. Comment out all lines except:
  11. ddns-update-style none;
  12. Declare the IP range of addresses for DHCP.
  13. subnet netmask {
            option domain-name-servers,;
            option routers;
  14. Enable the hostapd program to run on startup.
  15. sudo vim /etc/default/hostapd
  16. Set:
  17. RUN_DAEMON="yes"

IP Settings

  1. Configure the IP settings for the wireless network.
  2. sudo vim /etc/network/interfaces
  3. Add
  4. auto lo
    iface lo inet loopback
    auto wlan0 #Wireless Network Interface
    iface wlan0 inet static
    address #Local Router IP

Firewall Settings

Allow IP masquerading in the Iptables. This is a networking function that allows local machines to access the same connection the host router is utilizing.

  1. echo “1” > /proc/sys/net/ipv4/ip_forward
  2. iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

DHCP Monitoring

  1. All DHCP requests can be found in /var/log/syslog. Grep can be used to pull certain requests for monitoring.
  2. cat /var/log/syslog | grep DHCPOFFER


  3. Further DHCP settings can be supplied in the configuration file, such as:
  4. sudo vim /etc/dhcp/dhcpd.conf
  5. Edit
  6. subnet netmask {
            option domain-name-servers,;
            max-lease-time 120; #Set the max release time
            default-lease-time 120;#Set the default lease time
            option routers;

To flush the DHCP leases, the following can be performed:

  1. cd /var/lib/dhcp/
  2. sudo rm dhcpd.leases~
  3. sudo echo ‚Äú‚ÄĚ > dhcpd.leases

Changing Signal Strength

It may be ideal to limit the signal strength to a specific room or region in order to prevent overlapping signals. For cards that support multiple transmit powers, this can be done through iwconfig.

  1. iwconfig wlan0 txpower <LEVEL IN DBM>

Wireless AP
There you have it!

Stop the MitM Attacks! Use Encryption!

So I’ve been having fun with Amazon’s Developer Services for user authentication. In order to get the darn thing working, Amazon requires your server to use HTTPS. This isn’t a bad thing but in order to have HTTPS, you need to get a valid certificate. Now it’s easy to create a certificate (see below) however, not as easy to get a trusted certificate. Trusted certificates are those that are authenticated by a Certificate Authority or CA. I wouldn’t really trust a self-authenticated certificate. Reminds me of online dating where everyone lies, you kind of want a third party, reliable source to tell you the truth.


Here is the process to create a certificate request or CSR:

The below uses Openssl (this is native on a lot of Linux distributions, IIS on Windows handles these things differently).

Generate a RSA encrypted private key

openssl genrsa ‚Äďout gen.key 2048

Create a CSR for the key

openssl req ‚Äďnew ‚Äďkey gen.key ‚Äďout key.csr

Answer all the questions, leave the password blank, it’s not needed.

To get it approved:

Self (Untrusted…lame)

Remove RSA passphrase, if you don’t, the server you are running will require it upon each request

openssl rsa -in gen.key -out server.key

Generate a Year Long Certificate

openssl x509 -req -days 365 -in key.csr -signkey server.key -out key.crt


Take it to a company such as Verisign, Thawte and RapidSSL.

Wrap it Up

You now have a certificate that can be included in your server configuration. Check your documentation for the correct implementation. There are too many server variations out there for me to describe the process.

So why do we care about HTTPS?

Well it‚Äôs secure! HTTPS stands for Hypertext Transfer Protocol Secure and utilizes SSL/TLS protocol to lockdown communications. It is used to prevent man-in-the-middle attacks with the use of encryption (preventing some of the attacks in the ettercap post). If your data is encrypted, little hacker man can‚Äôt read it. This is why whenever you are entering in confidential information, look for ‚Äúhttps://‚ÄĚ in the URL, else your private data is being broadcasted in clear text (there was an ettercap attack mentioned in my last post that removed the security from a Facebook form, changing the login URL from HTTPS to HTTP‚Ķ be warned).

Explanation of the SSL/TLS process:

  1. Client browses to a secure site (HTTPS)
  2. Hosting server sends its certificate and public key to requesting client
  3. The client‚Äôs browser checks the server‚Äôs certificate (Looks to see if it comes from a trusted CA, relates to the correct sire, and is currently valid)¬†‚Äď This is why you should pay attention to browser warnings, it may be trying to prevent you from going to an untrusted site.
  4. The browser uses the public key to encrypt a random symmetric encryption key and sends it to the server
  5. The server decrypts the key using its private key, the following communication between hosts is encrypted with the symmetric key
  6. Once communications have concluded, the symmetric key is discarded

The Public Key is available to anyone and anything that wants it. Anyone can retrieve it from the server. That’s all fine and dandy. The Private Key, on the other hand, is kept a secret and only the owner knows it. These keys are mathematically related, whatever is encrypted with a Public Key can only be decrypted by its corresponding Private Key. So even though a hacker can get the Public Key, he/she cannot decrypted the SSL/TLS communications because they do not have the Private Key.

So here is an example of how it all works.¬†Jack¬†wants to¬†send a secret message to¬†Jill,¬†he doesn‚Äôt want anyone else to read the message. So Jack,encrypts¬†his message¬†with¬†Jill’s Public Key.¬†Jill is cool with giving out her Public Key to anyone who wants it because it is after all public.¬†Jill is the only person who can decrypt the Public Key because she is the only one with its corresponding Private Key. So now Jack‚Äôs message can only be read by Jill.¬†Even if¬†hacker Todd gets a hold of the¬†encrypted data, he can‚Äôt read it because he doesn‚Äôt have the decryption or Private key.

Crazy security…

IMPROVEMENTS: Detecting New Network Devices with Python and Tkinter

So I wasn’t too happy with the¬†kludginess of the network monitoring tool that I posted about earlier this week. It lagged and really wasn’t an ideal tool. I decided to redesign the entire model.

New Model

The new tool still utilizes Python 2.7 and consists of three parts:

  • Ping/Enumeration Script
  • RESTful Django Script
  • Tkinter Reporting GUI Script

Here is how they connect. The Ping/Enumeration Script, pings all devices given within a network range. Whenever it finds a new device, it runs a NMAP scan on the device then formulates a request to the server to notify it of the device scan results. The script will also notify the server when a device disconnects from the network (this was an issue with the old version).

The Django server manages a sqlite database containing scan results on all devices currently connected to the network. It will remove or add a device record based on the ping script’s RESTful HTTP request. The server can also return a list of all devices detected. This list is used by the GUI script.

The GUI script maintains a Tkinter dialog window that will circulate through all network connected device scan results. It first sends a GET request to the Django server asking for a JSON list of all connected devices. The script will then display each record found in the JSON. Each device record will appear in the GUI window for 20 seconds. After it has made the rounds through each item, it will make another call to the server for a fresh JSON to iterate through.

The Ping/Enumeration Script is basically the same as what I discussed earlier. The difference is, after data is collected, it is sent to the Django server in a POST request.

import commands, re, json, urllib2, binascii
PREFIX = "192.168.1" #Network prefix
MIN = "0" #Starting network address, eg
MAX = "12" #Closing network address, e.g.
results = []

def escapeMe(message): #Escape characters (using ASCII value) not allowed in JSON
    new = ""
    for num in range(len(message)):
        char_code = ord(message[num])
        if char_code < 32 or char_code == 39 or             char_code == 34 or char_code == 92:
            new = new + "%" + binascii.hexlify(message[num])
            new = new + message[num]
    return new

def sendDevice(gotcha): #Send the device report to the server as a POST
        url = "" #Server address
        gotcha = escapeMe(gotcha)
        values = json.dumps({'device' : str(gotcha)})
        req = urllib2.Request(url)
        req.add_header('Content-Type', 'application/json')
        rsp = urllib2.urlopen(req, values)
        code = rsp.getcode()
    except Exception, e:
        print e

def removeDevice(ip): #Send request to remove device
        ip = ip.replace('.','-')
        url = ""+ip+"/"
        rsp = urllib2.urlopen(url)
        code = rsp.getcode()
    except Exception, e:
        print e

def main():
    global results
    while 1:
        new = commands.getoutput('for i in {'+MIN+'..'+MAX+'}; do ping -c 1 -t 1 '+PREFIX+'.$i | grep "from"; done') #Ping sweep the network to find connected devices
        tmp = re.findall(PREFIX+"\.(\d+)", str(new)) #Pull out IP addresses from the ping results
        if tmp != results:
            for ip in tmp:
                if ip not in results:
                    gotcha = commands.getoutput('nmap -v -A -Pn '+PREFIX+'.'+ip) #nmap new devices found on the network
                    sendDevice(gotcha) #send device record to server
            for r in results:
                if r not in tmp:
                    removeDevice(PREFIX+'.'+r) #remove device if it wasn't found in the latest ping
            results = tmp

if __name__ == "__main__":

Django is an awesome Python Web Application Framework that I absolutely adore (not the movie ūüôā ). It is known as the web framework for perfectionists with deadlines. Most of my web projects utilize Django.


It comes with its own lightweight server to host its applications, so its perfect for any development environment. For the sake of this project, I’m using its server, all script/server functionality is limited to the host machine running the tool. Everything is internal. Django also handles the RESTful routing and database modeling. It uses the model view controller (MVC) structure. Here is a great tutorial on how to create your own Django app, definitely worth looking into!

The following is the break down of code I wrote for the Django server (running version 1.3).
from django.db import models

class Devices(models.Model):
    device = models.TextField()

####################ADD to
url(r'^new/$', '', name='new'),
url(r'^listDevices/$', 'lilDevil.views.listDevices', name='listDevices'),
url(r'^remove/(?P*ip*.+)/$', 'lilDevil.views.remove', name='remove'), #REPLACE * with greater/less sign containing brackets
from django.http import HttpResponse
from lilDevil.models import Devices
import json

def remove(request, ip):
        ip = ip.replace('-','.')
        devicelist = Devices.objects.all()
        for d in devicelist:
            if ip in d.device:
        return HttpResponse(status = 200)
    except Exception, e:
        return HttpResponse(e)

def new(request):
        encoded = json.loads(request.raw_post_data)
        new = Devices(device=encoded["device"])
        return HttpResponse(status = 200)
    except Exception, e:
        return HttpResponse(e)

def listDevices(request):
        json_string = '{"devices": ['
        devicelist = Devices.objects.all()
        first = True
        for d in devicelist:
            if first:
                first = False
                json_string = json_string + ', '
            json_string = json_string + '{"device": "'+str(d.device)+'"}'

        json_string = json_string + ']}'
        return HttpResponse(json_string)
    except Exception, e:
        print HttpResponse(e)

Finally, the GUI script. Very similar to the one in the old post. Again, I just added the ability to request device data from the server.

from Tkinter import *
import time, urllib2, urllib, json
class flipGUI(Tk):
    def __init__(self,*args, **kwargs): #Setup the GUI and make it pretty
        Tk.__init__(self, *args, **kwargs)
        self.label1 = Label(self, width= 65, justify=CENTER, padx=5, pady=5, text="Guests") #Text label
        self.label2 = Label(self, text="") #Photo label
        self.label2.grid(row=0, column=1, sticky=W+E+N+S, padx=5, pady=5)
        self.label1.grid(row=0, column=0)

    def flipping(self): #Flip through NMAP scans of detected devices
        t = self.label1.cget("text")
        t = self.label2.cget("image")
        data = getData()
        found = json.loads(data)
        photo = PhotoImage(file="picture.gif")
        if found['devices']:
            for f in found['devices']: #Loop through all but the last item
                fixed = f['device'].replace('%0a', '\n') #return to ASCII value from earlier escaped hex
            self.label1.config(text="No connected devices")
        self.after(1, self.flipping())

def getData(): #Get a list of devices from server
    url = "" #server address
    response = urllib2.urlopen(url)
    code = response.getcode()
    if int(code) == 200:

if __name__ == "__main__":
        while 1:
            app = flipGUI()
    except Exception, e:
        print e

Final Note: Make sure to delete/clear out database or old results will carry over! I did this in an init.d script that calls the service.

Put it all together and you have a much more stable tool. I renamed it from the Hindenburg to the Lil Devil.

The Lil Devil
The Lil Devil

Restricting Bandwidth on Tomato

This is a shorter post but it’s all part of my latest and greatest project idea which will come together soon!

I dislike guests who over stay their welcome. If they want to use my internet, I don’t mind as long as they don’t go crazy. Earlier, I created a separate guest network¬†and now I want to limit its bandwidth. By limiting this, I limit how much streaming, download, uploading, etc. my guests can do per second. This can all be accomplished in the Bandwidth Limiter section in the tomato web GUI (default

Under the Bandwidth Limiter for LAN, enable the the limiter. This part kind of sucks. My network is setup to include a dedicated bridge for my personal network (br0) and another for my guest network (br1). Your network may be different. In order to limit the guest bridge (br1) I had to set a limit on my personal bridge (br0). I chose to set the limit ridiculously high (300 Mbps) on my personal so as never interfering with my experience. The picture shows my settings below.

Screen Shot 2014-01-05 at 8.34.54 AM

For my guests, I cut down their use to 5 Mbs download.

Screen Shot 2014-01-05 at 8.34.57 AM

Save it and you did it! This is pretty easy stuff. Just to verify everything, I connected to my guest network and ran a speed test (

Screen Shot 2014-01-05 at 8.36.40 AM

Nice! Stuff like this makes me feel like…

Detecting New Network Devices with Python and Tkinter

UPDATE: I made a better version of this tool with server implementation here.

Today I felt like building a python 2.7 script that would enumerate a network along with alert me to the presence of a new device.

I limited my project to functions in the standard library.

So something lightweight and okay fast is a ping sweep. From an early post I included the Linux command for a sweep. I used this command along with the python commands to execute the ping sweep along with storing the results in a variable.

new = commands.getoutput('for i in {'+MIN+'..'+MAX+'}; do ping -c 1 -t 1 '+PREFIX+'.$i | grep "from"; done')

Following, I used some regular expressions to pull out the IP addresses detected in a given prefix range.

tmp = re.findall(PREFIX+"\.(\d+)", str(new)) #Pull out IP addresses from the ping results

Put that in a loop with some comparison data and you have a script that prints an alert whenever a new device is detected.

import commands, re
PREFIX = "192.168.1" #Network prefix
MIN = "0" #Starting network address, eg
MAX = "12" #Closing network address, e.g.
results = []
while 1:
new = commands.getoutput('for i in {'+MIN+'..'+MAX+'}; do ping -c 1 -t 1 '+PREFIX+'.$i | grep "from"; done') #Ping sweep the network to find connected devices
tmp = re.findall(PREFIX+"\.(\d+)", str(new)) #Pull out IP addresses from the ping results
if tmp != results:
for t in tmp:
if t not in results:
print "New device at" + PREFIX + "." + str(t)
results = tmp

There are a few short comings in the code but that’s the basic idea.

Now take this further, I hooked it up to a GUI with enumeration information! The new beastly application constantly flips through NMAP scan results of devices found connected to the network and displays the results in a GUI. I even placed a picture in the GUI. I call this app, the Hindenburg, its kind of hacked together.

The Hindenburg!
The Hindenburg!
from Tkinter import *
import time, commands, re
PREFIX = "192.168.1" #Network prefix
MIN = "0" #Starting network address, eg
MAX = "12" #Closing network address, eg
class flipGUI(Tk):
def __init__(self,*args, **kwargs): #Setup the GUI and make it pretty
Tk.__init__(self, *args, **kwargs)
self.label1 = Label(self, width= 65, justify=CENTER, padx=5, pady=5, text="Guests") #Text label
self.label2 = Label(self, text="Guests") #Photo label
self.label2.grid(row=0, column=1, sticky=W+E+N+S, padx=5, pady=5)
self.label1.grid(row=0, column=0)
    def flipping(self): #Flip through NMAP scans of detected devices
t = self.label1.cget(“text”)
t = self.label2.cget(“image”)
found = scanNetwork()
photo = PhotoImage(file=”picture.gif”)
for f in found[:-1]: #Loop through all but the last item
self.label1.config(text=found[-1]) #the last item doesn’t require the sleep, it takes enough time to run the scans
self.after(1, flipping())

def scanNetwork():
found = []
new = commands.getoutput(‘for i in {‘+MIN+’..’+MAX+’}; do ping -c 1 -t 1 ‘+PREFIX+’.$i | grep “from”; done’) #Ping sweep the network to find connected devices
tmp = re.findall(PREFIX+”\.(\d+)”, str(new)) #Pull out IP addresses from the ping results
for ip in tmp: #Loop through each found IP
found.append(commands.getoutput(‘nmap -v -A -Pn ‘+PREFIX+’.’+ip))
return found

app = flipGUI()

It’s ideal for an environment where it can just sit on the screen without much of any type of activity going on. If you are enumerating the entire network, there will be a lag… it happens.

Tomato by Shibby Splash Page

What is a splash page? Well it’s basically a welcome page. Router’s can have splash pages to greet users immediately after connecting to the network, notify them of conditions of use and/or require user authentication.

I want a splash page for my guest network to basically inform guests that my guest network is a risky environment… it is free at least. Say for instance, if fingerprinting or enumeration tools just happen to be used in my guest network, they wave their rights to taking action against it by agreeing to access the network in the first place.

Screen Shot 2014-01-04 at 7.39.34 PM
My splash page

In Tomato Shibby, this can be done in the web UI (default under the Captive Portal section. Just enable the feature and save. Now you are using the default splash page.

Screen Shot 2014-01-04 at 7.40.08 PM

You can change things up by uploading your own html splash page. I couldn’t get this to work, so instead I SSH directly to the router and wrote my own in the console.


ssh root@

The root account should have the same password as the admin web UI account.

Screen Shot 2014-01-04 at 7.40.48 PM

Once in, I kind of fudged around. I recommend keeping a copy of the original splash page… just in case.¬†I customized the current splash.html page to fit my needs with vi.

vi /tmp/splashd/splash.html

My html page code is displayed below with the red section being the area I changed from the original:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
<html xmlns="">
    <meta http-equiv="Content-Type" content="text/html; 
    <title>Guests of Paul</title>
        body, html, #wrapper {width: 100%; height: 100%;}
        body, html, form, h1 { margin: 0; padding: 0; }
        body {
            background: #121b1d url(tomatousb_bg.png);
            font: 14px Tahoma, Arial, sans-serif;
            width: 100%;
            height: 100%;
        a {
            color: #e02600;
        a:hover {
            padding: 3px;
            color: #fff;
            background: #e02600;
        img { border: 0; padding-top: 8px; float: right; }
        #splash {
            width: 520px;
            margin: 0 auto;
            padding-top: 10px;
            position: relative;
        #splash_header {
            position: relative;
            background-color: #2f3d40;
            padding: 8px;
        #splash_header h1 {
            /* font: 28px 'Century Gothic', Tahoma, Arial, Sans-serif; */
            font-size: 28px;
            text-align: center;
            color: #919EA1;
        #splash_content {
            color: black;
            background-color: white;
            padding: 15px;
        textarea {
            white-space: pre-wrap;
            word-wrap: break-word;
            font: 12px monospace;
            width: 96%;
            height: 230px;
            min-width: 96%;
            min-height: 230px;
            padding: 10px;
        form { -webkit-box-align: center; text-align: center; }
        button {
            font: bold 1em Arial, Sans-serif;
            color: #919EA1;
            width: 200px;
            padding: 4px;
            margin-top: 15px;
            background: #283033;
            border: 1px solid #CCC;
        button:hover {
            color: white;
            background: #E02600;
            background: #ededed;
        iframe {
            border: 0;
            border-spacing: 0;
        #footer {
            color: #919EA1;
            margin: 0;
            text-align: center;
            padding-top: 8px;
    <script type="text/javascript">
    function toggle(element) { document.getElementById(element).
    style.display = (document.getElementById(element).style.display 
     == "none") ? "" : "none"; }
    <table id="wrapper">
            <td valign="middle">
                <div id="splash">
                    <div id="splash_header">
                        <h1>Guests of Paul</h1>
                    <div id="splash_content">
                        <!-- "textarea" is where you put your Text -->
                        <center><b>Wifi Network &amp; Internet conditions:</b></center>
                        <textarea readonly="readonly">
                        You are solely responsible for the risks of joining this 
                        network and accept this term by clicking the "OK, I AGREE" 
                        We are not responsible for faulty operation of your computer or 
                        equipment. You will be at risk to other devices on the network. 
                        By joining, you accept all risks and verify you are okay with 
                        the chance of possible device enumeration. You may be asked to
                        stop using your equipment.
                        This banner will appear again periodically.
                        To renew your access time, you must agree once again every 3600 
                        Thank You, and Enjoy!</textarea>
                        <form method="POST" action=$action>
                            <input type="hidden" name="mode_login">
                            <input type="hidden" name="redirect" value=$redirect>
                            <input type="hidden" name="accept_terms" value="yes">
                            <button type="submit" value="Submit">Ok, I Agree!</button>

So now I have this new splash page, make sure you update your code with the correct router IP address. Now I need to set it as the router’s splash page. In the Captive Portal section on the Tomato web UI, I just confirmed that the welcome path was set to my splash page.

Save it all, and that’s it. Enjoy!

Tomato Shibby Guest Wireless

I want a guest network to mess around with, I mean what are guests for after all?

What other reasons are there for having a guest network?

Well, say you don’t want to give out the password to your actual home network. You may want to limit activity of guests. You do not want guests to be able to communicate with personal devices on your network. You might have some malicious/untrustworthy ¬†friends and you want to keep yourself safe. So many reasons.

Worry not peoples, there is an easy way to set this up on Tomato Shibby and most other new router firmwares! The following steps use the tomato firmware web UI. By default, the UI can be accessed on by a computer connected wirelessly to the router.

First thing is first, a new bridge has to be greater for this guest network. This bridge can be created in the Basic -> Network section under LAN. Simple click ‘Add’ and enter in your desired settings.

Screen Shot 2014-01-04 at 6.01.03 PM

The bridge I created (br1), is pictured above. It is set to use IP addresses with the router hosting on I’m only allowing up to 6 guests. I don’t want my experience to get bogged down by guests so I limit the amount of addresses available to them hence limiting the number of guests able to connect. Also, I set the lease time for guests to 60 minutes, they don’t need a long lease time. Save your progress.

Sweet, so I now have this bridge. Now I must assign it to a VLAN.

“In¬†computer networking, a single¬†layer-2 network¬†may be¬†partitioned¬†to create multiple distinct¬†broadcast domains, which are mutually isolated so that packets can only pass between them via one or more¬†routers; such a domain is referred to as a¬†virtual local area network,¬†virtual LAN¬†or¬†VLAN” (Wikipedia).

I don’t want guests accessing my stuff, so I will put them on a separate VLAN. Create a VLAN (for me it was 3) and assign the new bridge (br1) to it in Advanced -> VLAN under VLAN.

Screen Shot 2014-01-05 at 9.25.48 AM

In my setup above, I’m not expecting guests to connect directly to a port on the router so I did not configure any of them. I expect guests to just connect wirelessly. Save your progress after setting this up.

Now time to set up the wireless SSID for the guests. Go to Advanced -> Virtual Wireless. Add the wl0.1 interface (or whatever one you want to use) and set it to use the new bridge (br1). Give it any SSID you want, I chose to call mine Guest, as seen below. Save it.

Screen Shot 2014-01-04 at 7.46.16 PM

You can configure settings for the wireless interface by selecting the coordinating tab (wl0.1) from the top of the page. For instance, you might want to give it security. For now, I gave mine security but I don’t think I’ll keep it. Save it.

Screen Shot 2014-01-04 at 7.46.21 PM

Finally, double check all is set correctly in Advanced -> VLAN.

Screen Shot 2014-01-04 at 7.46.32 PM

Basically, look to make sure the right bridge is setup to the right wireless interface. Save it.

Next to make sure my guest VLAN users cannot access my private network devices I added a few block forwarding IP table rules. To do this,  add the following commands in Administration->Scripts under Firewall:

iptables -P FORWARD DROP
iptables -A FORWARD -i eth0 -o br0 -j ACCEPT
iptables -A FORWARD -i br0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o br1 -j ACCEPT
iptables -A FORWARD -i br1 -o eth0 -j ACCEPT

Screen Shot 2014-03-08 at 10.07.36 AM

These rules first drop all forwarding communications. Following, the next rules set the firewall to allow communications between both bridges and the external world (eth0) only. This way the networks cannot talk to each other but still have internet connectivity. Save and you’re done with the basics!

I went ahead and added a few extra things like a splash page for guests and I also limited their bandwidth activity. I’ll explain how to do this in a later post, this one is too long.

Tomato Shibby on ASUS RT-N66W

I decided to change up the firmware on my router. I want more control than the standard firmware gives. It’s for fun.

I own an ASUS RT-N66W.

With my last router, I had DD-WRT firmware installed (which I liked), but I want something new. This time I’m trying out Tomato by Shibby.

“Tomato is a system based on Linux, dedicated for routers with Broadcom chipset and distributed on the GPL license. Its development was started by Jonathan Zarate. This advanced system consists of especially user-friendly interface, thanks to which even inexperienced users can work with it easily” (

On the Tomato website, there isn’t a firmware download specifically for the RT-N66W version, however there is one for RT-N66U. The two routers are almost identical and can operate the same firmware. The firmware I used was:

K26RT-N -> build5x-115-EN (latest english version at the time) -> Asus RT-N66u 64k -> tomato-K26USB-1.28.RT-N5x-MIPSR2-115-AIO-64K.trx



I suggest going and getting a backup of the router’s default firmware from ASUS… just in case.

Now, ASUS has software that will help you put new firmware on your router but I haven’t had any luck with it. I found it very unreliable. The first time I tried to install Tomato on my router I used the recommended software and the upload failed repetitively, leaving my router in this limbo state… not fun. Instead, I recommend using the web interface. Much easier!!

Here are the steps to upload the new firmware:

  • Put the router into recovery mode.
    • unplug the power from the router
    • press and hold in the reset button (circled in picture below)

2014-01-04 17.04.55

    • plug the power back into the router
    • push the power button to turn the router on (make sure you are still pressing the reset button)
    • wait until the power light slowly (and I mean very slowly) flashes on and off
    • release the reset button
  • Connect an ethernet cable from any of the ports (excluding the port connected to the modem) to your computer.
  • Statically set your ethernet network adapter IP on your computer to and net mask to If you’re not sure how, Windows users can follow these instructions.


  • With that changed, you can now force your computer to open the recovery webpage. In a browser go to


  • Choose to upload the firmware you downloaded earlier.


  • The following screen tells you the upload is complete and to chill until the unit reboots.


  • I waited about 15 minutes and this screen never changed, I did not even notice my router reboot. I just got tired and clicked “continue.”
  • Next thing you know, you have Tomato Shibby installed on your RT-N66W. You should be able to view the router’s web UI on The default credentials are admin:admin.
  • It is suggested to clear the NVRAM. This clears any old firmware settings and is a good practice. This can be done in the router’s web UI. Go to Administration -> Configuration, then choose “Erase all data in NVRAM…” under Restore Default Configuration.


Tah Dah! You now have Tomato Shibby installed, have fun.