Protocols/RELP

xxx - build the Protocol Template to then build a proper RELP page.
(Internet archive: ProtocolTemplate)

https://en.wikipedia.org/wiki/Reliable_Event_Logging_Protocol
https://packages.ubuntu.com/search?keywords=rsyslog-relp&searchon=names&suite=all&section=all
https://www.rsyslog.com/doc/search.html?q=relp&check_keywords=yes&area=default#

240913_RELP_syslog.pcapng

Dissector

-- 240914_RELP_syslog.lua
-- https://ask.wireshark.org/question/35534/dissector-syslog-transmitted-via-relp-protocol-span-multiple-tcp-packets/
-- https://ask.wireshark.org/question/35552/how-to-get-tcp-reassembled-length-in-lua/

-- Step 1 - document as you go. See header above and set_plugin_info().
local relp_info =
{
    version = "0.0.1",
    author = "Chuck Craft",
    description = "rsyslog RELP transport protocol",
    repository = "https://wiki.wireshark.org/Protocols/relp"
}

set_plugin_info(relp_info)

-- Step 1a - global variable(s)
local listen_port = 2514

local syslog_dissector = Dissector.get("syslog")

-- Step 2 - create a protocol to attach new fields to
local relp_p = Proto.new("relp","Reliable Event Logging Protocol")

-- Step 3 - add some field(s) to Step 2 protocol
local pf = {
    txnr           = ProtoField.string("relp.txnr", "Transaction (sequence) number"),
    cmd            = ProtoField.string("relp.cmd", "Command"),
    lendata        = ProtoField.string("relp.lendata", "Length of data part of frame"),
    pdata          = ProtoField.string("relp.pdata", "Frame data part")
}

relp_p.fields = pf

-- Step 4 - create a Field extractor to copy packet field data.
-- easypost_payload_f = Field.new("frame.protocols")

-- Step 5 - dissector functions and dissector main
local txnr, cmd, lendata, header

function _get_length(tvb, pinfo, offset)
    local relp_frame = tvb:range(offset):string()
    txnr, cmd, lendata = string.match(relp_frame, "([^ ]+) ([^ ]+) ([^ \n]+)")
    header = (txnr .." " .. cmd .. " " .. lendata)

    local frame_len = header:len() + 1 + lendata

    if (tonumber(lendata) > 0) then
        return frame_len+1 -- +1 for eol character
    else
        return header:len()+1
    end
end

function _dissect(tvb, pinfo, tree)
    subtree = tree:add(relp_p, tvb())

    pinfo.cols['protocol'] = relp_p.name

    if (string.sub(tostring(pinfo.cols.info), 0, 5) == "RELP:") then
        pinfo.cols.info:append(", " .. (txnr .. ":" .. cmd))
    else
        pinfo.cols.info:set("RELP: " .. txnr .. ":" .. cmd)
    end


    subtree:add(pf.txnr,    tvb(0,txnr:len()))
    subtree:add(pf.cmd,     tvb(txnr:len()+1,cmd:len()))
    subtree:add(pf.lendata, tvb(txnr:len()+1+cmd:len()+1,lendata:len()))
    if (tonumber(lendata) > 0) then
        subtree:add(pf.pdata,   tvb(header:len()+1,lendata))
    end

    if (cmd == "syslog") then
        syslog_dissector:call(tvb(header:len()+1):tvb(), pinfo, tree)
    end
    return tvb:len()
end

function relp_p.dissector(tvb,pinfo,tree)
    dissect_tcp_pdus(tvb, tree, 0, _get_length, _dissect, true)
end

-- Step 6 - register the new protocol with the TCP dissector
tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(listen_port, relp_p)