Create a Wireshark dissector in Lua

You have a custom protocol over TCP and would like to give your users the ability to visualize it in Wireshark? This post is for you. To create your dissector I recommend Wireshark’s Lua API and the embedded Lua interpreter. It is the easiest way to prototype dissectors, which for performance reasons may later be rewritten in C. At the time of writing I am still using Wireshark 1.2.1, but you might consider using the latest version.

Let us begin with some sample code.

Protocol dissector script in Lua

We use a chained dissector, it adds functionality to dissect packets of an existing protocol, such as packets destined to a particular tcp port. It receives only the payload part of the original protocol packet as the input buffer in the dissector function.

-- create myproto protocol and its fields
p_myproto = Proto ("myproto","My Protocol")
local f_command = ProtoField.uint16("myproto.command", "Command", base.HEX)
local f_data = ProtoField.string("myproto.data", "Data", FT_STRING)

p_myproto.fields = {f_command}

-- myproto dissector function
function p_myproto.dissector (buf, pkt, root)
  -- validate packet length is adequate, otherwise quit
  if buf:len() == 0 then return end
  pkt.cols.protocol = p_myproto.name

  -- create subtree for myproto
  subtree = root:add(p_myproto, buf(0))
  -- add protocol fields to subtree
  subtree:add(f_command, buf(0,2)):append_text(" [Command text]")

  -- description of payload
  subtree:append_text(", Command details here or in the tree below")
end

-- Initialization routine
function p_myproto.init()
end

-- register a chained dissector for port 8002
local tcp_dissector_table = DissectorTable.get("tcp.port")
dissector = tcp_dissector_table:get_dissector(8002)
  -- you can call dissector from function p_myproto.dissector above
  -- so that the previous dissector gets called
tcp_dissector_table:add(8002, p_myproto)

Running the Lua script in Wireshark

Here are the steps required to get the above code running. If your Wireshark version is 1.4 or better, skip step 3.

  1. Edit and save the lua script above to any folder (e.g. c:\myproto) and call the file myproto.lua
  2. Open init.lua in the Wireshark installation directory for editing. You will need Admin privileges on Windows Vista and 7.
  3. Comment out the following line in init.lua (single line comments begin with --):
    disable_lua = true; do return end;
  4. Add the following lines to init.lua (at the very end):
    MYPROTO_SCRIPT_PATH="C:\\myproto\\"
    dofile(MYPROTO_SCRIPT_PATH.."myproto.lua")
  5. Change MYPROTO_SCRIPT_PATH to point to the folder where you saved the script in step 1
  6. Run Wireshark
  7. Load a capture file that has the packets of your custom protocol or start a live capture

Here’s a figure that shows the protocol dissector in action.

35 thoughts on “Create a Wireshark dissector in Lua

  1. Hello, I am using ubuntu 11.10

    I followed your method along with if 0 and running_superuser then
    local disabled_lib = {}
    to make Lua work its still throwing out dofile disabled error.

    i am using 1.6.2 version

  2. Hello,
    I am trying to isolate a custom protocol that comes in the data part of udp using Lua scripts in Wireshark. How can i recognize these with flag values of the custom headers that come sequncially after udp headers in udp’s data.
    Any Idea where there is a proper list of comands pertaining to wireshark-lua script writing.
    A big Thanx in Advance.

    I am using latest wireshark version.

    Edwin Abraham

    1. Writing a dissector for UDP is very much like writing a dissector for TCP. You can register to dissect UDP packets with a particular port as follows

      local udp_dissector_table = DissectorTable.get("udp.port")
      dissector = udp_dissector_table:get_dissector(8002)
        -- you can call dissector from function p_myproto.dissector above
        -- so that the previous dissector gets called
      udp_dissector_table:add(8002, p_myproto)
      

      For help on Wireshark’s LUA API please refer to http://www.wireshark.org/docs/wsug_html_chunked/wsluarm.html. For Lua related information see the manual at http://www.lua.org/manual/5.1/manual.html.

      1. Okay suppose I did this. How does Wireshark know that this is my custom protocol. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag. Anyway of getting the data part of udp and then compare it?
        and is there a way to tell wireshark to look at all my udp ports not just a specific one?

      2. Q. Okay suppose I did this. How does Wireshark know that this is my custom protocol.

        A. You create a new Proto object, that is how it knows.

        Q. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag.

        A. You specify the fields by setting the fields property of your Proto object. You can add fields dynamically from the dissector function of your Proto object by using the root parameter. Wireshark cannot filter based on those fields though. You don’t need any additional flags, you can filter packets based on the procotol name to begin with.

        Q. Anyway of getting the data part of udp and then compare it?

        A. You can use the buf object, a parameter of the dissector function, to get the data and do whatever you want with it.

        Q. …and is there a way to tell wireshark to look at all my udp ports not just a specific one?

        A. You can register your protocol dissector against as many ports as you wish. Just repeat the following several times with different port numbers

        dissector = udp_dissector_table:get_dissector(8002)
        udp_dissector_table:add(8002, p_myproto)
        
  3. Thanx for the info firstly. One last question.

    The protocol I have to recognize is a udp packet where the data part of udp will act as headers for the rest of the data in the packet. Its a completely new packet and only way to Identify whether the udp that comes is of that custom protocol is a field that is 12th (unsigned long) from the udp headers. Now I defined all the names of the headers with uint32. But it still doesn’t understand that its myproto. I feel its because I haven’t asked it to recognize that. Now the only way it will recognize is by comparing the 12th uint32 data with some value.

    I understood the part of the udp ports , the protocol creation, but from the udp packet how will it know its my packet. For that what do I do? You said with the name of the protocol. But from where the packet?

    1. You can do that with something like the following in the dissector function

      if buf(11):uint() == val then
      
        -- dissect
      
      else
        -- call the previous dissector and quit
        dissector:call(buf, pkt, root)
        return
      end
      
  4. Hello!
    Thanks you for yours tutor. I have a problem with my dissector, and i need yours help. After running LUA script, I want to count total packets that appear in myproto. So, i dont know how to do :|. Can u help me,pls?.
    Sorry my english is not good
    Thank

    1. Hello! The dissector function is called once for each packet. You can maintain a global counter (defined outside the function) and increment it each time the dissector function is called, e.g.

      local count = 0
      ...
      function p_myproto.dissector (buf, pkt, root)
      ...
        count = count + 1
      ...
      end
      
  5. Hi,
    I see the following error thrown while the Wireshark GUI loads:
    Lua: Error during loading:
    C:\Program Files\Wireshark\myproto.lua:1: unexpected symbol near ‘{‘

    I have copied the script as is and placed “myproto.lua” in folder where “init.lua” is located (c:\Program Files\Wireshark )and added

    dofile(“myproto.lua”) at the end .

    Request to please help solve the issue

    1. Hi Santosh. The code as posted should work. Check that you didn’t add any extra characters into the script by mistake. Please tell more about your environment – OS version, Wireshark version etc.

      1. Devendra,
        Thanks I actually posted it on a rtf file that had extra charecters appended before the actual script. I used notepad and its fine now and working.

        Thanks for the post as it is tailor made for my use.

        Wanted to know are there ways to convert the hex data in the payload and display it as a decimal value when we expand the subtree for the custom protocol.

        Ex. Subtree lists “Squence Number: 3886” , for the value 0f2e in the payload.

        I use wireshark version 1.8.0 on Windows XP

        Thanks.

      2. Hi Santosh. The buf parameter of the dissector function is of type Tvb. You can obtain a TvbRange by doing something like buf(offset, 2). TvbRange has methods that return integer and other values. For your case you can use something like buf(offset, 2):uint(). Remember to change offset to the position in the buffer you want to read your value from. If the byte order of the data is little endian you can use le_uint. Follow the Wireshark Lua API link above for further details.

  6. Thanks Devendra.
    I was able to get my requirement of the previous post however, facing the issue while adding new protocol fields.

    only buf(x,x) ; where x=0,1,2,3,4 are accepted

    i.e, for Ex.If I attempt subtree:add(f_command, buf(4,5)) or subtree:add(f_command, buf(5,5)),

    It fails with error thrown as, [Dissector bug, protocol KODRTPOTCP: proto.c:1115: failed assertion “DISSECTOR_ASSERT_NOT_REACHED”].

    Can you please let me know what could be the problem.

    Thanks.

    1. You are most certainly exceeding the bounds of the buffer. You should create a TvbRange like buf(offset, length). The second parameter is the length of the field, not the end index/offset.

      1. It is intelligent enough to determine that the range has just 2 bytes (16 bits) and create an integer value from that. I hope that answers your question. If not, I don’t understand your question.

  7. Yes it’s obvious. Missed it. Thanks.

    Also,
    I plan to use control structure (if/else) and depending upon the value of payload data decoded, append text to the subtree, but I am facing issue in the same.

    i.e,
    local f_cmd = ProtoField.uint32(“Koproto.cmd”, “Version”,base.DEC)

    The above command displays the Version in subtree (as 2) correctly but when I use it in if/else statement, it’s not able to resolve, i.e

    if f_cmd == 2 then
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is 2″)
    else
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is not 2″)
    end.

    This Is failing.

    Unfortunately cannot print the value of “f_cmd” to verify what it holds actually.

    Can you please let me know what could be the issue?

    Thanks.

    1. f_cmd is like a template, not the actual field. You can read the value directly from buf as TvbRange and using one of its methods, then use that value in the if statement.

  8. Hi,
    Thanks for your reply.
    I face following error when I tried working with bitstring:

    Lua: Error during loading:
    error loading module ‘bitstring’ from file ‘C:\Program Files\Wireshark\bitstring.dll’:
    %1 is not a valid Win32 application.

    Can I know what could be the reason for the same?

    Followed following steps:
    1. Copy ‘bitstring.dll’ to your wireshark directory. This file provides ‘bitstring’ library for Lua.
    2. Copy ‘coap.lua’ to somewhere in your wireshark directory. For example, /plugins/coap/coap.lua.
    3. Open ‘init.lua’ in your wireshark root directory. Comment the line ‘disable_lua = true’ or change it to ‘disable_lua = false’.
    4. Add ‘dofile(“/plugins/coap/coap.lua”)’ at the end of the file(init.lua)

  9. I made a slight change to associate the dissector with port 80 because I have a test pcap with that traffic. At the bottom of the page in the screenshot shows a filterable field called myproto.command that links to 0x ebff. When I run this script it parses out the bytes but my bytes (2 bytes from traffic) show up as text. If this data is text then I cannot filter or use tshark command. Can you shed some light on this matter? I have tried a lot of different things and cannot get it to work:( Also, I am evaluating the lua script directly in wireshark via the evaluate option and then I refresh my test pcap.

  10. Hello, I’m trying to create a protocol using Lua. But I want to put the protocol defined in analyze- enabled protocols in wireshark. If you do not mind Do you think you can help me?

    1. If I understand you correctly, you want the protocol to appear in the dialog that appears when you go to the Analyze menu and select Enabled Protocols…

      That being the case, there is nothing you need to do. If you’ve created the dissector as shown above, it will appear in the Enabled Protocols dialog.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s