mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
spicy-redis: Add some commands and touch up parsing
This commit is contained in:
parent
22bda56af3
commit
f0e9f46c7c
21 changed files with 200 additions and 114 deletions
|
@ -26,6 +26,11 @@ export {
|
|||
key: string &log;
|
||||
};
|
||||
|
||||
type AuthCommand: record {
|
||||
username: string &optional;
|
||||
password: string;
|
||||
};
|
||||
|
||||
type Command: record {
|
||||
## The raw command, exactly as parsed
|
||||
raw: vector of string;
|
||||
|
@ -71,15 +76,18 @@ export {
|
|||
|
||||
type State: record {
|
||||
## Pending requests.
|
||||
pending: table[count] of Info;
|
||||
pending: table[count] of Info;
|
||||
## Current request in the pending queue.
|
||||
current_request: count &default=0;
|
||||
current_request: count &default=0;
|
||||
## Current response in the pending queue.
|
||||
current_response: count &default=0;
|
||||
## 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;
|
||||
## We store if this analyzer had a violation to avoid logging if so.
|
||||
## This should not be super necessary, but worth a shot.
|
||||
violation: bool &default=F;
|
||||
};
|
||||
|
||||
# Redis specifically mentions 10k commands as a good pipelining threshold, so
|
||||
|
@ -102,6 +110,21 @@ event zeek_init() &priority=5
|
|||
Analyzer::register_for_ports(Analyzer::ANALYZER_SPICY_REDIS, ports);
|
||||
}
|
||||
|
||||
event analyzer_violation_info(atype: AllAnalyzers::Tag,
|
||||
info: AnalyzerViolationInfo)
|
||||
{
|
||||
if ( atype == Analyzer::ANALYZER_SPICY_REDIS )
|
||||
{
|
||||
if ( info?$c )
|
||||
{
|
||||
if ( info$c?$redis_state )
|
||||
{
|
||||
info$c$redis_state$violation = T;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function new_redis_session(c: connection): Info
|
||||
{
|
||||
return Info($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||
|
@ -116,11 +139,14 @@ function make_new_state(c: connection)
|
|||
|
||||
function set_state(c: connection, is_orig: bool)
|
||||
{
|
||||
if ( ! c?$redis_state ) make_new_state(c);
|
||||
if ( ! c?$redis_state )
|
||||
make_new_state(c);
|
||||
|
||||
local current: count;
|
||||
if ( is_orig ) current = c$redis_state$current_request;
|
||||
else current = c$redis_state$current_response;
|
||||
if ( is_orig )
|
||||
current = c$redis_state$current_request;
|
||||
else
|
||||
current = c$redis_state$current_response;
|
||||
|
||||
if ( current !in c$redis_state$pending )
|
||||
c$redis_state$pending[current] = new_redis_session(c);
|
||||
|
@ -131,28 +157,24 @@ function set_state(c: connection, is_orig: bool)
|
|||
# Returns true if the last interval exists and is closed
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if ( ! c?$redis_state ) make_new_state(c);
|
||||
if ( ! c?$redis_state )
|
||||
make_new_state(c);
|
||||
|
||||
if ( max_pending_requests > 0 && |c$redis_state$pending| > max_pending_requests )
|
||||
if ( max_pending_requests > 0
|
||||
&& |c$redis_state$pending| > max_pending_requests )
|
||||
{
|
||||
Reporter::conn_weird("Redis_excessive_pipelining", c);
|
||||
|
||||
# Just spit out what we have
|
||||
while ( c$redis_state$current_response < c$redis_state$current_request )
|
||||
{
|
||||
local cr = c$redis_state$current_response;
|
||||
if ( cr in c$redis_state$pending )
|
||||
{
|
||||
Log::write(Redis::LOG, c$redis_state$pending[cr]);
|
||||
delete c$redis_state$pending[cr];
|
||||
}
|
||||
++c$redis_state$current_response;
|
||||
}
|
||||
# Delete the current state and restart later. We'll be in a weird state, but
|
||||
# really we want to abort. I don't quite get how to register this as a
|
||||
# violation. :)
|
||||
delete c$redis_state;
|
||||
return;
|
||||
}
|
||||
|
||||
++c$redis_state$current_request;
|
||||
|
@ -164,9 +186,10 @@ event Redis::command(c: connection, is_orig: bool, command: Command)
|
|||
if ( to_lower(command$raw[2]) == "on" )
|
||||
{
|
||||
# If the last range is open, close it here. Otherwise, noop
|
||||
if ( |c$redis_state$no_response_ranges| > 0 )
|
||||
if ( |c$redis_state$no_response_ranges| > 0 )
|
||||
{
|
||||
local range = c$redis_state$no_response_ranges[|c$redis_state$no_response_ranges| - 1];
|
||||
local range = c$redis_state$no_response_ranges[|c$redis_state$no_response_ranges|
|
||||
- 1];
|
||||
if ( |range| == 1 )
|
||||
{
|
||||
range += c$redis_state$current_request;
|
||||
|
@ -176,16 +199,17 @@ event Redis::command(c: connection, is_orig: bool, command: Command)
|
|||
if ( to_lower(command$raw[2]) == "off" )
|
||||
{
|
||||
# Only add a new interval if the last one is closed
|
||||
if ( is_last_interval_closed(c) )
|
||||
if ( is_last_interval_closed(c) )
|
||||
{
|
||||
c$redis_state$no_response_ranges += vector(c$redis_state$current_request);
|
||||
}
|
||||
}
|
||||
if ( to_lower(command$raw[2]) == "skip" )
|
||||
{
|
||||
if ( is_last_interval_closed(c) )
|
||||
if ( is_last_interval_closed(c) )
|
||||
# It skips this one and the next one
|
||||
c$redis_state$no_response_ranges += vector(c$redis_state$current_request, c$redis_state$current_request + 2);
|
||||
c$redis_state$no_response_ranges += vector(c$redis_state$current_request,
|
||||
c$redis_state$current_request + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,10 +226,10 @@ function response_num(c: connection): count
|
|||
for ( i in c$redis_state$no_response_ranges )
|
||||
{
|
||||
local range = c$redis_state$no_response_ranges[i];
|
||||
assert |range| >= 1;
|
||||
assert | range | >= 1;
|
||||
if ( |range| == 1 && resp_num > range[0] )
|
||||
{} # TODO: This is necessary if not using pipelining
|
||||
if ( |range| == 2 && resp_num >= range[0] && resp_num < range[1] )
|
||||
{ } # TODO: This is necessary if not using pipelining
|
||||
if ( |range| == 2 && resp_num >= range[0] && resp_num < range[1] )
|
||||
return range[1];
|
||||
}
|
||||
|
||||
|
@ -215,7 +239,8 @@ function response_num(c: connection): count
|
|||
|
||||
event Redis::server_data(c: connection, is_orig: bool, data: ServerData)
|
||||
{
|
||||
if ( ! c?$redis_state ) make_new_state(c);
|
||||
if ( ! c?$redis_state )
|
||||
make_new_state(c);
|
||||
|
||||
local previous_response_num = c$redis_state$current_response;
|
||||
c$redis_state$current_response = response_num(c);
|
||||
|
@ -232,27 +257,37 @@ event Redis::server_data(c: connection, is_orig: bool, data: ServerData)
|
|||
next;
|
||||
}
|
||||
|
||||
if ( previous_response_num in c$redis_state$pending )
|
||||
if ( previous_response_num in c$redis_state$pending &&
|
||||
c$redis_state$pending[previous_response_num]?$cmd )
|
||||
{
|
||||
Log::write(Redis::LOG, c$redis_state$pending[previous_response_num]);
|
||||
delete c$redis_state$pending[previous_response_num];
|
||||
}
|
||||
previous_response_num += 1;
|
||||
}
|
||||
# Log this one
|
||||
Log::write(Redis::LOG, c$redis);
|
||||
delete c$redis_state$pending[c$redis_state$current_response];
|
||||
# Log this one if we have the request and response
|
||||
if ( c$redis?$cmd )
|
||||
{
|
||||
Log::write(Redis::LOG, c$redis);
|
||||
delete c$redis_state$pending[c$redis_state$current_response];
|
||||
}
|
||||
}
|
||||
|
||||
hook finalize_redis(c: connection)
|
||||
{
|
||||
if ( c$redis_state$violation )
|
||||
{
|
||||
# If there's a violation, make sure everything gets deleted
|
||||
delete c$redis_state;
|
||||
}
|
||||
# Flush all pending but incomplete request/response pairs.
|
||||
if ( c?$redis_state )
|
||||
if ( c?$redis_state && c$redis_state$current_response != 0 )
|
||||
{
|
||||
for ( r, info in c$redis_state$pending )
|
||||
{
|
||||
# We don't use pending elements at index 0.
|
||||
if ( r == 0 ) next;
|
||||
if ( r == 0 )
|
||||
next;
|
||||
Log::write(Redis::LOG, info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import RESP;
|
|||
|
||||
public type KnownCommand = enum {
|
||||
APPEND,
|
||||
AUTH,
|
||||
BITCOUNT,
|
||||
BITFIELD,
|
||||
BITFIELD_RO,
|
||||
|
@ -234,6 +235,7 @@ function command_from(cmd_bytes: bytes): optional<KnownCommand> {
|
|||
switch (cmd_bytes.lower()) {
|
||||
case b"set": cmd = KnownCommand::SET;
|
||||
case b"append": cmd = KnownCommand::APPEND;
|
||||
case b"auth": cmd = KnownCommand::AUTH;
|
||||
case b"bitcount": cmd = KnownCommand::BITCOUNT;
|
||||
case b"bitfield": cmd = KnownCommand::BITFIELD;
|
||||
case b"bitfield_ro": cmd = KnownCommand::BITFIELD_RO;
|
||||
|
@ -352,3 +354,21 @@ public function make_get(command: Command): Get {
|
|||
public function is_get(data: RESP::ClientData): bool {
|
||||
return data.command.known && *(data.command.known) == KnownCommand::GET && |data.command.raw| >= 2;
|
||||
}
|
||||
|
||||
type Auth = struct {
|
||||
username: optional<bytes>;
|
||||
password: bytes;
|
||||
};
|
||||
|
||||
public function make_auth(command: Command): Auth {
|
||||
assert |command.raw| >= 2 : "AUTH must have arguments";
|
||||
if (|command.raw| == 2) {
|
||||
return [$username = Null, $password = command.raw[1]];
|
||||
}
|
||||
|
||||
return [$username = command.raw[1], $password = command.raw[2]];
|
||||
}
|
||||
|
||||
public function is_auth(data: RESP::ClientData): bool {
|
||||
return data.command.known && *(data.command.known) == KnownCommand::AUTH && |data.command.raw| >= 2;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ 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));
|
||||
|
||||
# All client data is a command
|
||||
on RESP::ClientData -> event Redis::command($conn, $is_orig, self.command);
|
||||
|
|
|
@ -9,7 +9,7 @@ import spicy;
|
|||
const MAX_SIZE = 1024 * 1024;
|
||||
|
||||
public type ClientMessages = unit {
|
||||
: (ClientData &synchronize)[];
|
||||
: ClientData[];
|
||||
};
|
||||
|
||||
public type ServerMessages = unit {
|
||||
|
@ -17,21 +17,22 @@ public type ServerMessages = unit {
|
|||
};
|
||||
|
||||
public type ClientData = unit {
|
||||
%synchronize-after = b"\x0d\x0a";
|
||||
on %init() { self.start = self.input(); }
|
||||
|
||||
# Clients can only be an array or inline
|
||||
ty: uint8 &convert=DataType($$);
|
||||
ty: uint8 &convert=DataType($$) {
|
||||
if (self.ty != DataType::ARRAY) {
|
||||
# This is inline, so we need to reparse `ty`
|
||||
self.set_input(self.start);
|
||||
}
|
||||
}
|
||||
if (self.ty == DataType::ARRAY) {
|
||||
multibulk: Array;
|
||||
} else {
|
||||
# HACK: If the type isn'tan array, this is just some random unserialized
|
||||
# string until \r\n - do this by prepending the type to the remaining bytes.
|
||||
# Formally in Redis code, that's an "inline command."
|
||||
#
|
||||
# As an extra point, this is handled in redis in `processInlineBuffer`,
|
||||
# which has a hardcoded limit of 1024*64. That seems too big. We'll do 1024.
|
||||
inline: RedisBytes &convert=(pack(cast<uint8>(self.ty), spicy::ByteOrder::Network) + $$) &max-size=1024;
|
||||
inline: RedisBytes &max-size=1024;
|
||||
};
|
||||
|
||||
var start: iterator<stream>;
|
||||
var command: Redis::Command;
|
||||
|
||||
on %done {
|
||||
|
@ -152,10 +153,10 @@ type Set = unit {
|
|||
elements: Data[self.num_elements];
|
||||
};
|
||||
|
||||
on Data::%done {
|
||||
on ServerData::%done {
|
||||
spicy::accept_input();
|
||||
}
|
||||
|
||||
on Data::%error {
|
||||
spicy::decline_input("error while parsing RESP data");
|
||||
on ServerData::%error {
|
||||
spicy::decline_input("error while parsing RESP server data");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
### 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 redis
|
||||
#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 CtPZjS20MLrsMUOJi2 127.0.0.1 53099 127.0.0.1 6379 AUTH - - F OK
|
||||
XXXXXXXXXX.XXXXXX CtPZjS20MLrsMUOJi2 127.0.0.1 53099 127.0.0.1 6379 PING - - F OK
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,10 @@
|
|||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||
AUTH
|
||||
username: notauser
|
||||
password: notapassword
|
||||
AUTH
|
||||
username: default
|
||||
password: defaultpasswordinvalid
|
||||
AUTH
|
||||
username: noone
|
||||
password: password
|
|
@ -7,17 +7,10 @@
|
|||
#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 ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - - -
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 PING - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
|
@ -26,8 +19,4 @@ XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
|||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 57156 ::1 6379 - - - F PONG
|
||||
#close XXXX-XX-XX-XX-XX-XX
|
||||
|
|
BIN
testing/btest/Traces/redis/almost-resp.trace
Normal file
BIN
testing/btest/Traces/redis/almost-resp.trace
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/auth.trace
Normal file
BIN
testing/btest/Traces/redis/auth.trace
Normal file
Binary file not shown.
|
@ -0,0 +1,8 @@
|
|||
# @TEST-DOC: Test 2 commands that look like RESP, then server responses don't
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/redis/almost-resp.trace base/protocols/redis %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
|
16
testing/btest/scripts/base/protocols/redis/auth.zeek
Normal file
16
testing/btest/scripts/base/protocols/redis/auth.zeek
Normal file
|
@ -0,0 +1,16 @@
|
|||
# @TEST-DOC: Test Zeek with AUTH commands
|
||||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/redis/auth.trace base/protocols/redis %INPUT >output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
event Redis::auth_command(c: connection, is_orig: bool,
|
||||
command: Redis::AuthCommand)
|
||||
{
|
||||
print "AUTH";
|
||||
if ( command?$username )
|
||||
print fmt("username: %s", command$username);
|
||||
else
|
||||
print "username: default";
|
||||
|
||||
print fmt("password: %s", command$password);
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
# 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)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/redis/reply-off-on-2conn.trace base/protocols/redis %INPUT >output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/redis/reply-off-on.trace base/protocols/redis %INPUT >output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
#
|
||||
# @TEST-EXEC: zeek -Cr $TRACES/redis/client-skip-while-off.trace base/protocols/redis %INPUT >output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
# @TEST-EXEC: btest-diff output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
redef Redis::ports += {
|
||||
10625/tcp,
|
||||
};
|
||||
redef Redis::ports += { 10625/tcp, };
|
||||
|
||||
event Redis::set_command(c: connection, is_orig: bool, 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);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
# @TEST-EXEC: btest-diff output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
event Redis::set_command(c: connection, is_orig: bool, 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);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
# 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)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
|
||||
event Redis::get_command(c: connection, is_orig: bool, command: Redis::GetCommand)
|
||||
{
|
||||
print fmt("GET: %s", command);
|
||||
}
|
||||
event Redis::get_command(c: connection, is_orig: bool,
|
||||
command: Redis::GetCommand)
|
||||
{
|
||||
print fmt("GET: %s", command);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
# @TEST-EXEC: zeek -Cr $TRACES/redis/set.trace base/protocols/redis %INPUT >output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
event Redis::set_command(c: connection, is_orig: bool, command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("Key: %s Value: %s", command$key, command$value);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("Key: %s Value: %s", command$key, command$value);
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# @TEST-DOC: Test parsing behavior of RESP.
|
||||
#
|
||||
# @TEST-EXEC: spicyc ${DIST}/analyzer/resp.spicy ${DIST}/analyzer/redis.spicy -j -d -o redis.hlto
|
||||
#
|
||||
# TODO: A lot of tests are possible from the docs and having them would be nice.
|
||||
# But, a lot of characters ($, -, etc.) cause problems with TEST_EXEC. ugh.
|
||||
# @TEST-EXEC: printf "+OK\x0d\x0a" | spicy-dump -p RESP::Data redis.hlto >>output 2>&1
|
||||
# @TEST-EXEC: printf ":1000\x0d\x0a" | spicy-dump -p RESP::Data redis.hlto >>output 2>&1
|
||||
# @TEST-EXEC: printf ":-1000\x0d\x0a" | spicy-dump -p RESP::Data redis.hlto >>output 2>&1
|
||||
# @TEST-EXEC: printf ":+1000\x0d\x0a" | spicy-dump -p RESP::Data redis.hlto >>output 2>&1
|
||||
# @TEST-EXEC: TEST_DIFF_CANONIFIER= btest-diff output
|
|
@ -4,12 +4,14 @@
|
|||
# @TEST-EXEC: btest-diff output
|
||||
# @TEST-EXEC: btest-diff redis.log
|
||||
|
||||
event Redis::set_command(c: connection, is_orig: bool, command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
event Redis::set_command(c: connection, is_orig: bool,
|
||||
command: Redis::SetCommand)
|
||||
{
|
||||
print fmt("SET: %s %s", command$key, command$value);
|
||||
}
|
||||
|
||||
event Redis::get_command(c: connection, is_orig: bool, command: Redis::GetCommand)
|
||||
{
|
||||
print fmt("GET: %s", command);
|
||||
}
|
||||
event Redis::get_command(c: connection, is_orig: bool,
|
||||
command: Redis::GetCommand)
|
||||
{
|
||||
print fmt("GET: %s", command);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue