spciy-redis: Bring Redis analyzer into Zeek proper

This commit is contained in:
Evan Typanski 2025-03-19 13:50:11 -04:00
parent aef9fe11dc
commit 11777bd6d5
39 changed files with 293 additions and 279 deletions

View file

@ -30,6 +30,8 @@ extend-ignore-re = [
"ot->Yield\\(\\)->InternalType\\(\\)",
"switch \\( ot \\)",
"\\(ZAMOpType ot\\)",
"exat", # Redis expire at
"EXAT",
# News stuff
"SupressWeirds.*deprecated",

View file

@ -72,6 +72,7 @@
@load base/protocols/quic
@load base/protocols/radius
@load base/protocols/rdp
@load base/protocols/redis
@load base/protocols/rfb
@load base/protocols/sip
@load base/protocols/snmp

View file

@ -1,3 +1,6 @@
@if ( have_spicy_analyzers() )
@load ./spicy-decls
@load ./main
@load-sigs ./dpd.sig
@endif

View file

@ -1,6 +1,8 @@
@load base/protocols/conn/removal-hooks
@load base/frameworks/signatures
@load ./spicy-decls
module Redis;
export {
@ -10,49 +12,6 @@ export {
## The ports to register Redis for.
const ports = { 6379/tcp } &redef;
type SetCommand: record {
key: string &log;
value: string &log;
nx: bool;
xx: bool;
get: bool;
ex: count &optional;
px: count &optional;
exat: count &optional;
pxat: count &optional;
keep_ttl: bool;
};
type GetCommand: record {
key: string &log;
};
type AuthCommand: record {
username: string &optional;
password: string;
};
type Command: record {
## The raw command, exactly as parsed
raw: vector of string;
## The first element of the command. Some commands are two strings, meaning this
## is inaccurate for those cases.
command: string &log;
## The key, if this command is known to have a key
key: string &log &optional;
## The value, if this command is known to have a value
value: string &log &optional;
## The command in an enum if it was known
known: Redis::KnownCommand &optional;
};
type ServerData: record {
## Was this an error?
err: bool &log;
## The string response, if it was a simple string or error
data: string &log &optional;
};
## Record type containing the column fields of the Redis log.
type Info: record {
## Timestamp for when the activity happened.
@ -61,18 +20,15 @@ export {
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## The Redis command
cmd: Command &log &optional;
## The response for the command
## The Redis command.
cmd: Command &log;
## The response for the command.
response: ServerData &log &optional;
};
## A default logging policy hook for the stream.
global log_policy: Log::PolicyHook;
## Default hook into Redis logging.
global log_resp: event(rec: Info);
global finalize_redis: Conn::RemovalHook;
type State: record {
@ -82,7 +38,7 @@ export {
current_request: count &default=0;
## Current response in the pending queue.
current_response: count &default=0;
## Ranges where we do not expect a response
## Ranges where we do not expect a response.
## Each range is one or two elements, one meaning it's unbounded, two meaning
## it begins at one and ends at the second.
no_response_ranges: vector of vector of count;
@ -105,7 +61,7 @@ redef likely_server_ports += { ports };
event zeek_init() &priority=5
{
Log::create_stream(Redis::LOG, [ $columns=Info, $ev=log_resp, $path="redis",
Log::create_stream(Redis::LOG, [ $columns=Info, $path="redis",
$policy=log_policy ]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SPICY_REDIS, ports);
@ -155,14 +111,14 @@ function set_state(c: connection, is_orig: bool)
c$redis = c$redis_state$pending[current];
}
# Returns true if the last interval exists and is closed
## Returns whether the last "no response" interval is not still open.
function is_last_interval_closed(c: connection): bool
{
return |c$redis_state$no_response_ranges| == 0
|| |c$redis_state$no_response_ranges[|c$redis_state$no_response_ranges| - 1]| != 1;
}
event Redis::command(c: connection, is_orig: bool, command: Command)
event Redis::client_command(c: connection, command: Command)
{
if ( ! c?$redis_state )
make_new_state(c);
@ -179,6 +135,9 @@ event Redis::command(c: connection, is_orig: bool, command: Command)
}
++c$redis_state$current_request;
# CLIENT commands can skip a number of responses and may be used with
# pipelining. We need special logic in order to track the request/response
# pairs.
if ( command?$known && command$known == KnownCommand_CLIENT )
{
# All 3 CLIENT commands we care about have 3 elements
@ -238,7 +197,7 @@ function response_num(c: connection): count
return resp_num;
}
event Redis::server_data(c: connection, is_orig: bool, data: ServerData)
event Redis::server_data(c: connection, data: Redis::ServerData)
{
if ( ! c?$redis_state )
make_new_state(c);

View file

@ -0,0 +1,97 @@
##! Events and records generated by the Redis analyzer.
module Redis;
export {
## The Redis SET command.
type SetCommand: record {
## The key the SET command is setting.
key: string &log;
## The value the SET command is setting key to.
value: string &log;
## If NX is set -- only set the key if it does not exist.
nx: bool;
## If XX is set -- only set the key if it already exists.
xx: bool;
## If GET is set -- return the old string stored at key.
get: bool;
## EX option -- set the specified expire time, in seconds.
ex: count &optional;
## PX option -- set the specified expire time, in milliseconds.
px: count &optional;
## EXAT option-- set the specified Unix time at which the key will
## expire, in seconds.
exat: count &optional;
## PXAT option -- set the specified Unix time at which the key will
## expire, in milliseconds.
pxat: count &optional;
## If KEEPTTL is set -- retain the time to live associated with the key.
keep_ttl: bool;
};
## The Redis AUTH command.
type AuthCommand: record {
## The username getting authenticated.
username: string &optional;
## The password authenticated with.
password: string;
};
## A generic Redis command from the client.
type Command: record {
## The raw command, exactly as parsed
raw: vector of string;
## The first element of the command. Some commands are two strings, meaning
## this is inaccurate for those cases.
command: string &log;
## The key, if this command is known to have a key
key: string &log &optional;
## The value, if this command is known to have a value
value: string &log &optional;
## The command in an enum if it was known
known: KnownCommand &optional;
};
## Generic server data returned from the server.
type ServerData: record {
## Was this an error?
err: bool &log;
## The string response, if it was a simple string or error
data: string &log &optional;
};
}
## Generated for Redis SET commands sent to the Redis server.
##
## c: The connection.
##
## command: The SET command sent to the server and its data.
global set_command: event(c: connection, command: SetCommand);
## Generated for Redis GET commands sent to the Redis server.
##
## c: The connection.
##
## command: The GET command sent to the server and its data.
global get_command: event(c: connection, key: string);
## Generated for Redis AUTH commands sent to the Redis server.
##
## c: The connection.
##
## command: The AUTH command sent to the server and its data.
global auth_command: event(c: connection, command: AuthCommand);
## Generated for every command sent by the client to the Redis server.
##
## c: The connection.
##
## command: The command sent to the server.
global client_command: event(c: connection, command: Command);
## Generated for every response sent by the Redis server to the client.
##
## c: The connection.
##
## data: The server data sent to the client.
global server_data: event(c: connection, data: ServerData);

View file

@ -32,6 +32,7 @@ add_subdirectory(postgresql)
add_subdirectory(quic)
add_subdirectory(radius)
add_subdirectory(rdp)
add_subdirectory(redis)
add_subdirectory(rfb)
add_subdirectory(rpc)
add_subdirectory(sip)

View file

@ -2,5 +2,4 @@ spicy_add_analyzer(
NAME Redis
PACKAGE_NAME spicy-redis
SOURCES resp.spicy resp.evt redis.spicy zeek_redis.spicy
SCRIPTS __load__.zeek main.zeek
)
MODULES RESP Redis Zeek_Redis)

View file

@ -1,3 +1,5 @@
# See the file "COPYING" in the main distribution directory for copyright.
#
# Handle any Redis-specific "parsing"
module Redis;
@ -126,16 +128,12 @@ public function inline_command(command: RESP::ClientData): Command {
}
}
if (it == end(command.inline)) {
if (it == end(command.inline))
done = True;
# If we're still in quotes, that's weird, but not really too bad.
#if (double_quotes || single_quotes)
# zeek::weird("unbalanced_quotes", "unbalanced quotes in inline buffer: '" + command.inline.sub(start, it).decode() + "'");
}
}
} else {
} else
break;
}
tokenized.push_back(command.inline.sub(start, it));
}
return parse_command(tokenized);

View file

@ -1,3 +1,5 @@
# See the file "COPYING" in the main distribution directory for copyright.
protocol analyzer spicy::Redis over TCP:
parse originator with RESP::ClientMessages,
parse responder with RESP::ServerMessages;
@ -9,11 +11,11 @@ import Zeek_Redis;
export Redis::KnownCommand;
export Zeek_Redis::ZeekServerData;
on RESP::ClientData if ( Redis::is_set(self) ) -> event Redis::set_command($conn, $is_orig, Redis::make_set(self.command));
on RESP::ClientData if ( Redis::is_get(self) ) -> event Redis::get_command($conn, $is_orig, Redis::make_get(self.command));
on RESP::ClientData if ( Redis::is_auth(self) ) -> event Redis::auth_command($conn, $is_orig, Redis::make_auth(self.command));
on RESP::ClientData if ( Redis::is_set(self) ) -> event Redis::set_command($conn, Redis::make_set(self.command));
on RESP::ClientData if ( Redis::is_get(self) ) -> event Redis::get_command($conn, Redis::make_get(self.command).key);
on RESP::ClientData if ( Redis::is_auth(self) ) -> event Redis::auth_command($conn, Redis::make_auth(self.command));
# All client data is a command
on RESP::ClientData -> event Redis::command($conn, $is_orig, self.command);
on RESP::ClientData -> event Redis::client_command($conn, self.command);
# Server data needs an event to attach request/responses
on RESP::ServerData -> event Redis::server_data($conn, $is_orig, Zeek_Redis::make_server_data(self));
on RESP::ServerData -> event Redis::server_data($conn, Zeek_Redis::make_server_data(self));

View file

@ -1,3 +1,5 @@
# See the file "COPYING" in the main distribution directory for copyright.
module RESP;
import Redis;

View file

@ -1,3 +1,5 @@
# See the file "COPYING" in the main distribution directory for copyright.
#
# Zeek-specific Redis handling
module Zeek_Redis;

View file

@ -46,6 +46,7 @@
1 614
1 631
1 636
1 6379
1 6666
1 6667
1 6668
@ -66,8 +67,8 @@
1 992
1 993
1 995
75 and
74 or
75 port
47 tcp
76 and
75 or
76 port
48 tcp
28 udp

View file

@ -466,6 +466,9 @@ scripts/base/init-default.zeek
scripts/base/protocols/rdp/__load__.zeek
scripts/base/protocols/rdp/consts.zeek
scripts/base/protocols/rdp/main.zeek
scripts/base/protocols/redis/__load__.zeek
scripts/base/protocols/redis/spicy-decls.zeek
scripts/base/protocols/redis/main.zeek
scripts/base/protocols/rfb/__load__.zeek
scripts/base/protocols/rfb/main.zeek
scripts/base/protocols/sip/__load__.zeek

View file

@ -46,6 +46,7 @@ print_log_path
quic
radius
rdp
redis
reporter
rfb
signatures

View file

@ -593,6 +593,35 @@ connection {
* ts: time, log=T, optional=F
* uid: string, log=T, optional=F
}
* redis: record Redis::Info, log=F, optional=T
Redis::Info {
* cmd: record Redis::Command, log=T, optional=F
Redis::Command {
* command: string, log=T, optional=F
* key: string, log=T, optional=T
* known: enum Redis::KnownCommand, log=F, optional=T
* raw: vector of string, log=F, optional=F
* value: string, log=T, optional=T
}
* id: record conn_id, log=T, optional=F
conn_id { ... }
* response: record Redis::ServerData, log=T, optional=T
Redis::ServerData {
* data: string, log=T, optional=T
* err: bool, log=T, optional=F
}
* ts: time, log=T, optional=F
* uid: string, log=T, optional=F
}
* redis_state: record Redis::State, log=F, optional=T
Redis::State {
* current_request: count, log=F, optional=T
* current_response: count, log=F, optional=T
* no_response_ranges: vector of vector of count, log=F, optional=F
* pending: table[count] of record Redis::Info, log=F, optional=F
Redis::Info { ... }
* violation: bool, log=F, optional=T
}
* removal_hooks: set[func], log=F, optional=T
* resp: record endpoint, log=F, optional=F
endpoint { ... }

View file

@ -7,6 +7,6 @@
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p cmd.command cmd.key cmd.value response.err response.data
#types time string addr port addr port string string string bool string
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 53099 127.0.0.1 6379 AUTH - - F OK
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 53099 127.0.0.1 6379 PING - - F OK
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53099 127.0.0.1 6379 AUTH - - F OK
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53099 127.0.0.1 6379 PING - - F OK
#close XXXX-XX-XX-XX-XX-XX

View file

@ -1,153 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
SET: :1:factorial_1 1 expires in 60000 milliseconds
SET: :1:factorial_2 2 expires in 60000 milliseconds
SET: :1:factorial_3 6 expires in 60000 milliseconds
SET: :1:factorial_4 24 expires in 60000 milliseconds
SET: :1:factorial_5 120 expires in 60000 milliseconds
SET: :1:factorial_6 720 expires in 60000 milliseconds
SET: :1:factorial_7 5040 expires in 60000 milliseconds
SET: :1:factorial_8 40320 expires in 60000 milliseconds
SET: :1:factorial_9 362880 expires in 60000 milliseconds
SET: :1:factorial_10 3628800 expires in 60000 milliseconds
SET: :1:factorial_11 39916800 expires in 60000 milliseconds
SET: :1:factorial_12 479001600 expires in 60000 milliseconds
SET: :1:factorial_13 6227020800 expires in 60000 milliseconds
SET: :1:factorial_14 87178291200 expires in 60000 milliseconds
SET: :1:factorial_15 1307674368000 expires in 60000 milliseconds
SET: :1:factorial_16 20922789888000 expires in 60000 milliseconds
SET: :1:factorial_17 355687428096000 expires in 60000 milliseconds
SET: :1:factorial_18 6402373705728000 expires in 60000 milliseconds
SET: :1:factorial_19 121645100408832000 expires in 60000 milliseconds
SET: :1:factorial_20 2432902008176640000 expires in 60000 milliseconds
SET: :1:factorial_21 51090942171709440000 expires in 60000 milliseconds
SET: :1:factorial_22 1124000727777607680000 expires in 60000 milliseconds
SET: :1:factorial_23 25852016738884976640000 expires in 60000 milliseconds
SET: :1:factorial_24 620448401733239439360000 expires in 60000 milliseconds
SET: :1:factorial_25 15511210043330985984000000 expires in 60000 milliseconds
SET: :1:factorial_26 403291461126605635584000000 expires in 60000 milliseconds
SET: :1:factorial_27 10888869450418352160768000000 expires in 60000 milliseconds
SET: :1:factorial_28 304888344611713860501504000000 expires in 60000 milliseconds
SET: :1:factorial_29 8841761993739701954543616000000 expires in 60000 milliseconds
SET: :1:factorial_30 265252859812191058636308480000000 expires in 60000 milliseconds
SET: :1:factorial_31 8222838654177922817725562880000000 expires in 60000 milliseconds
SET: :1:factorial_32 263130836933693530167218012160000000 expires in 60000 milliseconds
SET: :1:factorial_33 8683317618811886495518194401280000000 expires in 60000 milliseconds
SET: :1:factorial_34 295232799039604140847618609643520000000 expires in 60000 milliseconds
SET: :1:factorial_35 10333147966386144929666651337523200000000 expires in 60000 milliseconds
SET: :1:factorial_36 371993326789901217467999448150835200000000 expires in 60000 milliseconds
SET: :1:factorial_37 13763753091226345046315979581580902400000000 expires in 60000 milliseconds
SET: :1:factorial_38 523022617466601111760007224100074291200000000 expires in 60000 milliseconds
SET: :1:factorial_39 20397882081197443358640281739902897356800000000 expires in 60000 milliseconds
SET: :1:factorial_40 815915283247897734345611269596115894272000000000 expires in 60000 milliseconds
SET: :1:factorial_41 33452526613163807108170062053440751665152000000000 expires in 60000 milliseconds
SET: :1:factorial_42 1405006117752879898543142606244511569936384000000000 expires in 60000 milliseconds
SET: :1:factorial_43 60415263063373835637355132068513997507264512000000000 expires in 60000 milliseconds
SET: :1:factorial_44 2658271574788448768043625811014615890319638528000000000 expires in 60000 milliseconds
SET: :1:factorial_45 119622220865480194561963161495657715064383733760000000000 expires in 60000 milliseconds
SET: :1:factorial_46 5502622159812088949850305428800254892961651752960000000000 expires in 60000 milliseconds
SET: :1:factorial_47 258623241511168180642964355153611979969197632389120000000000 expires in 60000 milliseconds
SET: :1:factorial_48 12413915592536072670862289047373375038521486354677760000000000 expires in 60000 milliseconds
SET: :1:factorial_49 608281864034267560872252163321295376887552831379210240000000000 expires in 60000 milliseconds
SET: :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 expires in 60000 milliseconds
SET: :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 expires in 60000 milliseconds
SET: :1:factorial_1 1 expires in 60000 milliseconds
SET: :1:factorial_2 2 expires in 60000 milliseconds
SET: :1:factorial_3 6 expires in 60000 milliseconds
SET: :1:factorial_4 24 expires in 60000 milliseconds
SET: :1:factorial_5 120 expires in 60000 milliseconds
SET: :1:factorial_6 720 expires in 60000 milliseconds
SET: :1:factorial_7 5040 expires in 60000 milliseconds
SET: :1:factorial_8 40320 expires in 60000 milliseconds
SET: :1:factorial_9 362880 expires in 60000 milliseconds
SET: :1:factorial_10 3628800 expires in 60000 milliseconds
SET: :1:factorial_11 39916800 expires in 60000 milliseconds
SET: :1:factorial_12 479001600 expires in 60000 milliseconds
SET: :1:factorial_13 6227020800 expires in 60000 milliseconds
SET: :1:factorial_14 87178291200 expires in 60000 milliseconds
SET: :1:factorial_15 1307674368000 expires in 60000 milliseconds
SET: :1:factorial_16 20922789888000 expires in 60000 milliseconds
SET: :1:factorial_17 355687428096000 expires in 60000 milliseconds
SET: :1:factorial_18 6402373705728000 expires in 60000 milliseconds
SET: :1:factorial_19 121645100408832000 expires in 60000 milliseconds
SET: :1:factorial_20 2432902008176640000 expires in 60000 milliseconds
SET: :1:factorial_21 51090942171709440000 expires in 60000 milliseconds
SET: :1:factorial_22 1124000727777607680000 expires in 60000 milliseconds
SET: :1:factorial_23 25852016738884976640000 expires in 60000 milliseconds
SET: :1:factorial_24 620448401733239439360000 expires in 60000 milliseconds
SET: :1:factorial_25 15511210043330985984000000 expires in 60000 milliseconds
SET: :1:factorial_26 403291461126605635584000000 expires in 60000 milliseconds
SET: :1:factorial_27 10888869450418352160768000000 expires in 60000 milliseconds
SET: :1:factorial_28 304888344611713860501504000000 expires in 60000 milliseconds
SET: :1:factorial_29 8841761993739701954543616000000 expires in 60000 milliseconds
SET: :1:factorial_30 265252859812191058636308480000000 expires in 60000 milliseconds
SET: :1:factorial_31 8222838654177922817725562880000000 expires in 60000 milliseconds
SET: :1:factorial_32 263130836933693530167218012160000000 expires in 60000 milliseconds
SET: :1:factorial_33 8683317618811886495518194401280000000 expires in 60000 milliseconds
SET: :1:factorial_34 295232799039604140847618609643520000000 expires in 60000 milliseconds
SET: :1:factorial_35 10333147966386144929666651337523200000000 expires in 60000 milliseconds
SET: :1:factorial_36 371993326789901217467999448150835200000000 expires in 60000 milliseconds
SET: :1:factorial_37 13763753091226345046315979581580902400000000 expires in 60000 milliseconds
SET: :1:factorial_38 523022617466601111760007224100074291200000000 expires in 60000 milliseconds
SET: :1:factorial_39 20397882081197443358640281739902897356800000000 expires in 60000 milliseconds
SET: :1:factorial_40 815915283247897734345611269596115894272000000000 expires in 60000 milliseconds
SET: :1:factorial_41 33452526613163807108170062053440751665152000000000 expires in 60000 milliseconds
SET: :1:factorial_42 1405006117752879898543142606244511569936384000000000 expires in 60000 milliseconds
SET: :1:factorial_43 60415263063373835637355132068513997507264512000000000 expires in 60000 milliseconds
SET: :1:factorial_44 2658271574788448768043625811014615890319638528000000000 expires in 60000 milliseconds
SET: :1:factorial_45 119622220865480194561963161495657715064383733760000000000 expires in 60000 milliseconds
SET: :1:factorial_46 5502622159812088949850305428800254892961651752960000000000 expires in 60000 milliseconds
SET: :1:factorial_47 258623241511168180642964355153611979969197632389120000000000 expires in 60000 milliseconds
SET: :1:factorial_48 12413915592536072670862289047373375038521486354677760000000000 expires in 60000 milliseconds
SET: :1:factorial_49 608281864034267560872252163321295376887552831379210240000000000 expires in 60000 milliseconds
SET: :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 expires in 60000 milliseconds
SET: :1:factorial_51 1551118753287382280224243016469303211063259720016986112000000000000 expires in 60000 milliseconds
SET: :1:factorial_52 80658175170943878571660636856403766975289505440883277824000000000000 expires in 60000 milliseconds
SET: :1:factorial_53 4274883284060025564298013753389399649690343788366813724672000000000000 expires in 60000 milliseconds
SET: :1:factorial_54 230843697339241380472092742683027581083278564571807941132288000000000000 expires in 60000 milliseconds
SET: :1:factorial_55 12696403353658275925965100847566516959580321051449436762275840000000000000 expires in 60000 milliseconds
SET: :1:factorial_56 710998587804863451854045647463724949736497978881168458687447040000000000000 expires in 60000 milliseconds
SET: :1:factorial_57 40526919504877216755680601905432322134980384796226602145184481280000000000000 expires in 60000 milliseconds
SET: :1:factorial_58 2350561331282878571829474910515074683828862318181142924420699914240000000000000 expires in 60000 milliseconds
SET: :1:factorial_59 138683118545689835737939019720389406345902876772687432540821294940160000000000000 expires in 60000 milliseconds
SET: :1:factorial_60 8320987112741390144276341183223364380754172606361245952449277696409600000000000000 expires in 60000 milliseconds
SET: :1:factorial_61 507580213877224798800856812176625227226004528988036003099405939480985600000000000000 expires in 60000 milliseconds
SET: :1:factorial_62 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000 expires in 60000 milliseconds
SET: :1:factorial_63 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000 expires in 60000 milliseconds
SET: :1:factorial_64 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000 expires in 60000 milliseconds
SET: :1:factorial_65 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000 expires in 60000 milliseconds
SET: :1:factorial_66 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000 expires in 60000 milliseconds
SET: :1:factorial_67 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000 expires in 60000 milliseconds
SET: :1:factorial_68 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000 expires in 60000 milliseconds
SET: :1:factorial_69 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000 expires in 60000 milliseconds
SET: :1:factorial_70 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000 expires in 60000 milliseconds
SET: :1:factorial_71 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000 expires in 60000 milliseconds
SET: :1:factorial_72 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000 expires in 60000 milliseconds
SET: :1:factorial_73 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000 expires in 60000 milliseconds
SET: :1:factorial_74 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000 expires in 60000 milliseconds
SET: :1:factorial_75 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_76 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_77 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_78 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_79 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_80 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_81 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_82 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_83 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_84 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_85 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_86 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_87 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_88 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_89 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_90 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_91 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_92 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_93 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_94 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_95 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_96 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_97 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_98 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_99 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 expires in 60000 milliseconds
SET: :1:factorial_100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 expires in 60000 milliseconds
Factorial of 100 is 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Found 152 SET commands

View file

@ -1,3 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
SET: HI 3
GET: [key=HI]
GET: HI

View file

@ -1,4 +1,4 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
SET: hi:2 2
SET: hi:3 sup
GET: [key=hi:3]
GET: hi:3

View file

@ -1,8 +1,11 @@
# @TEST-DOC: Test 2 commands that look like RESP, then server responses don't
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/almost-resp.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/almost-resp.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
#
# Really, the first 2 ARE Redis. The later ones should not be logged because we
# realized it's not Redis. The output from the server is:
# +OK\r\n+OK\r\nnot RESP\r\nStill not RESP\r\nNope\r\n
@load base/protocols/redis

View file

@ -1,10 +1,12 @@
# @TEST-DOC: Test Zeek with AUTH commands
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/auth.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/auth.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
event Redis::auth_command(c: connection, is_orig: bool,
command: Redis::AuthCommand)
@load base/protocols/redis
event Redis::auth_command(c: connection, command: Redis::AuthCommand)
{
print "AUTH";
if ( command?$username )

View file

@ -1,3 +0,0 @@
# @TEST-DOC: Check that the Redis analyzer is available.
#
# @TEST-EXEC: zeek -NN | grep -Eqi 'ANALYZER_SPICY_REDIS'

View file

@ -1,14 +1,17 @@
# @TEST-DOC: Test Zeek parsing a trace file made with bulk-created SET commands
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/bulk-loading.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/bulk-loading.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# The bulk-loading functionality just sends the serialized form from some ruby
# code directly to the server, but it's useful to see if that trace might come
# up with something different. See:
# https://redis.io/docs/latest/develop/use/patterns/bulk-loading/
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
print fmt("SET: %s %s", command$key, command$value);
}

View file

@ -1,4 +1,7 @@
# @TEST-DOC: Test CLIENT REPLY OFF, but turns on with new connection
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/reply-off-on-2conn.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/reply-off-on-2conn.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
@load base/protocols/redis

View file

@ -1,4 +1,7 @@
# @TEST-DOC: Test CLIENT REPLY OFF then ON again and a SKIP
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/reply-off-on.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/reply-off-on.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
@load base/protocols/redis

View file

@ -1,4 +1,7 @@
# @TEST-DOC: Test CLIENT REPLY OFF then ON again and a SKIP
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/client-skip-while-off.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/client-skip-while-off.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
@load base/protocols/redis

View file

@ -1,15 +1,37 @@
# @TEST-DOC: Test Redis traffic from a django app using Redis (in the cloud) as a cache
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/django-cloud.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/django-cloud.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
redef Redis::ports += { 10625/tcp, };
# This test has a bunch of factorial commands, try to test for the correct
# factorial without exploding the baseline
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
redef Redis::ports += {
10625/tcp,
};
global largest_num: count = 0;
global largest_result: string = "";
global num_sets: count = 0;
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
# Print the whole command because these have extra data that's worth capturing.
print fmt("SET: %s %s expires in %d milliseconds", command$key, command$value,
command$px);
local factorial_of = to_count(command$key[13:]);
if ( factorial_of > largest_num )
{
largest_num = factorial_of;
largest_result = command$value[:];
}
num_sets += 1;
}
event zeek_done()
{
print fmt("Factorial of %d is %s", largest_num, largest_result);
print fmt("Found %d SET commands", num_sets);
}

View file

@ -1,11 +1,13 @@
# @TEST-DOC: Test Redis traffic from a django app using Redis as a cache
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/django-cache.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/django-cache.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
# Print the whole command because these have extra data that's worth capturing.
print fmt("SET: %s %s expires in %d milliseconds", command$key, command$value,

View file

@ -1,8 +1,11 @@
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/excessive-pipelining.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/excessive-pipelining.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
# @TEST-EXEC: btest-diff weird.log
@load base/protocols/redis
# Make sure we get a weird if we go over the pipelining threshold (intentionally limited)
redef Redis::max_pending_requests = 5;

View file

@ -1,9 +1,12 @@
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/pipeline-quotes.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/pipeline-quotes.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
# TODO: Make it so weird.log exists again with `zeek::weird` for inline commands
# btest-diff weird.log
# Tests unserialized data where quotes should make one token
@load base/protocols/redis

View file

@ -1,20 +1,22 @@
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/pipeline-with-commands.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/pipeline-with-commands.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
# Sometimes commands aren't serialized, like when pipelining. This still works! So we
# should handle this. This particular example has a few commands, amongst them a SET and
# a GET.
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
print fmt("SET: %s %s", command$key, command$value);
}
event Redis::get_command(c: connection, is_orig: bool,
command: Redis::GetCommand)
event Redis::get_command(c: connection, key: string)
{
print fmt("GET: %s", command);
print fmt("GET: %s", key);
}

View file

@ -1,6 +1,7 @@
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/pipelining-example.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/pipelining-example.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
@ -10,3 +11,5 @@
# be able to skip it and get the responses, which are properly encoded.
#
# Also, you can send serialized data this way - that's kinda what the bulk test does.
@load base/protocols/redis

View file

@ -1,9 +1,12 @@
# @TEST-DOC: Test Zeek parsing pubsub commands
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/pubsub.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/pubsub.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
# Testing the example of pub sub in REDIS docs:
# https://redis.io/docs/latest/develop/interact/pubsub/
# These are just commands between two different clients, one PUBLISH and one SUBSCRIBE.
# These are just commands between two different clients, one PUBLISH and one SUBSCRIBE
@load base/protocols/redis

View file

@ -1,10 +1,12 @@
# @TEST-DOC: Test Zeek parsing SET commands
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/set.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/set.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
print fmt("Key: %s Value: %s", command$key, command$value);
}

View file

@ -1,14 +1,17 @@
# @TEST-DOC: Test that Redis does not parse if it starts with the server data
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/start-with-server.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/start-with-server.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
event Redis::command(c: connection, is_orig: bool, command: Redis::Command)
@load base/protocols/redis
event Redis::client_command(c: connection, command: Redis::Command)
{
print "BAD", command;
}
event Redis::server_data(c: connection, is_orig: bool, dat: Redis::ServerData)
event Redis::server_data(c: connection, dat: Redis::ServerData)
{
print "BAD", dat;
}

View file

@ -1,7 +1,10 @@
# @TEST-DOC: Test Zeek parsing pubsub commands
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/stream.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/stream.pcap %INPUT >output
# @TEST-EXEC: btest-diff redis.log
# Streams like with XRANGE return arrays of bulk strings. We shouldn't count the
# response as commands.
@load base/protocols/redis

View file

@ -1,6 +1,9 @@
# @TEST-DOC: Test Zeek with RESP over TLS so it doesn't get gibberish
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/tls.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/tls.pcap %INPUT >output
# @TEST-EXEC-FAIL: test -f redis.log
# The logs should probably be empty since it's all encrypted
@load base/protocols/redis

View file

@ -1,17 +1,18 @@
# @TEST-DOC: Test Zeek parsing a trace file through the Redis analyzer.
# @TEST-REQUIRES: have-spicy
#
# @TEST-EXEC: zeek -Cr $TRACES/redis/loop-redis.pcap base/protocols/redis %INPUT >output
# @TEST-EXEC: zeek -b -Cr $TRACES/redis/loop-redis.pcap %INPUT >output
# @TEST-EXEC: btest-diff output
# @TEST-EXEC: btest-diff redis.log
event Redis::set_command(c: connection, is_orig: bool,
command: Redis::SetCommand)
@load base/protocols/redis
event Redis::set_command(c: connection, command: Redis::SetCommand)
{
print fmt("SET: %s %s", command$key, command$value);
}
event Redis::get_command(c: connection, is_orig: bool,
command: Redis::GetCommand)
event Redis::get_command(c: connection, key: string)
{
print fmt("GET: %s", command);
print fmt("GET: %s", key);
}

View file

@ -1 +1 @@
d20f3027e30434d340f1d3b45b5f86c84e5c74e0
16aa8f4da279cff88c594855a35305b5ca7ecfea