aboutsummaryrefslogtreecommitdiff
path: root/util/rip_dissector
diff options
context:
space:
mode:
authorNicholas DeMarinis <ndemarinis@wpi.edu>2023-09-29 09:35:23 -0400
committerNicholas DeMarinis <ndemarinis@wpi.edu>2023-09-29 09:35:23 -0400
commit6739e13c64fd2e9a4796cab6fa9c99a2d6134428 (patch)
treed34775ef6beed2e00de49ee14aa7baf649719193 /util/rip_dissector
parenta7a11b1c8b9115a28149a0169c8c90b317f1ac00 (diff)
Added vnet_scripts, RIP dissector, .gitattributes.
Diffstat (limited to 'util/rip_dissector')
-rw-r--r--util/rip_dissector/README.md70
-rw-r--r--util/rip_dissector/cs168_rip.lua115
2 files changed, 185 insertions, 0 deletions
diff --git a/util/rip_dissector/README.md b/util/rip_dissector/README.md
new file mode 100644
index 0000000..abfd6a5
--- /dev/null
+++ b/util/rip_dissector/README.md
@@ -0,0 +1,70 @@
+# CS168 RIP Dissector
+
+This directory contains a dissector (also known as a decoder) for the
+RIP protocol implementation for CS168.
+
+## Installation Instructions
+
+The dissector is provided as a Lua script in this directory. For
+security reasons, Wireshark does not run Lua scripts when run as
+root--therefore, you must ensure that you are using Wireshark as your
+local user, not with root or sudo. To run wireshark as a standard
+user, make sure your user is added to the `wireshark` group. If you
+are using the provided VM, the the vagrant user is already in the
+wireshark group. However, if you are running Wireshark on your own
+system, you will need to configure this yourself.
+
+Once you have Wireshark running as your user. Add the dissector to
+Wireshark, by copying the script into your plugins directory.
+
+To do this:
+ 0. Run wireshark as your user (**not with root or sudo**).
+ 1. Open Wireshark's Help menu and select "About Wireshark".
+ 2. In the folders tab, find the entry "Personal Lua Plugins". For
+ example: `~/.config/wireshark/plugins`
+ 3. Copy the script to this directory (if it doesn't exist, create it)
+ and restart wireshark
+ 4. Open the "About Wireshark" window again and look in the Plugins
+ tab. You should now see cs168_rip.lua in the list of plugins.
+
+## Using the dissector
+
+Note: To make sure your dissector is working, please run the reference IP
+node with an example network to ensure you are testing with correct
+packets.
+
+Wireshark will automatically invoke the RIP dissector when it
+encounters an IP packet using protocol number 200.
+
+Four our overlay network, however, Wireshark does not automatically
+know to interpret our IP-in-UDP packets as IP packets. You can tell
+wireshark to do this using its "User-specified decodes" feature:
+ 1. Start capturing traffic for the IP assignment. In most cases,
+ you will be capturing on the loopback interface.
+ 2. Find a UDP packet related to the assignment and select it. These
+ packets will use the port numbers specified in the lnx files, and
+ therefore may be different depending on the network you are running.
+ 3. Look in the lower pane that shows the layers present in ths
+ packet. Under UDP, you should see a layer "Data" that contains
+ our Virtual IP packets. Select this field.
+ 4. Right-click on the field and select "**Decode As...**" This should
+ open a window and add a rule template to decode UDP traffic on the port
+ number used in the packet. In the rightmost column ("Current"),
+ select the IPv4 decoder, then click "**Save**".
+ 5. Wireshark should now update and decode the UDP packets first as
+ IP packets, and then decode those with protocol 200 as RIP using
+ the dissector you installed.
+
+If you do not see IP packets encapsulated in your UDP packets, check
+your "Decode as... rules from Step 5. If you do not see RIP being
+decoded, make sure the plugin is loaded in the help menu.
+
+**Note**: this will only invoke the correct decoder on a single UDP
+port. If you want to decode the traffic for multiple nodes, repeat
+this process for each port you need to observe.
+
+## Feedback
+
+This decoder and the instructions are new. If you have questions or
+encounter any issues, please post on Piazza or see the course staff
+for help.
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)