WIFI presence detection

Back in my very first post I talked about using Bluetooth to detect my presence at home in order to disable the CCTV system and control a few other things.

While this works well it does not scale well to multiple people as the Bluetooth layer 2 ping takes about 5 seconds to time out if the device in not in range. This means that at most 12 different phones can be checked in a minute.

A couple of recent chats with a few people at work (Vaibhavi Joshi & Dale Lane and Bharat Bedi) got me thinking about this again. Modern phones tend to have WIFI as well as Bluetooth and 3G radios these days so I thought that I’d have a look at seeing if this could be used to locate devices.

After bit of a poke around it looked like a package called Kisment should be able to do what I wanted.

Kismet

Kismet is a client server application, the backend server reads from the network card and decodes the packets and the UI which requests data from the server over a socket connection. This also means the backend can be on a different machine, in fact several different drone backends can be consolidated in a single master backend server and all the captured data presented to UI. This means you could distribute a number of drones over site and generate a map as devices move between areas covered by the different backends.

The default client is a ncurses based application that can list all the visible networks and a chart showing the incoming packet rates. It’s great for getting a view of what networks are active which can be very useful when you have to set up a new one and want to see which channels are free.

Rather than use the default client I decided to write my own to drive the backend the way I wanted it and to make exposing the data easier (I’m going to publish detected devices on a MQTT topic). But first I had a bit of a play using the netcat (nc) command. Netcat basically pipes stdin/stdout to and from a given socket, this is useful because the Kisment protocol is just a set of simple text commands. For example the following command will get the kismet backend to return a list of all the clients it has seen to date.


echo -e '!0 enable client MAC,manuf,signal_dbm,signal_rssi' | nc localhost 2501


Returns something that looks like this:

...
*CLIENT: 00:25:69:7D:53:D9 [0x01]SagemCommu[0x01] -71 0
...

The only tricky bit about the response is that any field that can contain a space is wrapped in characters with a value of 0x01, in this case the manufacture field could contain spaces so we need the following regexp to chop up the responses for each time a client is spotted.

I decided my client in Java (because the MQTT libraries are easy to use) so I chose to use a regular expression to split up the response

Pattern.compile("\*CLIENT: ([0-9A-F:]*) \x01(.*)\x01 (-?\d+) (\d) ");

By default Kismet cycles round all the available channels to try and get a full picture of all the WIFI traffic in range, but this means it can miss some packets and in turn miss clients that are not generating a lot of traffic. To help get round this I have locked Kismet to just listen on the same channel as my WIFI access point since all my devices are likely to try and connect to it as soon as it comes in range and there is less chance of me missing detecting my phone up front.

!1  HOPSOURCE cab63dc8-9916-11e0-b51a-0f04751ce201 LOCK 13

cab63dc8-9916-11e0-b51a-0f04751ce201 is the UUID assigned to the wifi card by kismet and the 13 is the channel I run my WIFI access point on. You can find the UUID by running the following command:

echo -e '!1234 enable source type,username,channel,uuid' | nc localhost 2501

Which returns a string that looks like this every time the back end hops to new channel.

*KISMET: 0.0.0 1308611701 [0x01]Kismet_2009[0x01] [0x01]alert[0x01] 0 
*PROTOCOLS: KISMET,ERROR,ACK,PROTOCOLS,CAPABILITY,TERMINATE,TIME,PACKET,STATUS, 
PLUGIN,SOURCE,ALERT,WEPKEY,STRING,GPS,BSSID,SSID,CLIENT,BSSIDSRC,CLISRC, 
NETTAG,CLITAG,REMOVE,CHANNEL,SPECTRUM,INFO,BATTERY 
*SOURCE: orinoco_cs test 3 30b9b5a4-9b93-11e0-acfe-ee054e2c7201 
*ACK: 1234 [0x01]OK[0x01]

Publishing the last seen time on the following topic /WIFIWatch/<mac> allows applications to register to see a specific device and also build up a list of all devices ever seen and when.

WIFI Watch topics

It’s not just phones that have WIFI adapters these days, net books, tablets even digital cameras (with things like eyefi) all have , also with multiple kismet nodes it might be possible to track devices as they move around an area.

Next is to look at the signal strength information to see if I can judge a relative distance from the detection adapter.

Resources:

Kismet

17 thoughts on “WIFI presence detection”

  1. Sorry if I sound stupid but is this devices connected to the Wifi or just devices in range of the Wifi? Will this listen to probe packets or just those packets of connected devices? Thanks

    1. Kismet will report all packets on the channel including probe packets and can be set up to hop round the full range of channels to get maximum coverage

  2. Just started playing with Kismet on a Pi with a 4 wifi card directional array to see if I can discover direction relating to signal strength. Really interesting what you were doing. Did you get any further with this?

    Jim

    1. I still use it at home as it is described here to do presence detection, but at work we set up 3 of the rigs and managed to come up with basic triangulation system to do proper location detection. It worked reasonably well.

  3. Did you use the ALERT built into Kismet to respond when your MAC was detected or was that part of your java client? Did your client log to a database?

    1. I’m just looking for the *CLIENT output to keep track of each time kismet sees a packet from a device. It’s all getting consumed by the Java code.

      All the data is thrown at a MQTT broker so it can be consumed by a number of different applications. For the look at the neighbourhood code it was getting logged to a mongodb to help build up some historical patterns.

  4. Sorry im not to too java savy I lost you after netcat! – So is the java client and the broker together or separate elements? Any chance of a simple guide regarding this?

    1. The broker and the Java app are separate. The broker is just a messaging hub for a load of different projects. You can find more about MQTT at mqtt.org.

      The Java app replaces all the netcat stuff. It basically connects to the kismet server component, sends all the command strings that I had been sending manually with nc and then listens for the strings the server spits out when ever it detects something new, normally a packet from device to the access point or a broadcast looking for new access points. It breaks the sting up into it’s component parts, adds a timestamp and them uses that info to build the message published to the broker. The tracking of specific devices (to signal presence detection) is done by other apps that just listen to the feed on the broker.

  5. I see, will the whole lot run on a Raspberry Pi or does it require a bit more oomf? I was looking at at parsing the kismet server syslog entries to something like snort but your way looks way better. Any chance you could post the java client on github?

    1. Jim,

      We used to run this on a collection of Guruplugs which are not too different from Pis and it was fine.

      Unfortunately the code was all written on work time so I can’t really share it without asking.

  6. Ben,

    No probs, i have googled around and found a kismet java client called Jkismet, so will have a tinker and see if i can see how it works. Probably bit off more than I can chew for a first project!!

    All the best!

    Jim

  7. So i notice towards the end you mentioned:
    “Publishing the last seen time ”

    Did you use the nectar command for this?

    I tried running
    “echo -e ‘!0 enable client MAC,manuf,signal_dbm,signal_rssi,last_seen’ | nc localhost 2501”

    and it says an error?

    thanks in advance

    1. I publish the exact time every time I see a packet from a given MAC address as a retained message, this means I always have the “last seen time” available for that device.

      Without the error message I really can’t guess what the problem is.d

      1. I was just wondering how you get this time. Did you use the netcat interface?

        I am tring tomehting like this:

        $ echo -e ‘!0 enable client MAC,manuf,signal_dbm,signal_rssi,last_seen_time’ | nc localhost 2501

        Which results in:
        *ERROR: 0 Unknown field last_seen_time

        1. The last seen time was generated by the java client I used to read the output from kismet. Netcat (nc) was just used to get a view of what the output from the kismet server looked like to make writing the java parser easier.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.