aboutsummaryrefslogtreecommitdiff
path: root/util/rip_dissector/cs168_rip.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/rip_dissector/cs168_rip.lua')
-rw-r--r--util/rip_dissector/cs168_rip.lua115
1 files changed, 115 insertions, 0 deletions
diff --git a/util/rip_dissector/cs168_rip.lua b/util/rip_dissector/cs168_rip.lua
new file mode 100644
index 0000000..4e6e6d9
--- /dev/null
+++ b/util/rip_dissector/cs168_rip.lua
@@ -0,0 +1,115 @@
+-- CS168 RIP Protocol Dissector
+--
+-- The structure of a RIP message is as follows:
+-- uint16_t command
+-- uint16_t num_entries
+-- struct {
+-- uint32_t cost
+-- uint32_t address
+-- } entries[num_entries]
+
+local RIP_HEADER_LEN = 4
+local ROUTE_ENTRY_LEN = 12
+
+rip_protocol = Proto("CS168RIP", "CS168 RIP")
+
+command = ProtoField.uint16("cs168rip.command", "command", base.DEC)
+num_entries = ProtoField.uint16("cs168rip.num_entries", "num_entries", base.DEC)
+
+rip_entry_cost = ProtoField.uint32("cs168rip.entry.cost", "cost", base.DEC)
+rip_entry_addr = ProtoField.ipv4("cs168rip.entry.address", "address")
+rip_entry_mask = ProtoField.ipv4("cs168rip.entry.mask", "mask")
+
+
+rip_protocol.fields = {
+ command,
+ num_entries,
+ rip_entry_cost,
+ rip_entry_addr,
+ rip_entry_mask,
+}
+
+local ef_bad_entry = ProtoExpert.new("cs168rip.query.entry.expert",
+ "Route entry missing or malformed",
+ expert.group.MALFORMED,
+ expert.severity.WARN)
+
+rip_protocol.experts = {
+ ef_bad_entry,
+}
+
+local field_cost = Field.new("cs168rip.entry.cost")
+local field_addr = Field.new("cs168rip.entry.address")
+local field_mask = Field.new("cs168rip.entry.mask")
+
+
+function rip_protocol.dissector(buffer, pinfo, tree)
+ length = buffer:len()
+ if length == 0 then return end
+
+ pinfo.cols.protocol = rip_protocol.name
+
+ local subtree = tree:add(rip_protocol, buffer(), "CS168 RIP Protocol")
+
+ local pktlen = buffer:reported_length_remaining()
+
+ local cmd_num = buffer(0, 2):uint()
+ local cmd_name = get_command_name(cmd_num)
+
+ -- Add command ID and name
+ subtree:add(command, buffer(0, 2)):append_text(" (" .. cmd_name .. ") ")
+ pinfo.cols.info:append("RIP " .. cmd_name)
+
+ -- num_entries
+ local entry_count = buffer(2, 2):uint()
+ subtree:add(num_entries, buffer(2, 2))
+ pinfo.cols.info:append(" (" .. entry_count .. " entries)")
+
+ local pos = RIP_HEADER_LEN
+ local e_idx = 0
+
+ -- Parse each entry
+ if entry_count > 0 then
+ local entry_tree = subtree:add("Entries")
+
+ local pkt_remaining = pktlen - pos
+
+ while entry_count > 0 and pkt_remaining > 0 do
+ if pkt_remaining < ROUTE_ENTRY_LEN then
+ entry_tree:add_proto_expert_info(ef_bad_entry)
+ return
+ end
+
+ local cost = buffer(pos, 4):uint()
+ local address = buffer(pos + 4, 4):uint()
+ local mask = buffer(pos + 8, 4):uint()
+
+ -- TODO Add each entry to its own subtree (with helpful summary)
+ local etree = entry_tree
+
+ etree:add(rip_entry_cost, buffer(pos, 4))
+ etree:add(rip_entry_addr, buffer(pos + 4, 4))
+ etree:add(rip_entry_mask, buffer(pos + 8, 4))
+
+ pos = pos + 12
+
+ pkt_remaining = pkt_remaining - 12
+ entry_count = entry_count - 1
+ e_idx = e_idx + 1
+ end
+ end
+
+end
+
+function get_command_name(cmd)
+ local name = "UNKNOWN"
+ if cmd == 1 then name = "REQUEST"
+ elseif cmd == 2 then name = "RESPONSE"
+ end
+
+ return name
+end
+
+
+local ip_proto = DissectorTable.get("ip.proto")
+ip_proto:add(200, rip_protocol.dissector)