Search code examples
wiresharkzigbeewireshark-dissector

Wireshark 802.15.4 Dissector for all Destinations in Lua


I'm getting started creating a Dissector for an IEEE 802.15.4 packet. I'm using the TI cc2531 dongle and the python script ccsniffpip to get data into Wireshark. So far so good as I can see the packets as raw 802.15.4 packets just fine. My problem is with dissecting the payload with my custom protocol. It seems that Wireshark is designed assuming that the 802.15.4 destination addresses significant in the sense that ports are intended to hint at what the packet type is. For 15.4 that is often just not the case. For 15.4 the destination is more akin to an IP address. I want to decode every 15.4 packet I see. In my case, I have my protocol hiding inside the "data" section of 15.4 packets with the first byte of the data indicating the packet type. I have no problem creating a simple Lua dissector to walk through things and build out some simple trees, but as fas as I can tell, I have to go in by hand in the GUI and tell the program to Decode As "MyProtocol" for each new destination address that becomes allocated by the master 15.4 device. My need to to make my dissector promiscuous to all 15.4 destination addresses. I've fond notes where dissector_add for_decode_as was exposed to Lua ( "Wireshark-commits: [Wireshark-commits] master 016769d: Expose dissector_add_for_decode_as() to Lua"), but I can't find any examples on how to use it in Lua for 15.4.

Also any high level architecture suggestions would be greatly appreciated. My simple dissector that I have written seems to not be able to highlight the particular data in the bottom data pane so I assume that I am not using Wireshark in the right way.

FYI I got started using this related SO note: Wireshark Lua Dissector for IEEE 802.15.4 - DissectorTable name?


Solution

  • NB: I am not really answering your question, but providing an avenue for a different way to solve the issue.

    I had a very similar problem a few years ago. We were building a product that used the 802.15.4 MAC layer directly, and we needed a tool to dissect our custom payloads.

    Originally I used ccsniffpiper (and the tools I built it from), and wrote dissectors in LUA which I loaded into Wireshark. However, I found that this process was slow and tedious for a number of reasons (doing the LUA dissectors was tricky, loading them into wireshark was not always straight-forward, and using Python was faster overall).

    Instead, I developed a 'command line' tool that wrapped around pyCCSniffer and provided my custom dissecting in python!

    I have had a quick read over the pyCCSniffer code and am now thinking that it is a bit chaotic...but I think it could be quite handy for your problem. Thus I'll explain how we used it in a bit more detail.

    We had a custom 'PacketHandler' class for our company (e.g. "ACMEPacketHandler"), similar to the one defined in the pyCCSniffer.py file. And we registered this in the 'main' method of our script:

    def main():
        packetHandler = ACMEPacketHandler()
        packetHandler.enable()
    
        # Create a list of handlers to dispatch to
        # NB: handlers must have a "handleSniffedPacket" method
        handlers = [packetHandler]
        def handlerDispatcher(timestamp, macPDU):
            if len(macPDU) > 0:
                packet = SniffedPacket(macPDU, timestamp)
                for handler in handlers:
                    handler.handleSniffedPacket(packet)
    
        snifferDev = CC2531EMK(handlerDispatcher, args.channel)
    

    Then in the 'handleSniffedPacket' method of our ACMEPacketHandler we had something like this:

    class ACMEPacketHandler:
        ...
        def handleSniffedPacket(self, sniffedPacket):
            ...check errors etc...
    
            # parse as 802.15.4 frame
            frame = ieee.IEEE15dot4FrameFactory.parse(sniffedPacket)
    
            # parse contents of frames to our custom representation
            our_frame = ACMEFrameFactory.parse(frame)
    
            print(our_frame)
    

    And then in the 'ACMEFrameFactory' we had the logic to parse the information we needed from the specific 802.15.4 frames:

    class ACMEFrameFactory(object):
        @staticmethod
        def parse(ieee15dot4Frame):
    
            if noe ieee15dot4Frame.fcf.frametype is ieee.FrameType.DATA:
                return ieee15dot4Frame # we only use payloads in DATA frames
            byteStream = ieee15dot4Frame.msdu
    
            offset = 0
            fmt = "<B"
            (packet_type,) = ieee.checkAndUnpack(fmt, byteStream, offset, (0, 0))
    
            if packet_type == 1:
                return WilyCoyotePlotFrame(...)
            if packet_type == 2:
                return RoadRunnerMeepMeepFrame(...)
    
            # unknown packet_type
            return ieee15dot4Frame
    

    I hope that helps (it's my two cents anyway).