Last year the WiFi router at our department in the University finally died and I took the opportunity of installing the new router to attempt to address several annoyances we had had with the old setup for years:

  • No DHCP: This wasn’t the router’s fault but, for a long time and for reasons beyond our control, we couldn’t enable DHCP in the router. Our network had been (poorly) setup so that broadcasts reached too far. So if we enabled DHCP in our router, it would answer discovery requests from labs from across the building. This was fixed at some point, but our setup stuck longer.
  • Hidden SSID: The router wasn’t sanctioned by the proper authorities, so we set it not to broadcast its SSID. This, along with having no DHCP, made it a hassle for new people to connect to the network, and some devices had trouble sometimes connecting or reconnecting to the network. Also, Windows machines showed there was some hidden network, and when there were more than one, guessing was required, which by Murphy’s Laws, never worked at the first attempt.
  • PSK: The router (some crappy DLink we chipped in to buy) had no enterprise features, so it forced us to choose between a Private Shared Key or no key at all. We didn’t like private shared keys for our setup, because our department was constantly visited by students and teachers from everywhere and the key would quickly spread around the university. We chose not to have any key
  • MAC based access-control: At least the router supported making a white list of MAC addresses allowed to connect. That can be broken, but it was enough protection for our purposes.
  • Just 20 MACs: Sadly, the list of MACs had just 20 entries. When we first set that up, a good 10 years ago, we had just a handful of wireless devices. By July last year, we were changing the list so frequently that if you didn’t stop by for two days you would certainly be dropped from it.

Without DHCP we used the cavemen’s IP-address management solution:

16 by 16 table of the /24 network of REDES

Neanderthal's DHCP

Managing the MAC addresses

Managing the list of MACs was a huge pain. The router’s web interface didn’t allow tagging the MACs, or disabling an entry without removing it. It had 20 input elements and that was it. We built a command line tool that read a text file and allowed comments, like this:

 1 70:f1:a1:a9:9b:7d   # yanelys (lolita)
 2 00:23:12:07:05:bd   # diana
 3 00:19:d1:22:56:d7   # ??
   ...
18 00:22:fb:20:04:90
19 00:1b:77:75:87:81
20 00:26:b0:b1:9c:06
21 # this is the border of the 20 ones
22 00:23:12:07:05:be   # diana
23 00:1b:2f:ce:08:35   # lara
24 00:12:f0:37:ed:48   # isobel
25 # this next line is for vim
26 # vim:number:filetype=conf
</span>

The tool then interacted with our router’s web UI to put just the first 20 entries. With Vim’s modeline at the bottom, I guaranteed line numbers were displayed and comments were highlighted. It was simpler to edit this file and run our tool than struggling with the extremely limited web UI of the router. And it also let us keep a history of the changes in a git repo.

This was a step forward, but still a hassle.

dpto2

When the crappy DLink router died, about a year ago, someone donated a Cisco router that wasn’t much better, but that happened to support Radius authentication. That meant we could move from MAC authentication to giving each person its own pair of username & password. So I set out to set it up and, in a few afternoons, I built a system & web interface to manage our WiFi and local network.

The first name of the system was dpto2. That was our hidden WiFi SSID, and the new system was super ad-hoc. I established these initial design goals:

  • DHCP: no explanation needed :)
  • Visible SSID: the politics around WiFi at the University had softened a lot in the last several years so we didn’t need to hide anymore and this was easier.
  • No MAC access-control: I wanted a way to give access to the proper users that was more convenient and flexible than managing a list of MAC addresses.
  • Guests: we needed a way of giving temporary access to our many guests without having some password spread all over the University.
  • Web UI: to get rid of the whiteboard IPs table, I wanted to have an equivalent web interface. I also wanted a web way of managing the list of users.
  • No superusers: managing the old list of MACs required admin access to the router. So only a couple of guys could do it. If they weren’t around people were stuck. I wanted every registered user to be able to manage the system.

The new system is a Python web app built with Flask. The first page looks like this:

first page of smallnet, showing today's guest password

As the text shows, now there are users in the system, and a special guest user whose password is shown in the first page and is changed everyday to a random string. The string is all lowercase letters, so that users in mobile devices can enter it more easily; and we avoid symbols that can be confusing such as i, j and o.

User authentication is managed by Freeradius, using a plain text file with NTLM passwords that we generate ourselves, since it’s just MD4 over UTF-16LE. This password scheme uses no salting, so if someone gets hold of the passwords file, they’ll have an easier time deciphering them. But the balance of simplicity and security is ok for the size of our system.

To see that page, you must already have an IP in our network. That way, outside users can’t just visit the system and get the guest password. They must go to someone that’s already in and ask them. This isn’t bullet-proof, but, again, this is secure enough for our size.

When you log in, you see this:

admin page of smallnet; create & delete users; links to other pages

This page reflects the next design choice. Every user that has an account in the system is a full-fledged administrator. They can create and delete other users. In a large, internet facing system, this would be chaos. Here, we keep people in check with transparency. As the next image shows, everyone can see who created who:

tree of users showing who created who

Transparency keeps "reproduction" in check

The first user, myself, was created by Ilúvatar (also myself). All other users must be created by some existing user. Except hydn, who didn’t know how the system worked and went on and read the source code to figure it out and created himself directly in the users database file.

The new version of our whiteboard IPs table looks like this:

web version of the 16 by 16 table of the /24 network of smallnet

This table shows all addresses in our /24 range. Any user can label a cell and give it color. Some cells are unusable, like .0 and .255, and some are locked. Locked IPs are there to keep the system running. One of them, .99 is the server where the system is running; other is the network’s gateway and other is the IP of the WiFi router itself. If you click one cell you’ll see something like this:

Config page for a specific IP cell. It can be labeled, given a color, added to the DHCP pool for any device or reserved for a specific device; optionally, that device can be given an alternative gateway via DHCP

The in the images above marks the addresses that are currently leased via DHCP.

The server behind the system is Dnsmasq. In dnsmasq.conf I wrote:

dhcp-range=10.6.122.1,10.6.122.254,24h
dhcp-hostsfile=/etc/dnsmasq.d/dpto2/dhcp-hosts
dhcp-optsfile=/etc/dnsmasq.d/dpto2/dhcp-opts

The first setting looks strange. I’m giving almost all addresses to Dnsmasq’s DHCP pool. This works because dpto2/dhcp-hosts looks like this:

ff:ff:ff:ff:ff:fe,10.6.122.1
...
ff:ff:ff:ff:ff:fe,10.6.122.13
# {"locked": true, "reserved-by": "WiFi dpto2"}
ff:ff:ff:ff:ff:fe,10.6.122.14
...
ff:ff:ff:ff:ff:fe,10.6.122.103
# {"color": "green", "reserved-by": "Andy"}
ff:ff:ff:ff:ff:fe,10.6.122.104
# {"color": "red", "reserved-by": "Andy"}
f8:a9:d0:4a:cf:1e,10.6.122.105,set:clientf8a9d04acf1e
...
ff:ff:ff:ff:ff:fe,10.6.122.254

Although in dnsmasq.conf all addresses are in the DHCP pool, the file above reserves them all for an unlikely MAC address: ff:ff:ff:ff:ff:fe. Only the addresses that are not listed in this file are really free to be assigned to DHCP requests.

When a user of the system reserves one IP, a comment is added to the file before the corresponding line. The comment is a small JSON with the user settings. Address .104 above is reserved by Andy, is colored green, and it’s not part of the DHCP pool, since it has the unlikely MAC address associated.

Address .105, as shown above, has a tag, the set:... part. That’s Dnsmasq’s way of sending special DHCP settings to specific clients. If the user chooses to have an alternative gateway, that tag is added and a line like the following is written in the dhcp-opts file.

tag:clientf8a9d04acf1e,option:router,10.6.122.96

Now when that specific client connects it will receive a different router option via DHCP.

Get it

The system is of course open source, and all the caveats apply: it comes with zero warranties, especially those of merchantability or fitness for any purpose. Check the code and grab your copy here.