diff options
25 files changed, 420 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..440b509 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +\#*# +*.o + +.DS_Store + +# Created by tester +/stations +/reference/stations diff --git a/mp3/Beethoven-SymphonyNo5.mp3 b/mp3/Beethoven-SymphonyNo5.mp3 Binary files differnew file mode 100644 index 0000000..33fb0f9 --- /dev/null +++ b/mp3/Beethoven-SymphonyNo5.mp3 diff --git a/mp3/DukeEllington-Caravan.mp3 b/mp3/DukeEllington-Caravan.mp3 Binary files differnew file mode 100644 index 0000000..be08489 --- /dev/null +++ b/mp3/DukeEllington-Caravan.mp3 diff --git a/mp3/FX-Impact193.mp3 b/mp3/FX-Impact193.mp3 Binary files differnew file mode 100644 index 0000000..48950f0 --- /dev/null +++ b/mp3/FX-Impact193.mp3 diff --git a/mp3/ManchurianCandidates-Breakin.mp3 b/mp3/ManchurianCandidates-Breakin.mp3 Binary files differnew file mode 100644 index 0000000..d5ff1d5 --- /dev/null +++ b/mp3/ManchurianCandidates-Breakin.mp3 diff --git a/mp3/ManchurianCandidates-TwentyEightHouse.mp3 b/mp3/ManchurianCandidates-TwentyEightHouse.mp3 Binary files differnew file mode 100644 index 0000000..11a2342 --- /dev/null +++ b/mp3/ManchurianCandidates-TwentyEightHouse.mp3 diff --git a/mp3/U2-StuckInAMoment.mp3 b/mp3/U2-StuckInAMoment.mp3 Binary files differnew file mode 100644 index 0000000..0908a8c --- /dev/null +++ b/mp3/U2-StuckInAMoment.mp3 diff --git a/mp3/VanillaIce-IceIceBaby.mp3 b/mp3/VanillaIce-IceIceBaby.mp3 Binary files differnew file mode 100644 index 0000000..732d19d --- /dev/null +++ b/mp3/VanillaIce-IceIceBaby.mp3 diff --git a/reference/arm64/snowcast_control b/reference/arm64/snowcast_control Binary files differnew file mode 100755 index 0000000..4336ed0 --- /dev/null +++ b/reference/arm64/snowcast_control diff --git a/reference/arm64/snowcast_listener b/reference/arm64/snowcast_listener Binary files differnew file mode 100755 index 0000000..0ddb872 --- /dev/null +++ b/reference/arm64/snowcast_listener diff --git a/reference/arm64/snowcast_server b/reference/arm64/snowcast_server Binary files differnew file mode 100755 index 0000000..5d9a380 --- /dev/null +++ b/reference/arm64/snowcast_server diff --git a/reference/snowcast_control b/reference/snowcast_control Binary files differnew file mode 100755 index 0000000..866cead --- /dev/null +++ b/reference/snowcast_control diff --git a/reference/snowcast_listener b/reference/snowcast_listener Binary files differnew file mode 100755 index 0000000..6033d3f --- /dev/null +++ b/reference/snowcast_listener diff --git a/reference/snowcast_server b/reference/snowcast_server Binary files differnew file mode 100755 index 0000000..8107323 --- /dev/null +++ b/reference/snowcast_server diff --git a/util/run_tests b/util/run_tests new file mode 100755 index 0000000..4dbdf4b --- /dev/null +++ b/util/run_tests @@ -0,0 +1,192 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +TESTER_DIR=${SCRIPT_DIR}/tester +DATA_DIR=${TESTER_DIR}/data +MP3_DIR=${SCRIPT_DIR}/../mp3 + +# Set automatically +arch="`uname -m`" +platform= + +verbose=true +fail_fast=false +bin_dir=$(realpath ${SCRIPT_DIR}/..) + +__check_platform() +{ + if test -z "$platform" -a \( "$arch" = "arm64" -o "$arch" = "aarch64" \); then + platform=linux/arm64 + elif test -z "$platform"; then + platform=linux/amd64 + fi +} + +do_help() { + cat <<EOF +Usage $0: [options] [command] [tester args] + +This command runs tester programs for each component +of Snowcast. + +Top-level options: + --quiet Don't print the output of each test + --fail-fast Stop after the first test failure + --arm Force using binaries for arm64 platform + +Commands: + all Run all tests + server Run tests for snowcast_server + control Run tests for snowcast_control + milestone Run tests for the project milestone + +Tester args: + -help Display usage info for tester + +If no command is specified, the default is 'all'. +EOF +} + +check_exists() { + bin="$1" + if [[ ! -e ${bin} ]]; then + echo "Binary ${bin} not found! Exiting" + exit 1 + fi +} + +run_tester() { + tester_name=$1 + shift + + case $platform in + linux/amd64) + tester_path=${TESTER_DIR}/ + ;; + linux/arm64) + tester_path=${TESTER_DIR}/arm64 + ;; + *) + echo "Unsupported platform ${platform}" + exit 1 + esac + + vflag="" + if $verbose; then + vflag="-test.v" + fi + + failflag="" + if $fail_fast; then + failflag="-test.failfast" + fi + + export BIN_DIR=${bin_dir} + export MP3_DIR=$MP3_DIR + export DATA_DIR=$DATA_DIR + ${tester_path}/${tester_name} $vflag $failflag $@ +} + +do_server() { + check_exists "${bin_dir}/snowcast_server" + run_tester server_tester $@ +} + +do_control() { + check_exists "${bin_dir}/snowcast_server" + run_tester server_tester $@ +} + +do_milestone() { + do_control -test.run="Test.+?/Test(ConnectsToServer|AcceptsClientConnection|CompletesHandshake)" + do_server -test.v -test.run="Test.+?/Test(ConnectsToServer|AcceptsClientConnection|CompletesHandshake)" +} + + +do_all() { + do_server $@ + do_control $@ +} + +main() { + POSITIONAL=() + while [[ $# -gt 0 ]]; do + key=$1 + case $key in + --fail-fast|-f) + shift + fail_fast=true + ;; + --quiet|-q) + shift + verbose=false + ;; + -a|--arm|--arm64|--aarch64) + shift + if [[ ( "${arch}" == "arm64" ) || ( "${arch}" == "aarch64" ) ]]; then + platform=linux/arm64 + else + echo "$0 --arm only works on arm64 hosts (platform is ${arch})" 1>&2 + exit 1 + fi + ;; + -x|--x86-64) + shift + platform=linux/amd64 + ;; + --bin-dir) + bin_dir="$2" + shift + shift + ;; + --help) + shift + do_help + exit 0 + ;; + *) + POSITIONAL+=("$1") + shift + esac + done + set -- "${POSITIONAL[@]}" + + __check_platform + + # Default subcommand + if [[ $# == 0 ]]; then + do_all + exit 0 + fi + + # Subcommands + case $1 in + help) + do_help + exit 0 + ;; + server) + shift + do_server $@ + ;; + control) + shift + do_control $@ + ;; + milestone) + shift + do_milestone $@ + ;; + all) + shift + do_all $@ + ;; + *) + echo "Unrecognized command $1" + exit 1 + ;; + esac +} + +main $@ diff --git a/util/snowcast-dissector/README.md b/util/snowcast-dissector/README.md new file mode 100644 index 0000000..a62522e --- /dev/null +++ b/util/snowcast-dissector/README.md @@ -0,0 +1,68 @@ +# CS1680 Snowcast Dissector + +THis directory contains a dissector (also known as a decoder) for the Snowcast +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: + + 1. Run wireshark as your user (**not with root or sudo**). + 2. Open Wireshark's Help menu and select "About Wireshark". + 3. In the folders tab, find the entry "Personal Lua Plugins". For example: + `~/.config/wireshark/plugins` + 4. Copy the script to this directory (if it doesn't exist, create it) and + restart wireshark + 5. 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 + +_To make sure your dissector is working, please run the Snowcast reference +binaries_ + +Wireshark will automatically invoke the Snowcast dissector when it encounters a +TCP packets on port 1680. This means that if you start the Snowcast server on +port 1680, TCP packets on port 1680 will automatically be decoded as Snowcast +commands and replies. + +To use the Snowcast dissector with other port numbers we can instruct wireshark +to interpret TCP packets on a given port as Snowcast commands and responses. +We can tell wireshark to do this using Wireshark's "User-Specified Decodes" +feature: + +1. Run your binaries and to start capturing packets. You should be capturing + packets on the loopback interface. +2. Find a TCP packet related to this assignment and select it. These packets + will have a destination and source port number. One of these port numbers + should be the port number you selected when starting up the Snowcast server. +3. Right click on the TCP packet and select "Decode As..." +4. Double click "(none)" under "current" and select CS168SNOWCAST. + +Wireshark should no update and decode the TCP packets with your specified port +number as Snowcast commands and replies. + +If you do not see Snowcast commands and replies, check your "Decode As..." rule +from step 4. If you still do not see Snowcast commands and replies, make sure +that the plugin is loaded in the help menu. + +### Disclaimer + +The steps listed above will invoke the decoder only on a single TCP port. You +should repeat the steps above each time you change TCP ports + +## Feedback + +If you have questions or encounter any issues with the decoder, please post on +EdStem or see the course staff for help. diff --git a/util/snowcast-dissector/cs168_snowcast.lua b/util/snowcast-dissector/cs168_snowcast.lua new file mode 100644 index 0000000..5389035 --- /dev/null +++ b/util/snowcast-dissector/cs168_snowcast.lua @@ -0,0 +1,107 @@ +-- CS168 Snowcast Protocol Dissector + +snowcast_protocol = Proto("CS168Snowcast", "CS168 Snowcast Protocol") + +message = ProtoField.uint8("cs168snowcast.messsage_type", "messageType", base.DEC) + +-- HELLO fields +udp_port = ProtoField.uint16("cs168snowcast.udp_port", "udpPort", base.DEC) +-- SET_STATION fields +station_number = ProtoField.uint16("cs168snowcast.station_number", "stationNumber", base.DEC) +-- WELCOME fields +num_stations = ProtoField.uint16("cs168snowcast.num_stations", "numStations", base.DEC) +-- ANNOUNCE fields +song_name_size = ProtoField.uint8("cs168snowcast.song_name_size", "songnameSize", base.DEC) +song_name = ProtoField.string("cs168snowcast.song_name", "songname") +-- INVALID_COMMAND fields +reply_string_size = ProtoField.uint8("cs168snowcast.reply_string_size", "replyStringSize", base.DEC) +reply_string = ProtoField.string("cs168snowcast.reply_string", "replyString") + +snowcast_protocol.fields = { + message, + udp_port, + station_number, + num_stations, + song_name_size, + song_name, + reply_string_size, + reply_string +} + +function snowcast_protocol.dissector(buffer, pinfo, tree) + length = buffer:len() + if length == 0 then return end + + pinfo.cols.protocol = snowcast_protocol.name + + local subtree = tree:add(snowcast_protocol, buffer(), "Snowcast Protocol Data") + + local packet_len = buffer:reported_length_remaining() + + local message_num = buffer(0, 1):uint() + local message_name = get_message_name(message_num) + + -- Add command ID and name + subtree:add(message, buffer(0, 1)):append_text(" (" .. message_name .. ") ") + + -- Clear any existing info in the info column so the TCP stuff info isn't in the way + pinfo.cols.info = "" + + pinfo.cols.info:append("Snowcast " .. message_name) + + if message_num == 0 then + -- Handling HELLO command + local udpPort = buffer(1, 2):uint() + subtree:add(udp_port, buffer(1, 2)) + pinfo.cols.info:append(" (UDP Port: " .. udpPort .. ") ") + elseif message_num == 1 then + -- Handling SET_STATION command + local stationNumber = buffer(1, 2):uint() + subtree:add(station_number, buffer(1, 2)) + pinfo.cols.info:append(" (Station Number: " .. stationNumber .. ") ") + elseif message_num == 2 then + -- Handling WELCOME reply + local numStations = buffer(1, 2):uint() + subtree:add(num_stations, buffer(1, 2)) + pinfo.cols.info:append(" (Station Number: " .. numStations .. ") ") + elseif message_num == 3 then + -- Handling ANNOUNCE reply + local songnameSize = buffer(1, 1):uint() + subtree:add(reply_string_size, buffer(1, 1)) + + local songname = buffer(2, songnameSize):string() + subtree:add(reply_string, buffer(2, songnameSize)) + + pinfo.cols.info:append(" (Song Name [" .. songnameSize .. " bytes]: " .. songname .. ") ") + elseif message_num == 4 then + -- Handling INVALID_COMMAND reply + local replyStringSize = buffer(1, 1):uint() + subtree:add(reply_string_size, buffer(1, 1)) + + local replyString = buffer(2, replyStringSize):string() + subtree:add(reply_string, buffer(2, replyStringSize)) + + pinfo.cols.info:append(" (Reply String [" .. replyStringSize .. " bytes]: " .. replyString .. ") ") + end +end + +function get_message_name(message_num) + local message_name = "UNNOWN" + + if message_num == 0 then + message_name = "HELLO" + elseif message_num == 1 then + message_name = "SET_STATION" + elseif message_num == 2 then + message_name = "WELCOME REPLY" + elseif message_num == 3 then + message_name = "ANNOUNCE REPLY" + elseif message_num == 4 then + message_name = "INVALID_COMMAND REPLY" + end + + return message_name +end + +local tcp_port = DissectorTable.get("tcp.port") +tcp_port:add(16800, snowcast_protocol) diff --git a/util/snowcast-dissector/install.sh b/util/snowcast-dissector/install.sh new file mode 100755 index 0000000..efd2341 --- /dev/null +++ b/util/snowcast-dissector/install.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +TARGET=~/.config/wireshark/plugins + +main() { + mkdir -pv ${TARGET} + install -v -m644 ${SCRIPT_DIR}/cs168_snowcast.lua ${TARGET} +} + +main $@ diff --git a/util/tester/arm64/control_tester b/util/tester/arm64/control_tester Binary files differnew file mode 100755 index 0000000..5eebce7 --- /dev/null +++ b/util/tester/arm64/control_tester diff --git a/util/tester/arm64/server_tester b/util/tester/arm64/server_tester Binary files differnew file mode 100755 index 0000000..6694cfe --- /dev/null +++ b/util/tester/arm64/server_tester diff --git a/util/tester/control_tester b/util/tester/control_tester Binary files differnew file mode 100755 index 0000000..942e960 --- /dev/null +++ b/util/tester/control_tester diff --git a/util/tester/data/short_file b/util/tester/data/short_file Binary files differnew file mode 100644 index 0000000..cc198a1 --- /dev/null +++ b/util/tester/data/short_file diff --git a/util/tester/data/test.txt b/util/tester/data/test.txt new file mode 100644 index 0000000..e4f841e --- /dev/null +++ b/util/tester/data/test.txt @@ -0,0 +1,12 @@ +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567 +1234567
\ No newline at end of file diff --git a/util/tester/server_tester b/util/tester/server_tester Binary files differnew file mode 100755 index 0000000..13063ec --- /dev/null +++ b/util/tester/server_tester diff --git a/util/update_from_stencil b/util/update_from_stencil new file mode 100755 index 0000000..6385b67 --- /dev/null +++ b/util/update_from_stencil @@ -0,0 +1,18 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +REPO_DIR=$(realpath ${SCRIPT_DIR}/..) + +STENCIL_REPO=http://github.com/brown-csci1680/snowcast-template + +main() { + git remote rm stencil || true + git remote add stencil $STENCIL_REPO + + git pull stencil main +} + + +main $@ |