Monday, July 28, 2014

nRF24L01+ sniffer - part 3

In the first two parts of this series I explained the mechanism behind 'promiscuous' capturing of nRF24L01+ packets on air. I explained how to build hardware and install software to be able to capture the packets and analyze them using Wireshark. This post will dive deeper into the possibilities of the wireless sniffer and Wireshark combo and give you some insight in what this powerful tool has to offer.

Wireshark basics


If you followed the instructions to install the sniffer software and start Wireshark in the previous post, Wireshark should now be capturing:


The capture screen is divided in three parts: The packets captured, the details of the selected packet and the raw packet & payload data.
Packets captured each have a sequential number, and a timestamp (captured with microsecond resolution by the sniffer). These are shown in the first two columns of the packet list named No. and Time. Next two columns contain the Source node address and Destination node address (the base address has been omitted). As nRF24L01+ packets only contain a destination address, the source address will display a question mark. Later we will see that when a higher-level protocol contains the source node address this will be filled. Next is the Protocol column. When capturing the screenshot I only had the nrf24 dissector installed (nrf24.dll in the Wireshark plugins directory), so Wireshark only recognizes nRF24 packages. By adding extra dissectors (e.g. for MySensors) it will also recognize protocols that use the nRF24 as transport medium. Next column is the total packet Length, in bytes followed by the Info column which contains a short, textual description of the packet data. I chose to display the full address (base+node), payload length, pid and ack-flag (inverted NO_ACK).
Packets of length 0 are interpreted by the nRF24 as acknowledgement packets.
The nrf24 dissector calculates the CRC value of every packet. This value should match with the CRC stored in the packet. The CRC for packet 165 apparently failed, therefore it is marked as 'CRC Error' in the info column and its contents cannot be trusted.
When a packet is selected its details appear in the section below. Here you can see, bit by bit, how the packet is dissected.
Click on one of the fields and its location  in the raw packet data will be shown in the section at the bottom. When a packet contains a payload that can further be dissected its raw data are shown in a separate tab (e.g. 'Frame (22bytes)' for the raw frame data and 'NRF24 Payload Data (12 bytes)' for the actual payload data.
This observation is important as the nRF24 has a header which is not a multiple of 8 bits. Any bytes stored as payload will appear bit-shifted in the 'Frame' data, but are shown as regular bytes in the 'NRF24 Payload Data'. In the screenshot the 'NRF24 Payload Data' is shown, in which you might even recognize a MySensors payload: a temperature reading of 24.9 degrees.

Filtering


One of the most powerful features of Wireshark is filtering. Packets captured can be filtered using expressions on the details of the packet data. The nrf24 dissector recognizes the folowing filter keywords:

  • nrf24.node - full node addres, including base address
  • nrf24.ctrl - control field value
  • nrf24.ctrl.len - payload length
  • nrf24.ctrl.pid - pid value
  • nrf24.ctrl.noack - NO_ACK flag
  • nrf24.crc - CRC value
  • nrf24.crcvalid - flag indicating if CRC is valid or not
Filter expressions are entered in the 'Filter:' editbox on the top of the screen.

Now lets display all packets captured with CRC errors:


Enter 'nrf24.crcvalid == false' and press Apply.
Or filter on all packets with payload of 22 bytes or more, and valid CRC:



You probably get it by now, right? For the filter syntax please refer to the Wireshark user's guide.

IO Graph and statistics


Another nice feature for long term capturing is the IO graph, available through the menu Statistics -> IO Graph.
After capturing for a while and moving the sensor node around a bit, the graph looked like:


The black line shows the number of packets per 10 sec. over a timespan of a little over 700 seconds. When the sensor node started, the number of packets peaked at approx. 200 packets. It then settled at around 40, to increase again after 450 sec.
I enabled 'Graph 2' with the previously explored CRC invalid expression, which is drawn as red bars in the graph. Apparently the location where I moved the sensor node after 450 sec. lead to a clear increase in CRC errors!

Wireshark has many, many more possibilities to analyze your network traffic. I suggest to play around for a while and explore the user manual.

MySensors dissector


Along with the nrf24 dissector I also wrote two dissectors for the MySensors protocol. The stable version 1.3 will be dissected by mysensors1.dll, the beta 1.4 by mysensors2.dll. As said before, only have one of the mysensors dissectors active in the plugins directory, as Wireshark might otherwise mixup protocol versions 1 & 2 in a single capture. Below is a screenshot of a MySensors 1.4b communication capture, between nodes 0 (gateway) and 124 (sensor):

In the selected packet an acknowledge of a temperature value is sent by the gateway to the sensor node. Note that both Source and Destination node addresses are now set for the packets of the mysensors Protocol.
For version 1 (1.3) the following filters are supported:
  • mysensors.crc - CRC value
  • mysensors.crcvalid - CRC Valid flag
  • mysensors.version - Version (always 1)
  • mysensors.binary - Binary flag
  • mysensors.sender - Sender node address
  • mysensors.dest - Destination node address
  • mysensors.last - Last node address
  • mysensors.childid - ChildID for sensor value
  • mysensors.msgtype - Message type
  • mysensors.subtype - Sub type

For version 2 (1.4) the following filters are supported:
  • mysensors.paylen - Length of payload, in bytes
  • mysensors.version - Version (always 2)
  • mysensors.datatype - Data type
  • mysensors.cmdtype - Command type
  • mysensors.ack - Ack flag
  • mysensors.sender - Sender node address
  • mysensors.last - Last node address
  • mysensors.dest - Destination node address
  • mysensors.type - Type
  • mysensors.sensor - Sensor
Capturing all messages to the gateway (dest == 0) for sensor 3 (ChildId 3) results in the following display:


Wrapup

In the past days I've presented a wireless packet sniffer for nRF24L01+ radios. It has very powerful features, thanks to the integration of Wireshark, but also has some limitations anyone who uses it should be aware of.
Currently the dissectors cannot be configured, so packets are always assumed to be in Enhanced Shockburst format, with 1 byte node address and 2 byte CRC value.
Always remember that the nRF24 sniffer uses a regular radio to capture that packets on air. Sometimes it detects CRC errors, while another node will receive the packet correctly, and vice versa.

16 comments:

  1. Good work!

    I had considered the theoretical possibility of using a shorter address, no CRC and fixed length payload to capture an ESB packet & CRC - or most of it, in the case of a nearlly full ESB packet. But the decoding seemed like a lot of work.

    Using wireshark seems to have worked well for you, including handling the nested levels of protocol and the alternatives at the same level (1.3v 1.4). You have surmounted all difficulties to create a useful tool, thank you.

    ReplyDelete
    Replies
    1. Thanks for your positive reponse man! Appreciate it!

      Delete
  2. Thank you for the work you have done.

    There are 3 things that I bumped into though that I would like to share with you and those that decide to use the sniffer.

    1. Immediately after starting 'Nrf24Sniff.exe -P6' (the rest is default in my case) I got this error message 'The program can't start because MSVCR110.dll is missing...'. It basically complains that 'Visual C++ Redistributable Packages for Visual Studio 2012 SP 4' is not installed but that is not true. After doing a bit of searching I found that I needed to install or repair 'Microsoft Essentials'.
    Once this was done the program works as expected (don't ask me why, this must be pure MS genius).

    2. Once Wireshark was started like described I noticed that the Nrf24Sniff console window displayed a 'Wait for sniffer to restart' message. The author mentions that this will only take a few seconds but in my case I actually needed to reset the Arduino for it to go away. No exception.

    3. After creating the correct setup in Wireshark I expected data to show up but it did not. I wondered why and ran a complete test to see that the Ardiuno was ok, radio sufficiently powered etc. but that was all ok. I then re-read the article and found that the author says 'when monitoring MySensors 1.4beta traffic (at non-default 1Mb/s)'. I completely missed this and that caused the issue. The MySensors 1.4beta is set to 250b/s by default. Once I started the sniffer like 'Nrf24Sniff.exe -P6 -r2' everything works as expected.

    So, a big thank you to the author!!!

    ReplyDelete
    Replies
    1. Thanks for trying out. Too bad you ran into troubles (don't say I didn't warn you ;-).
      Some remarks:
      1. According to http://stackoverflow.com/a/17585163 the DLL should be included in the 'Visual C++ Redistributable for Visual Studio 2012 Update 4' but you need to run all of the installers. I didn't try it yet, as I need to be on a machine without Vsisual Studio installed.
      2. I experience the same problem. Probably packets come in after resetting (captured during reset of the Arduino) which get returned before the configuration is processed. This chokes the nrf24sniff executable. I'll have a look at it.
      3. MySensors 1.4 was switched from default 1Mbps to 250Kbps, as this was believed to decrease CRC errors. I didn't see a difference and sticked with 1Mbps, which became the default in the tool... Now you can check for yourself what bitrate performes best!

      Delete
  3. Very very cool work! What a grey write up too! Not only did u kick a$$ on the dissectors, research, etc., but wrote it Barney Style so anybody could reproduce your work. Thank you.
    I would add that friend Goodspeed and I have been chatting a bit on the Twittertubes about your great work built on top of his initial research. If you're on Twitter ping myself or Travis. We'd love to "meet" you to possibly discuss further.

    @infosec208 on Twitter.

    ReplyDelete
  4. Glad you like it! The dissectors took far more time to develop than I expected, mainly to the limited development docs on Wireshark dissectors... I'm not very active on Twitter but I might someday... Cheers!

    ReplyDelete
  5. Hi, I use Wireshark V1.12 and I do have an error when I start wireshark, it can't find nrf24.dll while it has been copied to the correct dir.

    ReplyDelete
    Replies
    1. I see some possible error causes:
      * I developed and tested using Wireshark 1.10.8. The dissectors might not be compatible with 1.12.x without recompilation. Maybe you can try with Wireshark 1.10.x?
      * Did you copy the correct version (32 or 64 bits) of the library, that matches your Wireshark architecture?
      If this all doesn't help, could you provide some more details, like 32/64bits, where you installed Wireshark and the plugins etc?
      Good luck!

      Delete
    2. I did remove 1.12 64Bit version and installed 1.10.9 64 Bit version on W7 64 Bit. I did copy the correct 64 version and now it detects the dll and I can also see it help->About->Plugins in the list. It doesn't work yet but we did solve this issue.

      Delete
    3. I checked your project and I was not able to capture a working setup on my side, I did look with the logic analyzer what your sending to the nordic chip and found that your only sending 2 bytes as address bytes and not the 4 you have to send. This is why your setup is not working on my side. I did have a quick look to see the error but I think it is inside the arduino code.

      Delete
    4. I found that the getAddressWidth(void) call does not work correct !. It always returns 2 even if the SETUP_AW return 0x02 !!.

      Delete
    5. I located the problem: The Nordic nRF24L01 expect the SPI data to be stable on the rising edge of the SPI clock. This is not happening, it is even changing on the rising edge and stable on the falling edge. The SPI functions are not correct for the nordic. I changed SPI mode_0 to mode_1 but this only solves the input sampling problem not the output shifting of the SPI on the arduino.

      Delete
    6. The nRF24 driver I'm using is just a 'standard' driver derived from Maniacbug's implementation everybody seems to be using.
      If the SPI configuration really is wrong, this is a serious bug!
      Could also be a problem in the SPI implementation in the Arduino libraries. Which Arduino IDE version do you use?
      Did you make any progress on the issue?

      Delete
    7. @Yveaux, I located the problem. Today I received the new saleae logic Pro series of logic analyzers and I did have a good look at what happens. 8MHz SPI speed mode 0. The MOSI output is delay a lot and by mounting a pullup resistor of 1K to 3V3 I made sure that the data is stable well before the clock signal. It still fails and its due to the fact that I am sending at maximum speed 1 Mbits/s but sending packets every 400us. The internal processing of the arduino nRF24 lib is so bad and slow that you have to wait a minimum of 1ms between two transmissions to make it work. I will try to make the lib faster.

      Delete
  6. It would be interesting to see if you can add the wireshark code to the RTL-SDR version of the sniffer - http://blog.cyberexplorer.me/2014/01/sniffing-and-decoding-nrf24l01-and.html

    ReplyDelete
  7. Does anyone know of a BLE 4.0 sniffer for wireshark ?

    ReplyDelete