Categories
Uncategorized

Juniper Mist Guest logger script for the built-in captive portal

Lately I have been deploying several Juniper Mist infrastructures and, for most projects, the built-in captive portal feature inside Mist offers a great solution for guest networks (when you need to rely on a captive portal).

The need for logging

In France, we have some strict regulations and laws regarding Open Wi-Fi networks through which anyone can access Internet. We are required to store any guest activity for an entire year, including personnal information (MAC addresses, names, email, etc…) and their traffic (URLs, IP addresses, time of connection, etc…).

While Mist provides a great captive portal solution, there is no history of guest activity on the dashboard. Once a guest account expires, it simply disappears and there is no remaining data.

So, to abide to French regulations and laws, we need to take care of that logging if we want our customers to use the captive portal.

How to log guest access on Juniper Mist

The first part of the job is to log the guest information. I wrote a Python script that logs any guest connection to a JSON file with a daily file rotation.

Here is the script: https://github.com/jrambeau/mist-guest-logger

Output JSON file from the script, containing guest information

Second part is logging the guest traffic including source IP addresses and destination IP addresses as well as URLs. This second part is crucial because the script won’t do that for you as the guest traffic is not going through the Mist dashboard. I usually achieve this traffic logging on the firewall used for guest Internet access and export the logs for safe keeping.

Using these two sources of information, you will then be able to match a guest to its traffic. You can even automatically cross these information if you happen to have an Elastic or Splunk or any other logging infratructure.

Details about the logger script

Let’s talk a bit more about the script. It uses a Websocket connection to the Mist API framework. This way it can automatically receive any new guest that authenticates to the guest portal. It also uses a RESTFUL API call when that guest authenticates, so it gathers additionnal information the guest has entered on the captive portal registration form (email address, name, etc…).

There is a very important line on this script that is used to filter on the actual guests or any client connecting to the guest SSID. We don’t want to log information about users connected to SSIDs others than the Guest SSID. And there are two ways to do that:

  • I look for the [is_guest] tag from the client information. If the tag is present, we are definitely looking at a guest and we want to log that.
  • Sometimes the [is_guest] tag is not present, for example with manually registered guest. In that case, I am also looking for some keywords on the SSID name to try and catch the Guest SSID: “invite”, “guest”, “hotspot”. Of course, you should modify these if they are not going to match your infrastructure.
Line #86:

if (message.get('data', {}).get('is_guest')) or ('guest' in message['data'].get('ssid', '').lower()) or ('invite' in message['data'].get('ssid', '').lower()) or ('hotspot' in message['data'].get('ssid', '').lower()):

What’s next?

I have been working closely with Thomas Munzer towards the end of this project and I thank him for his help in validating and improving the script. He is currently working with the dev team to provide another way to achieve this and their idea is to provide a Webhook topic. The code could be much simpler using this method. Webhooks and Websockets are a bit different, I let you take a look at the differences below:

Different types of Mist API options (source: Juniper Mist)

I will keep this post updated in case the script evolves and we find better ways to achieve this “Guest logger” program for the Mist captive portal.

Leave a Reply

Your email address will not be published. Required fields are marked *