Lua/Examples/filtcols

A post-dissector to allow filtering on Protocol and Info columns

Enhancement: filter for info column in Wireshark Issue #13491

Installation - place in plugins directory - see Lua Support in Wireshark

filtcols.lua

Example - Analyze filter smb2.cmd == 9 && smb2.filename contains "fname" shows no results
Filter filtcols.info contains "file87.txt"
Sample capture from SMB2 page.

201002_filtcols_info

Example - Filter TLS 1.3 traffic in Wireshark
Filter filtcols.protocol == "TLSv1.3"
Sample capture from Issue #12779 Add TLS 1.3 support

201002_filtcols_protocol

References
Post-dissector examples
gaddman/wireshark-tcpextend (Also on the Contrib page and LUA dissector: update treeitem in earlier packet )
Creating a Wireshark USB dissector in Lua - part 1 (mouse)
Creating a Wireshark dissector in Lua - part 1 (the basics)

-- filtcols.lua
-- similar to _ws.col.protocol in tshark

local filtcols_info =
{
    version = "1.0.2",
    author = "Chuck Craft",
    description = "Support filtering on Protocol and Info columns",
}

set_plugin_info(filtcols_info)

-- we create a "protocol" for our tree
local filtcols_p = Proto("filtcols","Filterable Protocol/Info columns")

-- we create our fields
local col_protocol_field = ProtoField.string("filtcols.protocol", "Protocol column")
local col_info_field = ProtoField.string("filtcols.info", "Info column")

-- we add our fields to the protocol
filtcols_p.fields = { col_protocol_field, col_info_field }

-- variables to persist across all packets
local pkt_data = {} -- indexed per packet

pkt_data.protocol = {}
pkt_data.info = {}

-- let's do it!
function filtcols_p.dissector(tvb,pinfo,tree)

    local cols_protocol = tostring(pinfo.cols.protocol)

    if  cols_protocol ~= "(protocol)" then
        pkt_data.protocol[pinfo.number] = cols_protocol
    end


    local pkt_proto = pkt_data.protocol[pinfo.number]

    if  pkt_proto ~= nil then
        tree:add(col_protocol_field, pkt_proto)
    end


    
    local cols_info = tostring(pinfo.cols.info)

    if cols_info ~= "(info)" then
        pkt_data.info[pinfo.number] = cols_info
    end


    local pkt_info = pkt_data.info[pinfo.number]

    if pkt_info ~= nil then
         tree:add(col_info_field, pkt_info)
    end
end

-- then we register filtcols_p as a postdissector
register_postdissector(filtcols_p)

mi·nu·ti·ae
In the SMB2 example there was not a good field(s) to use as a filter but Wireshark had placed enough data in the Info column.

The search for TLSv1.3 was difficult - no version field but could see that Wireshark was decoding by version.
packet-tls-util.c

/* Lookup tables {{{ */
const value_string ssl_version_short_names[] = {
    { SSLV2_VERSION,        "SSLv2" },
    { SSLV3_VERSION,        "SSLv3" },
    { TLSV1_VERSION,        "TLSv1" },
    { TLSV1DOT1_VERSION,    "TLSv1.1" },
    { TLSV1DOT2_VERSION,    "TLSv1.2" },
    { TLSV1DOT3_VERSION,    "TLSv1.3" },
    { DTLSV1DOT0_VERSION,   "DTLSv1.0" },
    { DTLSV1DOT2_VERSION,   "DTLSv1.2" },
    { DTLSV1DOT0_OPENSSL_VERSION, "DTLS 1.0 (OpenSSL pre 0.9.8f)" },
    { 0x00, NULL }
};

    col_set_str(pinfo->cinfo, COL_PROTOCOL,
                val_to_str_const(session->version, ssl_version_short_names, "SSL"));

There is session->version but it's not available to use in a display filter.

Notes

Pinfo and pinfo.cols - where do they come from?

The Wireshark Lua API Reference is auto-generated from files in epan/wslua and included in the Wireshark Developer’s Guide. All the information is there but it's sometimes quicker to look at the source.

As used in filtcols:

pinfo.number, pinfo.cols:
Pinfo source is epan/wslua/wslua_pinfo.c which combines epan/packet_info.h, epan/frame_data.h and maybe others?

pinfo.cols.protocol, pinfo.cols.info:
Columns source in epan/wslua/wslua_column.c which aligns with epan/column-utils.h.

Why is pinfo.cols returning an empty value?

tshark has special magical incantations for whether or not it populates the cinfo that Lua pulls pinfo.cols data from. There is an open merge request (2473: tshark: add --columns option) to add an option to explicitly create the column data.

tshark.c

    /* We only need the columns if either
         1) some tap needs the columns
       or
         2) we're printing packet info but we're *not* verbose; in verbose
            mode, we print the protocol tree, not the protocol summary.
       or
         3) there is a column mapped as an individual field */
    if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && print_summary) || output_fields_has_cols(output_fields))
      cinfo = &cf->cinfo;
    else
      cinfo = NULL;

-T fields will create the data but at that point you may as well add -e _ws.col.info and -e _ws.col.protocol to the command and skip Lua.
Until then try -V as mentioned in 11.7.1. TreeItem or -P (tshark man page: DESCRIPTION but be aware -T options will foobar things.

      } else if (strcmp(optarg, "pdml") == 0) {
        output_action = WRITE_XML;
        print_details = TRUE;   /* Need details */
        print_summary = FALSE;  /* Don't allow summary */
      } else if (strcmp(optarg, "psml") == 0) {
        output_action = WRITE_XML;
        print_details = FALSE;  /* Don't allow details */
        print_summary = TRUE;   /* Need summary */
      } else if (strcmp(optarg, "fields") == 0) {
        output_action = WRITE_FIELDS;
        print_details = TRUE;   /* Need full tree info */
        print_summary = FALSE;  /* Don't allow summary */
      } else if (strcmp(optarg, "json") == 0) {
        output_action = WRITE_JSON;
        print_details = TRUE;   /* Need details */
        print_summary = FALSE;  /* Don't allow summary */
      } else if (strcmp(optarg, "ek") == 0) {
        output_action = WRITE_EK;
        if (!print_summary)
          print_details = TRUE;
      } else if (strcmp(optarg, "jsonraw") == 0) {
        output_action = WRITE_JSON_RAW;
        print_details = TRUE;   /* Need details */
        print_summary = FALSE;  /* Don't allow summary */
      }

Nil vs Null
Lua: What's the difference between null and nil?
Lua Reference Manual: "Nil is a type with a single value, nil, whose main property is to be different from any other value."

The 1.0.0 version of filtcols did comparisons against NULL (oops) and happened to work in Wireshark but not tshark. @cjmaynard fixed it in this Wireshark Q&A question: Tshark LUA Script

FIXME - update script here on Wiki page.filtcols.lua