Capture loopback communication on Windows

Wireshark is unable to capture any loopback communication (not just loopback interface) on Windows using WinPcap. You’ll need to replace WinPcap with Npcap to be able to do that.

Uninstall WinPcap first.

Select the following options (uncheck support for raw 802.11 traffic at your discretion) during Npcap setup

Npcap Setup

To capture loopback traffic, capture on the Npcap loopback Adapter




Highlighting problems in Lua dissectors

Here’s a snippet of code from nordic_ble dissector that shows how you can highlight problems in Lua dissectors using add_expert_info

        local item  = tree:add_le(hf_nordic_ble_micok, tvb(UART_PACKET_FLAGS_INDEX, 1), micok > 0)
        if micok == 0 then
            -- MIC is bad
            item:add_expert_info(PI_CHECKSUM, PI_WARN, "MIC is bad")
            item:add_expert_info(PI_UNDECODED, PI_WARN, "Decryption failed (wrong key?)")

NOTE I recommend using add_proto_expert_info because add_expert_info is now deprecated.

SSL/TLS decryption in Wireshark

Wireshark’s dissector for SSL is able to decrypt SSL/TLS, given the private key in PFX/P12 or PEM format. If you want to figure out whether you’re using the right private key, you can derive the public key from it, and compare its modulus with the first certificate in the chain of certificates sent in the SERVER HELLO.

$ openssl rsa -text -in key.pem -pubout
Private-Key: (2048 bit)


Wireshark dissector in Lua for custom protocol over WebSockets

It is fairly easy to write a Wireshark dissector in Lua for your custom protocol over WebSockets. To understand the basics of writing, and using, dissectors for Wireshark in Lua, see Create a Wireshark dissector in Lua.

Here’s a template to get you started with writing your custom dissector. Replace port number 8002, with the port number where your WebSocket server listens for incoming connections, and the dissector should be called.


You can also register the dissector using declared WebSocket protocol name. Retrieve the ws.protocol dissector table instead of ws.port, and add your dissector to the dissector table using protocol name (a string) instead of port number.

If using WebSockets over SSL/TLS, you need to specify the server’s private key file in SSL protocol dissector‘s configuration, so that Wireshark can decrypt the traffic. The protocol field in configuration should be set to http.

Lua dofile and globals

I have been doing dissector development for Wireshark in Lua for a while now. Lua’s mechanism for reusing code organized across multiple files comes in two flavors, dofile and require. For historical reasons, we’ve been using dofile quite exclusively.

Our dissector files mostly contain global functions, and local or global tables. The tables are used to determine which function should be called to dissect a particular message, to look-up names that map to particular key values, and so on. If a script file needs a function or table in another file, we simply dofile the other file at the top. Lua interpreter will recognize all globals (functions and variables without local) of the other file from that point onwards.

Let’s consider an example. Here’s file1.lua

function f1()
  print("f1 called")



Here’s file2.lua, located in the same folder as file1.lua

function f2()
  print("f2 called")

When you run file1.lua, this is what you get

$ lua file1.lua
f1 called
f2 called

Lua only encounters call to global f2 inside function f1 when we call function f1 towards the end of file1.lua. If we call f1 right at the beginning of file1.lua we get

$ lua file1.lua
lua: file1.lua:2: attempt to call global 'f1' (a nil value)
stack traceback:
	file1.lua:2: in main chunk
	[C]: in ?

If we move dofile towards the end of file1.lua we get

$ lua file1.lua
f1 called
lua: file1.lua:3: attempt to call global 'f2' (a nil value)
stack traceback:
	file1.lua:3: in function 'f1'
	file1.lua:7: in main chunk
	[C]: in ?

Summing it up, a global exists only when Lua has encountered it, whether within the same or another script file.

Let us explore one other characteristic of dofile with another example. This is file1.lua

hello['world'] = 'hello!'

function f1()



It requires a certain global table in file2.lua, which it updates before using. It also requires a certain function f3 in file3.lua. This is file2.lua

hello = {['hello']='world!'}

function f2()
  print("f2 called")

This is file3.lua


function f3()
  print('f3 called')

It needs function f2 in file2.lua. You shouldn’t need dofile because file1.lua has already loaded file2.lua, but whoever coded file3.lua probably doesn’t know that. Let’s execute file1.lua and see what happens

$ lua file1.lua
f3 called
f2 called

By the time function f1 gets called, the value of key 'world' in the hello table ceases to exist. Why? Because, right before f1 is called, when we dofile file3.lua it will dofile file2.lua. Since file2.lua gets interpreted again, the global hello is replaced by a new table.

Summing it up, Lua will load and execute the same file again when it encounters dofile, redefining all globals in it.

That is why, for reusing code in other script files, use require. Lua will not reinterpret a script file that has already been encountered before. Modifying the example scripts above is straightforward. Replace all dofile with require and drop the lua extension. Thus dofile('file2.lua') will become require('file2'). Execute file1.lua thus

$ export LUA_PATH=$PWD/?.lua
$ lua file1.lua
f3 called
f2 called

Globals now work without side-effects! Note the use of LUA_PATH environment variable to specify the search path for Lua scripts. You can also set search path inside a Lua script by modifying package.path.

What if you have already invested in dofile and don’t want to change things for now? In the example above, modifying file2.lua thus, eliminates our problem

if hello == nil then hello = { } end

function f2()
  print("f2 called")

Wireshark migrating to Qt

Wireshark on Mac OS X is downright ugly. It requires XQuartz, an X11 port for OS X. Wireshark have announced that they have begun a steady migration to Qt. The move has its critics, and backers. I back whatever looks better than it currently does. As Miguel de Icaza of Xamarin points out, it is possible to look good on Mac OS X with the Gtk+ port for Cocoa. So what gives?

Handling TCP keep-alive

Keep-alives are useful in scenarios where either end of a TCP connection disappears without closing the session.

The following script in Python demonstrates sending a keep-alive message when there is no data activity for 60 seconds. If there is no response, 4 additional keep-alive messages are sent at intervals of 15 seconds. If none get a response, the connection is aborted.

Edit the IP address and port to whatever works on your network.

Create a test TCP listener/server using netcat (nc on OS X) on machine with IP address specified in the script

netcat -l 8001

Next, run the script


It should establish a TCP connection with the listener. Interrupt the network by enabling a firewall, or powering off a router. You’ll see the following when the connection times out

Traceback (most recent call last):
  File "", line 39, in do_work
    req = sock.recv(10)
error: [Errno 110] Connection timed out
Other Socket err, exit and try creating socket again

On OS X or Windows, you can enable keep-alive but cannot set TCP_KEEPIDLE and other parameters. You’ll get the following error message if you try to do so

Traceback (most recent call last):
  File "", line 65, in <module>
  File "", line 19, in do_work
    sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60)
AttributeError: 'module' object has no attribute 'TCP_KEEPIDLE'

Wireshark highlights keep-alive messages if TCP sequence number analysis is enabled.