Skip to content

Commit

Permalink
Bring over package stub
Browse files Browse the repository at this point in the history
This doesn't actually fix anything with the package to make it work, it
just brings the package stuff in and replaces relevant files
  • Loading branch information
evantypanski committed Sep 20, 2024
1 parent 947ddd9 commit 6d1b33b
Show file tree
Hide file tree
Showing 30 changed files with 407 additions and 22 deletions.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)

project(RESP LANGUAGES C)

list(PREPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
find_package(SpicyPlugin REQUIRED)

# Set minimum versions that this plugin needs. Make sure to use "x.y.z" format.
# spicy_require_version("1.2.0")
# spicy_plugin_require_version("0.99.0")
# zeek_require_version("5.0.0")

if (NOT CMAKE_BUILD_TYPE)
# Default to release build.
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")
endif ()

add_subdirectory(analyzer)
1 change: 1 addition & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Please provide licensing information here.
13 changes: 13 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Spicy-based RESP analyzer

Parses the [Redis serialization protocol](https://redis.io/docs/latest/develop/reference/protocol-spec/) (RESP).

## Usage

Currently, the package sucks. The following is usage from the `analyzer` directory:

1) Grab a PCAP (like [redis.pcap](https://github.com/macbre/data-flow-graph/blob/master/sources/pcap/redis.pcap))
2) Compile the code so Zeek can use it: `spicyz -o resp.hlto resp.spicy resp.evt zeek_analyzer.spicy`
3) See some output via Zeek: `zeek -C -r redis.pcap resp.hlto`

This will be updated as it's better :)
5 changes: 5 additions & 0 deletions analyzer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
spicy_add_analyzer(
NAME RESP
PACKAGE_NAME spicy-resp
SOURCES resp.spicy resp.evt zeek_resp.spicy
)
2 changes: 1 addition & 1 deletion resp.evt → analyzer/resp.evt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ protocol analyzer spicy::RESP over TCP:
import RESP;
import Zeek_RESP;

on RESP::Data -> event resp::data($conn, Zeek_RESP::create_data(self));
on RESP::Data -> event RESP::data($conn, Zeek_RESP::create_data(self));
2 changes: 0 additions & 2 deletions resp.spicy → analyzer/resp.spicy
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
module RESP;

import spicy;

public type Data = unit {
ty: uint8 &convert=DataType($$);
switch ( self.ty ) {
Expand Down
5 changes: 4 additions & 1 deletion zeek_analyzer.spicy → analyzer/zeek_resp.spicy
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Set up protocol confirmation/rejection for analyzers, as well as any further
# Zeek-specific analysis.

module Zeek_RESP;

import RESP;
import spicy;
import zeek;

# Any error bubbling up to the top unit will trigger a protocol rejection.
on RESP::Data::%done {
print self;
zeek::confirm_protocol();
Expand Down
78 changes: 78 additions & 0 deletions cmake/FindSpicyPlugin.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Find the Spicy plugin to get access to the infrastructure it provides.
#
# While most of the actual CMake logic for building analyzers comes with the Spicy
# plugin for Zeek, this code bootstraps us by asking "spicyz" for the plugin's
# location. Either make sure that "spicyz" is in PATH, set the environment
# variable SPICYZ to point to its location, or set variable ZEEK_SPICY_ROOT
# in either CMake or environment to point to its installation or build
# directory.
#
# This exports:
#
# SPICY_PLUGIN_FOUND True if plugin and all dependencies were found
# SPICYZ Path to spicyz
# SPICY_PLUGIN_VERSION Version string of plugin
# SPICY_PLUGIN_VERSION_NUMBER Numerical version number of plugin

# Runs `spicyz` with the flags given as second argument and stores the output in the variable named
# by the first argument.
function (run_spicycz output)
execute_process(COMMAND "${SPICYZ}" ${ARGN} OUTPUT_VARIABLE output_
OUTPUT_STRIP_TRAILING_WHITESPACE)

string(STRIP "${output_}" output_)
set(${output} "${output_}" PARENT_SCOPE)
endfunction ()

# Checks that the Spicy plugin version it at least the given version.
function (spicy_plugin_require_version version)
string(REGEX MATCH "([0-9]*)\.([0-9]*)\.([0-9]*).*" _ ${version})
math(EXPR version_number "${CMAKE_MATCH_1} * 10000 + ${CMAKE_MATCH_2} * 100 + ${CMAKE_MATCH_3}")

if ("${SPICY_PLUGIN_VERSION_NUMBER}" LESS "${version_number}")
message(FATAL_ERROR "Package requires at least Spicy plugin version ${version}, "
"have ${SPICY_PLUGIN_VERSION}")
endif ()
endfunction ()

###
### Main
###

if (NOT SPICYZ)
set(SPICYZ "$ENV{SPICYZ}")
endif ()

if (NOT SPICYZ)
# Support an in-tree Spicy build.
find_program(
spicyz spicyz
HINTS ${ZEEK_SPICY_ROOT}/bin ${ZEEK_SPICY_ROOT}/build/bin $ENV{ZEEK_SPICY_ROOT}/bin
$ENV{ZEEK_SPICY_ROOT}/build/bin ${PROJECT_SOURCE_DIR}/../../build/bin)
set(SPICYZ "${spicyz}")
endif ()

message(STATUS "spicyz: ${SPICYZ}")

if (SPICYZ)
set(SPICYZ "${SPICYZ}" CACHE PATH "" FORCE) # make sure it's in the cache

run_spicycz(SPICY_PLUGIN_VERSION "--version")
run_spicycz(SPICY_PLUGIN_VERSION_NUMBER "--version-number")
message(STATUS "Zeek plugin version: ${SPICY_PLUGIN_VERSION}")

run_spicycz(spicy_plugin_path "--print-plugin-path")
set(spicy_plugin_cmake_path "${spicy_plugin_path}/cmake")
message(STATUS "Zeek plugin CMake path: ${spicy_plugin_cmake_path}")

list(PREPEND CMAKE_MODULE_PATH "${spicy_plugin_cmake_path}")
find_package(Zeek REQUIRED)
find_package(Spicy REQUIRED)
zeek_print_summary()
spicy_print_summary()

include(ZeekSpicyAnalyzerSupport)
endif ()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SpicyPlugin DEFAULT_MSG SPICYZ ZEEK_FOUND)
18 changes: 0 additions & 18 deletions resp.zeek

This file was deleted.

2 changes: 2 additions & 0 deletions scripts/__load__.zeek
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@load ./main
@load-sigs ./dpd
8 changes: 8 additions & 0 deletions scripts/dpd.sig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# TODO: Use this file to optionally declare signatures activating your analyzer
# (instead of, or in addition to, using a well-known port).
#
# signature dpd_resp {
# ip-proto == tcp
# payload /^\x11\x22\x33\x44/ # TODO: Detect your protocol here.
# enable "spicy_RESP"
# }
103 changes: 103 additions & 0 deletions scripts/main.zeek
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
@load base/protocols/conn/removal-hooks

module RESP;

export {
## Log stream identifier.
redef enum Log::ID += { LOG };

## The ports to register RESP for.
const ports = {
# TODO: Replace with actual port(s).
12345/tcp,
} &redef;

## Record type containing the column fields of the RESP log.
type Info: record {
## Timestamp for when the activity happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;

# TODO: Adapt subsequent fields as needed.

## Request-side payload.
request: string &optional &log;
## Response-side payload.
reply: string &optional &log;
};

## A default logging policy hook for the stream.
global log_policy: Log::PolicyHook;

## Default hook into RESP logging.
global log_resp: event(rec: Info);

## RESP finalization hook.
global finalize_resp: Conn::RemovalHook;
}

redef record connection += {
resp: Info &optional;
};

redef likely_server_ports += { ports };

# TODO: If you're going to send file data into the file analysis framework, you
# need to provide a file handle function. This is a simple example that's
# sufficient if the protocol only transfers a single, complete file at a time.
#
# function get_file_handle(c: connection, is_orig: bool): string
# {
# return cat(Analyzer::ANALYZER_RESP, c$start_time, c$id, is_orig);
# }

event zeek_init() &priority=5
{
Log::create_stream(RESP::LOG, [$columns=Info, $ev=log_resp, $path="resp", $policy=log_policy]);

Analyzer::register_for_ports(Analyzer::ANALYZER_RESP, ports);

# TODO: To activate the file handle function above, uncomment this.
# Files::register_protocol(Analyzer::ANALYZER_RESP, [$get_file_handle=RESP::get_file_handle ]);
}

# Initialize logging state.
hook set_session(c: connection)
{
if ( c?$resp )
return;

c$resp = Info($ts=network_time(), $uid=c$uid, $id=c$id);
Conn::register_removal_hook(c, finalize_resp);
}

function emit_log(c: connection)
{
if ( ! c?$resp )
return;

Log::write(RESP::LOG, c$resp);
delete c$resp;
}

# Example event defined in resp.evt.
event RESP::data(c: connection, is_orig: bool, payload: string)
{
hook set_session(c);

local info = c$resp;
if ( is_orig )
info$request = payload;
else
info$reply = payload;
}

hook finalize_resp(c: connection)
{
# TODO: For UDP protocols, you may want to do this after every request
# and/or reply.
emit_log(c);
}
2 changes: 2 additions & 0 deletions testing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.btest.failed.dat
.tmp
2 changes: 2 additions & 0 deletions testing/Baseline/tests.run-pcap/conn.log.filtered
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.1.9.63 63526 54.175.222.246 80 tcp http 0.755677 207 489 SF 0 ShADTadFf 7 790 4 705 -
2 changes: 2 additions & 0 deletions testing/Baseline/tests.run-pcap/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Hello world!
Goodbye world!
4 changes: 4 additions & 0 deletions testing/Baseline/tests.standalone/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
RESP::Data {
payload: test string
}
3 changes: 3 additions & 0 deletions testing/Baseline/tests.trace/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
Testing RESP: [request] [orig_h=127.0.0.1, orig_p=64091/tcp, resp_h=127.0.0.1, resp_p=12345/tcp] Hello, Spicy!
Testing RESP: [reply] [orig_h=127.0.0.1, orig_p=64091/tcp, resp_h=127.0.0.1, resp_p=12345/tcp] Hello, back!
11 changes: 11 additions & 0 deletions testing/Baseline/tests.trace/resp.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path resp
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p request reply
#types time string addr port addr port string string
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 64091 127.0.0.1 12345 Hello, Spicy! Hello, back!
#close XXXX-XX-XX-XX-XX-XX
21 changes: 21 additions & 0 deletions testing/Files/random.seed
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
2983378351
1299727368
0
310447
0
1409073626
3975311262
34130240
1450515018
1466150520
1342286698
1193956778
2188527278
3361989254
3912865238
3596260151
517973768
1462428821
0
2278350848
32767
3 changes: 3 additions & 0 deletions testing/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

test:
@btest -c btest.cfg
7 changes: 7 additions & 0 deletions testing/Scripts/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Place helper scripts, such a btest-diff canonifiers, in this directory.
Note that Zeek versions 4.1 and newer include their btest tooling as part
of the installation. Take a look at the folder reported via

zeek-config --btest_tools_dir

for scripts, PRNG seeds, and pcaps you might be able to reuse.
6 changes: 6 additions & 0 deletions testing/Scripts/diff-remove-timestamps
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#! /usr/bin/env bash
#
# Replace anything which looks like timestamps with XXXs (including the #start/end markers in logs).

sed -E 's/(0\.000000)|([0-9]{9,10}\.[0-9]{2,8})/XXXXXXXXXX.XXXXXX/g' |
sed -E 's/^ *#(open|close).(19|20)..-..-..-..-..-..$/#\1 XXXX-XX-XX-XX-XX-XX/g'
40 changes: 40 additions & 0 deletions testing/Scripts/get-zeek-env
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#! /bin/sh
#
# BTest helper for getting values for Zeek-related environment variables.

# shellcheck disable=SC2002
base="$(dirname "$0")"
zeek_dist=$(cat "${base}/../../build/CMakeCache.txt" 2>/dev/null | grep ZEEK_DIST | cut -d = -f 2)

if [ -n "${zeek_dist}" ]; then
if [ "$1" = "zeekpath" ]; then
"${zeek_dist}/build/zeek-path-dev"
elif [ "$1" = "zeek_plugin_path" ]; then
(cd "${base}/../.." && pwd)
elif [ "$1" = "path" ]; then
echo "${zeek_dist}/build/src:${zeek_dist}/aux/btest:${base}/:${zeek_dist}/aux/zeek-cut:$PATH"
else
echo "usage: $(basename "$0") <var>" >&2
exit 1
fi
else
# Use Zeek installation for testing. In this case zeek-config must be in PATH.
if ! which zeek-config >/dev/null 2>&1; then
echo "zeek-config not found" >&2
exit 1
fi

if [ "$1" = "zeekpath" ]; then
zeek-config --zeekpath
elif [ "$1" = "zeek_plugin_path" ]; then
# Combine the local tree and the system-wide path. This allows
# us to test on a local build or an installation made via zkg,
# which squirrels away the build.
echo "$(cd "${base}/../.." && pwd)/build:$(zeek-config --plugin_dir)"
elif [ "$1" = "path" ]; then
echo "${PATH}"
else
echo "usage: $(basename "$0") <var>" >&2
exit 1
fi
fi
Binary file added testing/Traces/tcp-port-12345.pcap
Binary file not shown.
Binary file added testing/Traces/udp-port-12345.pcap
Binary file not shown.
Loading

0 comments on commit 6d1b33b

Please sign in to comment.