mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/etyp/redis-analyzer'
* origin/topic/etyp/redis-analyzer: spicy-redis: Add NEWS entry spicy-redis: Separate error replies from success spicy-redis: Cleanup scripts and tests spciy-redis: Bring Redis analyzer into Zeek proper spicy-redis: Abort parsing if server data comes first spicy-redis: Add recursion depth to server data spicy-redis: Make client data only accept bulk strings spicy-redis: Add dpd signature and clean pcaps spicy-redis: Add some commands and touch up parsing spicy-redis: Add some script logic for logging spicy-redis: Separate client/server spicy-redis: Touchup logging and Spicy issues spicy-redis: Add synchronization and pipeline support spicy-redis: Begin Spicy Redis analyzer
This commit is contained in:
commit
9f2fb47f48
71 changed files with 2747 additions and 6 deletions
|
@ -30,6 +30,8 @@ extend-ignore-re = [
|
||||||
"ot->Yield\\(\\)->InternalType\\(\\)",
|
"ot->Yield\\(\\)->InternalType\\(\\)",
|
||||||
"switch \\( ot \\)",
|
"switch \\( ot \\)",
|
||||||
"\\(ZAMOpType ot\\)",
|
"\\(ZAMOpType ot\\)",
|
||||||
|
"exat", # Redis expire at
|
||||||
|
"EXAT",
|
||||||
|
|
||||||
# News stuff
|
# News stuff
|
||||||
"SupressWeirds.*deprecated",
|
"SupressWeirds.*deprecated",
|
||||||
|
|
41
CHANGES
41
CHANGES
|
@ -1,3 +1,44 @@
|
||||||
|
8.0.0-dev.227 | 2025-05-27 10:18:49 -0400
|
||||||
|
|
||||||
|
* spicy-redis: Separate error replies from success (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Cleanup scripts and tests (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
- Recomputes checksums for pcaps to keep clean
|
||||||
|
- Removes some tests that had big pcaps or weren't necessary
|
||||||
|
- Cleans up scripting names and minor points
|
||||||
|
- Comments out Spicy code that causes a build failure now with a TODO to
|
||||||
|
uncomment it
|
||||||
|
|
||||||
|
* spciy-redis: Bring Redis analyzer into Zeek proper (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Abort parsing if server data comes first (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
Redis seems to only want client data first to request server data. The
|
||||||
|
DPD signature seems to pick up on some cases where server data comes
|
||||||
|
first, but is otherwise "valid" RESP. See if this helps lower FP rates.
|
||||||
|
|
||||||
|
* spicy-redis: Add recursion depth to server data (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Make client data only accept bulk strings (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Add dpd signature and clean pcaps (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Add some commands and touch up parsing (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Add some script logic for logging (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Separate client/server (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
This makes the parser more official and splits the client/server out
|
||||||
|
from each other.
|
||||||
|
|
||||||
|
* spicy-redis: Touchup logging and Spicy issues (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Add synchronization and pipeline support (Evan Typanski, Corelight)
|
||||||
|
|
||||||
|
* spicy-redis: Begin Spicy Redis analyzer (Evan Typanski, Corelight)
|
||||||
|
|
||||||
8.0.0-dev.209 | 2025-05-26 16:08:44 +0200
|
8.0.0-dev.209 | 2025-05-26 16:08:44 +0200
|
||||||
|
|
||||||
* btest: Add test for Cluster::hello zero-timestamp (Arne Welzel, Corelight)
|
* btest: Add test for Cluster::hello zero-timestamp (Arne Welzel, Corelight)
|
||||||
|
|
11
NEWS
11
NEWS
|
@ -42,6 +42,17 @@ New Functionality
|
||||||
const std::string& topic,
|
const std::string& topic,
|
||||||
zeek::cluster::detail::Event& event);
|
zeek::cluster::detail::Event& event);
|
||||||
|
|
||||||
|
- Zeek now includes the Redis protocol analyzer from the evantypanski/spicy-redis
|
||||||
|
project (https://github.com/evantypanski/spicy-redis). This analyzer is enabled
|
||||||
|
by default. This analyzer logs Redis commands and their associated replies in
|
||||||
|
``redis.log``.
|
||||||
|
|
||||||
|
To disable the analyzer in case of issues, use the following snippet:
|
||||||
|
|
||||||
|
redef Analyzer::disabled_analyzers += {
|
||||||
|
Analyzer::ANALYZER_REDIS,
|
||||||
|
};
|
||||||
|
|
||||||
Changed Functionality
|
Changed Functionality
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
8.0.0-dev.209
|
8.0.0-dev.227
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
@load base/protocols/quic
|
@load base/protocols/quic
|
||||||
@load base/protocols/radius
|
@load base/protocols/radius
|
||||||
@load base/protocols/rdp
|
@load base/protocols/rdp
|
||||||
|
@load base/protocols/redis
|
||||||
@load base/protocols/rfb
|
@load base/protocols/rfb
|
||||||
@load base/protocols/sip
|
@load base/protocols/sip
|
||||||
@load base/protocols/snmp
|
@load base/protocols/snmp
|
||||||
|
|
6
scripts/base/protocols/redis/__load__.zeek
Normal file
6
scripts/base/protocols/redis/__load__.zeek
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
@if ( have_spicy_analyzers() )
|
||||||
|
@load ./spicy-events
|
||||||
|
@load ./main
|
||||||
|
|
||||||
|
@load-sigs ./dpd.sig
|
||||||
|
@endif
|
14
scripts/base/protocols/redis/dpd.sig
Normal file
14
scripts/base/protocols/redis/dpd.sig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
signature resp-client {
|
||||||
|
ip-proto == tcp
|
||||||
|
payload /^.*\r\n/
|
||||||
|
tcp-state originator
|
||||||
|
requires-reverse-signature resp-serialized-server
|
||||||
|
enable "Redis"
|
||||||
|
}
|
||||||
|
|
||||||
|
signature resp-serialized-server {
|
||||||
|
ip-proto == tcp
|
||||||
|
payload /^([-+_,].*\r\n|[:$*#(!=%`~>][+-]?[0-9]+(\.[0-9]*)?\r\n)/
|
||||||
|
tcp-state responder
|
||||||
|
enable "Redis"
|
||||||
|
}
|
278
scripts/base/protocols/redis/main.zeek
Normal file
278
scripts/base/protocols/redis/main.zeek
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
@load base/protocols/conn/removal-hooks
|
||||||
|
@load base/frameworks/signatures
|
||||||
|
|
||||||
|
@load ./spicy-events
|
||||||
|
|
||||||
|
module Redis;
|
||||||
|
|
||||||
|
export {
|
||||||
|
## Log stream identifier.
|
||||||
|
redef enum Log::ID += { LOG };
|
||||||
|
|
||||||
|
## The ports to register Redis for.
|
||||||
|
const ports = {6379/tcp} &redef;
|
||||||
|
|
||||||
|
## Record type containing the column fields of the Redis 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;
|
||||||
|
## The Redis command.
|
||||||
|
cmd: Command &log;
|
||||||
|
## If the command was successful. Only set if the server responded.
|
||||||
|
success: bool &log &optional;
|
||||||
|
## The reply for the command.
|
||||||
|
reply: ReplyData &log &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
## A default logging policy hook for the stream.
|
||||||
|
global log_policy: Log::PolicyHook;
|
||||||
|
|
||||||
|
global finalize_redis: Conn::RemovalHook;
|
||||||
|
|
||||||
|
## Which numbered commands should not expect a reply due to CLIENT REPLY commands.
|
||||||
|
## These commands may simply skip one, or they may turn off replies then later
|
||||||
|
## reenable them. Thus, the end of the interval is optional.
|
||||||
|
type NoReplyRange: record {
|
||||||
|
begin: count;
|
||||||
|
end: count &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
type State: record {
|
||||||
|
## Pending commands.
|
||||||
|
pending: table[count] of Info;
|
||||||
|
## Current command in the pending queue.
|
||||||
|
current_command: count &default=0;
|
||||||
|
## Current reply in the pending queue.
|
||||||
|
current_reply: count &default=0;
|
||||||
|
## Ranges where we do not expect a reply due to CLIENT REPLY commands.
|
||||||
|
## Each range is one or two elements, one meaning it's unbounded, two meaning
|
||||||
|
## it begins at one and ends at the second.
|
||||||
|
no_reply_ranges: vector of NoReplyRange;
|
||||||
|
## 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
|
||||||
|
# we'll piggyback on that.
|
||||||
|
option max_pending_commands = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
redef record connection += {
|
||||||
|
redis: Info &optional;
|
||||||
|
redis_state: State &optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
redef likely_server_ports += {ports};
|
||||||
|
|
||||||
|
event zeek_init() &priority=5
|
||||||
|
{
|
||||||
|
Log::create_stream(Redis::LOG, [$columns=Info, $path="redis",
|
||||||
|
$policy=log_policy]);
|
||||||
|
|
||||||
|
Analyzer::register_for_ports(Analyzer::ANALYZER_REDIS, ports);
|
||||||
|
}
|
||||||
|
|
||||||
|
event analyzer_violation_info(atype: AllAnalyzers::Tag,
|
||||||
|
info: AnalyzerViolationInfo)
|
||||||
|
{
|
||||||
|
if ( atype == Analyzer::ANALYZER_REDIS && info?$c && info$c?$redis_state )
|
||||||
|
{
|
||||||
|
info$c$redis_state$violation = T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function new_redis_info(c: connection): Info
|
||||||
|
{
|
||||||
|
return Info($ts=network_time(), $uid=c$uid, $id=c$id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_new_state(c: connection)
|
||||||
|
{
|
||||||
|
local s: State;
|
||||||
|
c$redis_state = s;
|
||||||
|
Conn::register_removal_hook(c, finalize_redis);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_state(c: connection, is_orig: bool)
|
||||||
|
{
|
||||||
|
if ( ! c?$redis_state )
|
||||||
|
make_new_state(c);
|
||||||
|
|
||||||
|
local current: count;
|
||||||
|
if ( is_orig )
|
||||||
|
current = c$redis_state$current_command;
|
||||||
|
else
|
||||||
|
current = c$redis_state$current_reply;
|
||||||
|
|
||||||
|
if ( current !in c$redis_state$pending )
|
||||||
|
c$redis_state$pending[current] = new_redis_info(c);
|
||||||
|
|
||||||
|
c$redis = c$redis_state$pending[current];
|
||||||
|
}
|
||||||
|
|
||||||
|
## Returns whether the last "no reply" interval is not still open.
|
||||||
|
function is_last_interval_closed(c: connection): bool
|
||||||
|
{
|
||||||
|
return |c$redis_state$no_reply_ranges| == 0 ||
|
||||||
|
c$redis_state$no_reply_ranges[-1]?$end;
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::command(c: connection, cmd: Command)
|
||||||
|
{
|
||||||
|
if ( ! c?$redis_state )
|
||||||
|
make_new_state(c);
|
||||||
|
|
||||||
|
if ( max_pending_commands > 0
|
||||||
|
&& |c$redis_state$pending| > max_pending_commands )
|
||||||
|
{
|
||||||
|
Reporter::conn_weird("Redis_excessive_pipelining", c);
|
||||||
|
# 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_command;
|
||||||
|
# CLIENT commands can skip a number of replies and may be used with
|
||||||
|
# pipelining. We need special logic in order to track the command/reply
|
||||||
|
# pairs.
|
||||||
|
if ( cmd?$known && cmd$known == KnownCommand_CLIENT )
|
||||||
|
{
|
||||||
|
# All 3 CLIENT commands we care about have 3 elements
|
||||||
|
if ( |cmd$raw| == 3 )
|
||||||
|
{
|
||||||
|
if ( to_lower(cmd$raw[2]) == "on" )
|
||||||
|
{
|
||||||
|
# If the last range is open, close it here. Otherwise, noop
|
||||||
|
if ( |c$redis_state$no_reply_ranges| > 0 )
|
||||||
|
{
|
||||||
|
local range = c$redis_state$no_reply_ranges[-1];
|
||||||
|
if ( ! range?$end )
|
||||||
|
{
|
||||||
|
range$end = c$redis_state$current_command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( to_lower(cmd$raw[2]) == "off" )
|
||||||
|
{
|
||||||
|
# Only add a new interval if the last one is closed
|
||||||
|
if ( is_last_interval_closed(c) )
|
||||||
|
{
|
||||||
|
c$redis_state$no_reply_ranges += NoReplyRange(
|
||||||
|
$begin=c$redis_state$current_command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( to_lower(cmd$raw[2]) == "skip" )
|
||||||
|
{
|
||||||
|
if ( is_last_interval_closed(c) )
|
||||||
|
# It skips this one and the next one
|
||||||
|
c$redis_state$no_reply_ranges += NoReplyRange(
|
||||||
|
$begin=c$redis_state$current_command, $end=c$redis_state$current_command + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_state(c, T);
|
||||||
|
|
||||||
|
c$redis$cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
## Gets the next reply number based on a connection. This is necessary since
|
||||||
|
## some replies may have been skipped.
|
||||||
|
function reply_num(c: connection): count
|
||||||
|
{
|
||||||
|
local resp_num = c$redis_state$current_reply + 1;
|
||||||
|
for ( i in c$redis_state$no_reply_ranges )
|
||||||
|
{
|
||||||
|
local range = c$redis_state$no_reply_ranges[i];
|
||||||
|
if ( ! range?$end && resp_num > range$begin )
|
||||||
|
{ } # TODO: This is necessary if not using pipelining
|
||||||
|
if ( range?$end && resp_num >= range$begin && resp_num < range$end )
|
||||||
|
return range$end;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default: no disable/enable shenanigans
|
||||||
|
return resp_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logs up to and including the last seen command from the last reply
|
||||||
|
function log_from(c: connection, previous_reply_num: count)
|
||||||
|
{
|
||||||
|
# Log each of the pending replies to this point - we will not go
|
||||||
|
# back.
|
||||||
|
while ( previous_reply_num < c$redis_state$current_reply )
|
||||||
|
{
|
||||||
|
if ( previous_reply_num == 0 )
|
||||||
|
{
|
||||||
|
++previous_reply_num;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( previous_reply_num in c$redis_state$pending &&
|
||||||
|
c$redis_state$pending[previous_reply_num]?$cmd )
|
||||||
|
{
|
||||||
|
Log::write(Redis::LOG, c$redis_state$pending[previous_reply_num]);
|
||||||
|
delete c$redis_state$pending[previous_reply_num];
|
||||||
|
}
|
||||||
|
previous_reply_num += 1;
|
||||||
|
}
|
||||||
|
# Log this one if we have the command and reply
|
||||||
|
if ( c$redis?$cmd )
|
||||||
|
{
|
||||||
|
Log::write(Redis::LOG, c$redis);
|
||||||
|
delete c$redis_state$pending[c$redis_state$current_reply];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::reply(c: connection, data: ReplyData)
|
||||||
|
{
|
||||||
|
if ( ! c?$redis_state )
|
||||||
|
make_new_state(c);
|
||||||
|
|
||||||
|
local previous_reply_num = c$redis_state$current_reply;
|
||||||
|
c$redis_state$current_reply = reply_num(c);
|
||||||
|
set_state(c, F);
|
||||||
|
|
||||||
|
c$redis$reply = data;
|
||||||
|
c$redis$success = T;
|
||||||
|
log_from(c, previous_reply_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::error(c: connection, data: ReplyData)
|
||||||
|
{
|
||||||
|
if ( ! c?$redis_state )
|
||||||
|
make_new_state(c);
|
||||||
|
|
||||||
|
local previous_reply_num = c$redis_state$current_reply;
|
||||||
|
c$redis_state$current_reply = reply_num(c);
|
||||||
|
set_state(c, F);
|
||||||
|
|
||||||
|
c$redis$reply = data;
|
||||||
|
c$redis$success = F;
|
||||||
|
log_from(c, previous_reply_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
hook finalize_redis(c: connection)
|
||||||
|
{
|
||||||
|
if ( c$redis_state$violation )
|
||||||
|
{
|
||||||
|
# If there's a violation, don't log the remaining parts, just return.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
# Flush all pending but incomplete command/reply pairs.
|
||||||
|
if ( c?$redis_state && c$redis_state$current_reply != 0 )
|
||||||
|
{
|
||||||
|
for ( r, info in c$redis_state$pending )
|
||||||
|
{
|
||||||
|
# We don't use pending elements at index 0.
|
||||||
|
if ( r == 0 )
|
||||||
|
next;
|
||||||
|
Log::write(Redis::LOG, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
scripts/base/protocols/redis/spicy-events.zeek
Normal file
103
scripts/base/protocols/redis/spicy-events.zeek
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
##! 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.
|
||||||
|
name: 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
## A generic Redis reply from the client.
|
||||||
|
type ReplyData: record {
|
||||||
|
value: 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.
|
||||||
|
##
|
||||||
|
## cmd: The command sent to the server.
|
||||||
|
global command: event(c: connection, cmd: Command);
|
||||||
|
|
||||||
|
## Generated for every successful response sent by the Redis server to the
|
||||||
|
## client.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## data: The server data sent to the client.
|
||||||
|
global reply: event(c: connection, data: ReplyData);
|
||||||
|
|
||||||
|
## Generated for every error response sent by the Redis server to the
|
||||||
|
## client.
|
||||||
|
##
|
||||||
|
## c: The connection.
|
||||||
|
##
|
||||||
|
## data: The server data sent to the client.
|
||||||
|
global error: event(c: connection, data: ReplyData);
|
|
@ -32,6 +32,7 @@ add_subdirectory(postgresql)
|
||||||
add_subdirectory(quic)
|
add_subdirectory(quic)
|
||||||
add_subdirectory(radius)
|
add_subdirectory(radius)
|
||||||
add_subdirectory(rdp)
|
add_subdirectory(rdp)
|
||||||
|
add_subdirectory(redis)
|
||||||
add_subdirectory(rfb)
|
add_subdirectory(rfb)
|
||||||
add_subdirectory(rpc)
|
add_subdirectory(rpc)
|
||||||
add_subdirectory(sip)
|
add_subdirectory(sip)
|
||||||
|
|
5
src/analyzer/protocol/redis/CMakeLists.txt
Normal file
5
src/analyzer/protocol/redis/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
spicy_add_analyzer(
|
||||||
|
NAME Redis
|
||||||
|
PACKAGE_NAME spicy-redis
|
||||||
|
SOURCES resp.spicy resp.evt redis.spicy
|
||||||
|
MODULES RESP Redis)
|
403
src/analyzer/protocol/redis/redis.spicy
Normal file
403
src/analyzer/protocol/redis/redis.spicy
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
# See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
#
|
||||||
|
# Handle any Redis-specific "parsing"
|
||||||
|
|
||||||
|
module Redis;
|
||||||
|
|
||||||
|
import RESP;
|
||||||
|
|
||||||
|
public type KnownCommand = enum {
|
||||||
|
APPEND,
|
||||||
|
AUTH,
|
||||||
|
BITCOUNT,
|
||||||
|
BITFIELD,
|
||||||
|
BITFIELD_RO,
|
||||||
|
BITOP,
|
||||||
|
BITPOS,
|
||||||
|
BLMPOP,
|
||||||
|
BLPOP,
|
||||||
|
BRPOP,
|
||||||
|
CLIENT,
|
||||||
|
COPY,
|
||||||
|
DECR,
|
||||||
|
DECRBY,
|
||||||
|
DEL,
|
||||||
|
DUMP,
|
||||||
|
EXISTS,
|
||||||
|
EXPIRE,
|
||||||
|
EXPIREAT,
|
||||||
|
EXPIRETIME,
|
||||||
|
GET,
|
||||||
|
GETBIT,
|
||||||
|
GETDEL,
|
||||||
|
GETEX,
|
||||||
|
GETRANGE,
|
||||||
|
GETSET,
|
||||||
|
HDEL,
|
||||||
|
HGET,
|
||||||
|
HSET,
|
||||||
|
INCR,
|
||||||
|
INCRBY,
|
||||||
|
KEYS,
|
||||||
|
MGET,
|
||||||
|
MOVE,
|
||||||
|
MSET,
|
||||||
|
PERSIST,
|
||||||
|
RENAME,
|
||||||
|
SET,
|
||||||
|
STRLEN,
|
||||||
|
TTL,
|
||||||
|
TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Command = struct {
|
||||||
|
raw: vector<bytes>;
|
||||||
|
name: bytes;
|
||||||
|
key: optional<bytes>;
|
||||||
|
value: optional<bytes>;
|
||||||
|
known: optional<KnownCommand>;
|
||||||
|
};
|
||||||
|
|
||||||
|
# This just assumes all elements in the array is a bulk string and puts them in a vector
|
||||||
|
public function make_command(command: RESP::ClientData): Command {
|
||||||
|
if (command?.multibulk)
|
||||||
|
return bulk_command(command);
|
||||||
|
else
|
||||||
|
return inline_command(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bulk_command(command: RESP::ClientData): Command {
|
||||||
|
local v: vector<bytes>;
|
||||||
|
for (ele in command.multibulk.elements) {
|
||||||
|
v.push_back(ele.content);
|
||||||
|
}
|
||||||
|
return parse_command(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inline_command(command: RESP::ClientData): Command {
|
||||||
|
# Only call this if it's inline :)
|
||||||
|
assert command?.inline;
|
||||||
|
|
||||||
|
local tokenized: vector<bytes>;
|
||||||
|
local it = command.inline.at(0);
|
||||||
|
# Redis whitespace characters are null, tab, LF, CR, and space
|
||||||
|
local whitespace = set<uint8>(0, 9, 10, 13, 32);
|
||||||
|
# Note: this logic is a bit different from Redis. Hopefully it doesn't matter
|
||||||
|
while (True) {
|
||||||
|
while (it != end(command.inline) && ((*it) in whitespace))
|
||||||
|
it++;
|
||||||
|
|
||||||
|
# Get a token
|
||||||
|
local start = it;
|
||||||
|
if (it != end(command.inline)) {
|
||||||
|
local double_quotes = False;
|
||||||
|
local single_quotes = False;
|
||||||
|
local done = False;
|
||||||
|
while (!done) {
|
||||||
|
if (double_quotes) {
|
||||||
|
if (*it == '\' && it + 1 != end(command.inline) && *(it + 1) == '"') {
|
||||||
|
# Skip one, then later we skip another
|
||||||
|
it++;
|
||||||
|
} else if (*it == '"') {
|
||||||
|
double_quotes = False;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
} else if (single_quotes) {
|
||||||
|
if (*it == '\' && it + 1 != end(command.inline) && *(it + 1) == ''') {
|
||||||
|
# Skip one, then later we skip another
|
||||||
|
it++;
|
||||||
|
} else if (*it == ''') {
|
||||||
|
single_quotes = False;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
} else {
|
||||||
|
if (it != end(command.inline)) {
|
||||||
|
switch (*it) {
|
||||||
|
case '"': double_quotes = True;
|
||||||
|
case ''': single_quotes = True;
|
||||||
|
default: {
|
||||||
|
if ((*it) in whitespace)
|
||||||
|
done = True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done)
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == end(command.inline))
|
||||||
|
done = True;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
|
||||||
|
tokenized.push_back(command.inline.sub(start, it));
|
||||||
|
}
|
||||||
|
return parse_command(tokenized);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parses the vector of bytes to get a Command object
|
||||||
|
function parse_command(raw: vector<bytes>): Command {
|
||||||
|
assert |raw| >= 1;
|
||||||
|
local cmd = command_from(raw[0]);
|
||||||
|
local parsed: Command = [$raw = raw, $name = raw[0], $key = Null, $value = Null, $known = cmd];
|
||||||
|
if (!cmd)
|
||||||
|
return parsed;
|
||||||
|
|
||||||
|
if (|raw| >= 2) {
|
||||||
|
switch (*cmd) {
|
||||||
|
case KnownCommand::KEYS:
|
||||||
|
parsed.key = raw[1];
|
||||||
|
case KnownCommand::APPEND,
|
||||||
|
KnownCommand::BITCOUNT,
|
||||||
|
KnownCommand::BITFIELD,
|
||||||
|
KnownCommand::BITFIELD_RO,
|
||||||
|
KnownCommand::BITPOS,
|
||||||
|
KnownCommand::BLPOP,
|
||||||
|
KnownCommand::BRPOP,
|
||||||
|
KnownCommand::COPY,
|
||||||
|
KnownCommand::DECR,
|
||||||
|
KnownCommand::DECRBY,
|
||||||
|
KnownCommand::DEL,
|
||||||
|
KnownCommand::DUMP,
|
||||||
|
KnownCommand::EXISTS,
|
||||||
|
KnownCommand::EXPIRE,
|
||||||
|
KnownCommand::EXPIREAT,
|
||||||
|
KnownCommand::EXPIRETIME,
|
||||||
|
KnownCommand::GET,
|
||||||
|
KnownCommand::GETBIT,
|
||||||
|
KnownCommand::GETDEL,
|
||||||
|
KnownCommand::GETEX,
|
||||||
|
KnownCommand::GETRANGE,
|
||||||
|
KnownCommand::GETSET,
|
||||||
|
KnownCommand::HDEL,
|
||||||
|
KnownCommand::HGET,
|
||||||
|
KnownCommand::HSET,
|
||||||
|
KnownCommand::INCR,
|
||||||
|
KnownCommand::INCRBY,
|
||||||
|
KnownCommand::MGET,
|
||||||
|
KnownCommand::MOVE,
|
||||||
|
KnownCommand::MSET,
|
||||||
|
KnownCommand::PERSIST,
|
||||||
|
KnownCommand::RENAME,
|
||||||
|
KnownCommand::SET,
|
||||||
|
KnownCommand::STRLEN,
|
||||||
|
KnownCommand::TTL,
|
||||||
|
KnownCommand::TYPE:
|
||||||
|
parsed.key = raw[1];
|
||||||
|
default: ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (|raw| >= 3) {
|
||||||
|
switch (*cmd) {
|
||||||
|
case KnownCommand::SET,
|
||||||
|
KnownCommand::APPEND,
|
||||||
|
KnownCommand::DECRBY,
|
||||||
|
KnownCommand::EXPIRE,
|
||||||
|
KnownCommand::EXPIREAT,
|
||||||
|
KnownCommand::GETBIT,
|
||||||
|
KnownCommand::GETSET,
|
||||||
|
KnownCommand::HDEL,
|
||||||
|
KnownCommand::HGET,
|
||||||
|
KnownCommand::INCRBY,
|
||||||
|
KnownCommand::MOVE,
|
||||||
|
KnownCommand::MSET,
|
||||||
|
KnownCommand::RENAME:
|
||||||
|
parsed.value = raw[2];
|
||||||
|
# Op first, destination second, then a list of keys. Just log dest
|
||||||
|
case KnownCommand::BITOP: parsed.key = raw[2];
|
||||||
|
default: ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (|raw| >= 4) {
|
||||||
|
switch (*cmd) {
|
||||||
|
# timeout, numkeys, then key
|
||||||
|
case KnownCommand::BLMPOP: parsed.key = raw[3];
|
||||||
|
default: ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function command_from(cmd_bytes: bytes): optional<KnownCommand> {
|
||||||
|
local cmd: optional<KnownCommand> = Null;
|
||||||
|
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;
|
||||||
|
case b"bitop": cmd = KnownCommand::BITOP;
|
||||||
|
case b"bitpos": cmd = KnownCommand::BITPOS;
|
||||||
|
case b"blmpop": cmd = KnownCommand::BLMPOP;
|
||||||
|
case b"blpop": cmd = KnownCommand::BLPOP;
|
||||||
|
case b"brpop": cmd = KnownCommand::BRPOP;
|
||||||
|
case b"client": cmd = KnownCommand::CLIENT;
|
||||||
|
case b"copy": cmd = KnownCommand::COPY;
|
||||||
|
case b"decr": cmd = KnownCommand::DECR;
|
||||||
|
case b"decrby": cmd = KnownCommand::DECRBY;
|
||||||
|
case b"del": cmd = KnownCommand::DEL;
|
||||||
|
case b"dump": cmd = KnownCommand::DUMP;
|
||||||
|
case b"exists": cmd = KnownCommand::EXISTS;
|
||||||
|
case b"expire": cmd = KnownCommand::EXPIRE;
|
||||||
|
case b"expireat": cmd = KnownCommand::EXPIREAT;
|
||||||
|
case b"expiretime": cmd = KnownCommand::EXPIRETIME;
|
||||||
|
case b"expiretime": cmd = KnownCommand::EXPIRETIME;
|
||||||
|
case b"get": cmd = KnownCommand::GET;
|
||||||
|
case b"getbit": cmd = KnownCommand::GETBIT;
|
||||||
|
case b"getdel": cmd = KnownCommand::GETDEL;
|
||||||
|
case b"getex": cmd = KnownCommand::GETEX;
|
||||||
|
case b"getrange": cmd = KnownCommand::GETRANGE;
|
||||||
|
case b"getset": cmd = KnownCommand::GETSET;
|
||||||
|
case b"hdel": cmd = KnownCommand::HDEL;
|
||||||
|
case b"hget": cmd = KnownCommand::HGET;
|
||||||
|
case b"hset": cmd = KnownCommand::HSET;
|
||||||
|
case b"incr": cmd = KnownCommand::INCR;
|
||||||
|
case b"incrby": cmd = KnownCommand::INCRBY;
|
||||||
|
case b"keys": cmd = KnownCommand::KEYS;
|
||||||
|
case b"mget": cmd = KnownCommand::MGET;
|
||||||
|
case b"move": cmd = KnownCommand::MOVE;
|
||||||
|
case b"mset": cmd = KnownCommand::MSET;
|
||||||
|
case b"persist": cmd = KnownCommand::PERSIST;
|
||||||
|
case b"rename": cmd = KnownCommand::RENAME;
|
||||||
|
case b"strlen": cmd = KnownCommand::STRLEN;
|
||||||
|
case b"ttl": cmd = KnownCommand::TTL;
|
||||||
|
case b"type": cmd = KnownCommand::TYPE;
|
||||||
|
default: cmd = Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Set = struct {
|
||||||
|
key: bytes;
|
||||||
|
value: bytes;
|
||||||
|
nx: bool &default=False;
|
||||||
|
xx: bool &default=False;
|
||||||
|
get: bool &default=False;
|
||||||
|
ex: optional<uint64> &default=Null;
|
||||||
|
px: optional<uint64> &default=Null;
|
||||||
|
exat: optional<uint64> &default=Null;
|
||||||
|
pxat: optional<uint64> &default=Null;
|
||||||
|
keep_ttl: bool &default=False;
|
||||||
|
};
|
||||||
|
|
||||||
|
public function make_set(command: Command): Set {
|
||||||
|
assert |command.raw| >= 3 : "Must have at least 3 elements in SET";
|
||||||
|
assert command.key : "SET must validate a key";
|
||||||
|
assert command.value : "SET must validate a value";
|
||||||
|
local parsed: Set = [$key = *command.key, $value = *command.value];
|
||||||
|
local i = 3;
|
||||||
|
while (i < |command.raw|) {
|
||||||
|
switch (command.raw[i].lower()) {
|
||||||
|
case b"nx": parsed.nx = True;
|
||||||
|
case b"xx": parsed.xx = True;
|
||||||
|
case b"get": parsed.get = True;
|
||||||
|
case b"ex": {
|
||||||
|
++i;
|
||||||
|
if (i >= |command.raw|)
|
||||||
|
break;
|
||||||
|
parsed.ex = command.raw[i].to_uint();
|
||||||
|
}
|
||||||
|
case b"px": {
|
||||||
|
++i;
|
||||||
|
if (i >= |command.raw|)
|
||||||
|
break;
|
||||||
|
parsed.px = command.raw[i].to_uint();
|
||||||
|
}
|
||||||
|
case b"exat": {
|
||||||
|
++i;
|
||||||
|
if (i >= |command.raw|)
|
||||||
|
break;
|
||||||
|
parsed.exat = command.raw[i].to_uint();
|
||||||
|
}
|
||||||
|
case b"pxat": {
|
||||||
|
++i;
|
||||||
|
if (i >= |command.raw|)
|
||||||
|
break;
|
||||||
|
parsed.pxat = command.raw[i].to_uint();
|
||||||
|
}
|
||||||
|
case b"keepttl": parsed.keep_ttl = True;
|
||||||
|
default: ();
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function is_set(data: RESP::ClientData): bool {
|
||||||
|
return data.command.known && *(data.command.known) == KnownCommand::SET && data.command.key && data.command.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Get = struct {
|
||||||
|
key: bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
public function make_get(command: Command): Get {
|
||||||
|
assert command.key : "GET must validate a key";
|
||||||
|
return [$key = *command.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReplyData = struct {
|
||||||
|
value: optional<bytes>;
|
||||||
|
};
|
||||||
|
|
||||||
|
public function is_err(server_data: RESP::ServerData): bool {
|
||||||
|
return server_data.data?.simple_error || server_data.data?.bulk_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bulk_string_content(bulk: RESP::BulkString): bytes {
|
||||||
|
if (bulk?.content)
|
||||||
|
return bulk.content;
|
||||||
|
else
|
||||||
|
return b"";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the server reply in a simpler form
|
||||||
|
public function make_server_reply(data: RESP::ServerData): ReplyData {
|
||||||
|
local res: ReplyData = [$value = Null];
|
||||||
|
if (data.data?.simple_error)
|
||||||
|
res.value = data.data.simple_error.content;
|
||||||
|
else if (data.data?.bulk_error)
|
||||||
|
res.value = bulk_string_content(data.data.bulk_error);
|
||||||
|
else if (data.data?.simple_string)
|
||||||
|
res.value = data.data.simple_string.content;
|
||||||
|
else if (data.data?.bulk_string)
|
||||||
|
res.value = bulk_string_content(data.data.bulk_string);
|
||||||
|
else if (data.data?.verbatim_string)
|
||||||
|
res.value = bulk_string_content(data.data.verbatim_string);
|
||||||
|
else if (data.data?.boolean)
|
||||||
|
res.value = data.data.boolean.val ? b"T" : b"F";
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
20
src/analyzer/protocol/redis/resp.evt
Normal file
20
src/analyzer/protocol/redis/resp.evt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
protocol analyzer Redis over TCP:
|
||||||
|
parse originator with RESP::ClientMessages,
|
||||||
|
parse responder with RESP::ServerMessages;
|
||||||
|
|
||||||
|
import RESP;
|
||||||
|
import Redis;
|
||||||
|
|
||||||
|
export Redis::KnownCommand;
|
||||||
|
|
||||||
|
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, self.command);
|
||||||
|
|
||||||
|
on RESP::ServerData if ( ! Redis::is_err(self) ) -> event Redis::reply($conn, Redis::make_server_reply(self));
|
||||||
|
on RESP::ServerData if ( Redis::is_err(self) ) -> event Redis::error($conn, Redis::make_server_reply(self));
|
211
src/analyzer/protocol/redis/resp.spicy
Normal file
211
src/analyzer/protocol/redis/resp.spicy
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
# See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
module RESP;
|
||||||
|
|
||||||
|
import Redis;
|
||||||
|
|
||||||
|
import spicy;
|
||||||
|
|
||||||
|
# Maximum size for parsing of certain fields. By restricting this we avoid
|
||||||
|
# exhausting main memory.
|
||||||
|
const MAX_SIZE = 1024 * 1024;
|
||||||
|
const MAX_RECURSION_DEPTH = 20;
|
||||||
|
|
||||||
|
public type ClientMessages = unit {
|
||||||
|
# The context here refers to whether we saw client data first. It is a one-time switch,
|
||||||
|
# either we have seen client data or not.
|
||||||
|
%context = bool;
|
||||||
|
on %init {
|
||||||
|
*self.context() = True;
|
||||||
|
}
|
||||||
|
: ClientData[];
|
||||||
|
};
|
||||||
|
|
||||||
|
public type ServerMessages = unit {
|
||||||
|
%context = bool;
|
||||||
|
on %init {
|
||||||
|
if (!*self.context()) {
|
||||||
|
throw "Server responses must come after a client request is seen";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: (ServerData &synchronize)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
public type ClientData = unit {
|
||||||
|
on %init() {
|
||||||
|
self.start = self.input();
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clients can only be an array or inline
|
||||||
|
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: BulkStringArray;
|
||||||
|
} else {
|
||||||
|
inline: RedisBytes &max-size=1024;
|
||||||
|
};
|
||||||
|
|
||||||
|
var start: iterator<stream>;
|
||||||
|
var command: Redis::Command;
|
||||||
|
|
||||||
|
on %done {
|
||||||
|
self.command = Redis::make_command(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type BulkStringArray = unit {
|
||||||
|
num_elements: RedisBytes &convert=$$.to_int(10) &requires=self.num_elements <= int64(MAX_SIZE);
|
||||||
|
# Null array is an array with elements unset. This is different from an empty array
|
||||||
|
elements: BulkStringWithTy[uint64(self.num_elements)];
|
||||||
|
};
|
||||||
|
|
||||||
|
type BulkStringWithTy = unit {
|
||||||
|
# Need to consume the type here
|
||||||
|
: uint8 &requires=$$ == '$';
|
||||||
|
|
||||||
|
length: RedisBytes &convert=$$.to_int(10) &requires=self.length <= int64(MAX_SIZE);
|
||||||
|
# NullBulkString is a BulkString with content unset
|
||||||
|
content: bytes &size=uint64(self.length) if(self.length >= 0);
|
||||||
|
|
||||||
|
# Consume last CLRF
|
||||||
|
: skip RedisBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
public type ServerData = unit {
|
||||||
|
%synchronize-after = b"\x0d\x0a";
|
||||||
|
var depth: uint8& = new uint8;
|
||||||
|
data: Data(self.depth);
|
||||||
|
};
|
||||||
|
|
||||||
|
type Data = unit(depth: uint8&) {
|
||||||
|
%synchronize-after = b"\x0d\x0a";
|
||||||
|
ty: uint8 &convert=DataType($$);
|
||||||
|
switch (self.ty) {
|
||||||
|
DataType::SIMPLE_STRING -> simple_string: SimpleString(False);
|
||||||
|
DataType::SIMPLE_ERROR -> simple_error: SimpleString(True);
|
||||||
|
DataType::INTEGER -> integer: Integer;
|
||||||
|
DataType::BULK_STRING -> bulk_string: BulkString(False);
|
||||||
|
DataType::ARRAY -> array: Array(depth);
|
||||||
|
DataType::NULL -> null: Null_;
|
||||||
|
DataType::BOOLEAN -> boolean: Boolean;
|
||||||
|
DataType::DOUBLE -> double: Double;
|
||||||
|
DataType::BIG_NUM -> big_num: BigNum;
|
||||||
|
DataType::BULK_ERROR -> bulk_error: BulkString(True);
|
||||||
|
# This can be a different type, but the docs also say:
|
||||||
|
# "Some client libraries may ignore the difference between this type and the string type"
|
||||||
|
# It just includes the encoding first in the content
|
||||||
|
DataType::VERBATIM_STRING -> verbatim_string: BulkString(False);
|
||||||
|
DataType::MAP -> map_: Map(depth);
|
||||||
|
DataType::SET -> set_: Set(depth);
|
||||||
|
# "Push events are encoded similarly to arrays, differing only in their
|
||||||
|
# first byte" - TODO: can probably make it more obvious, though
|
||||||
|
DataType::PUSH -> push: Array(depth);
|
||||||
|
};
|
||||||
|
|
||||||
|
on %init {
|
||||||
|
depth++;
|
||||||
|
if (*depth > MAX_RECURSION_DEPTH)
|
||||||
|
throw "exceeded max recursion depth";
|
||||||
|
}
|
||||||
|
|
||||||
|
on %done {
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type DataType = enum {
|
||||||
|
SIMPLE_STRING = '+',
|
||||||
|
SIMPLE_ERROR = '-',
|
||||||
|
INTEGER = ':',
|
||||||
|
BULK_STRING = '$',
|
||||||
|
ARRAY = '*',
|
||||||
|
NULL = '_',
|
||||||
|
BOOLEAN = '#',
|
||||||
|
DOUBLE = ',',
|
||||||
|
BIG_NUM = '(',
|
||||||
|
BULK_ERROR = '!',
|
||||||
|
VERBATIM_STRING = '=',
|
||||||
|
MAP = '%',
|
||||||
|
SET = '~',
|
||||||
|
PUSH = '>',
|
||||||
|
};
|
||||||
|
|
||||||
|
# Helper unit to extract bytes of some reasonable size so we do not exhaust mem.
|
||||||
|
type RedisBytes = unit {
|
||||||
|
data: bytes &until=b"\x0d\x0a" &max-size=MAX_SIZE;
|
||||||
|
} &convert=self.data;
|
||||||
|
|
||||||
|
type SimpleString = unit(is_error: bool) {
|
||||||
|
content: RedisBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Integer = unit {
|
||||||
|
int: RedisBytes &convert=$$.to_int(10);
|
||||||
|
};
|
||||||
|
|
||||||
|
type BulkString = unit(is_error: bool) {
|
||||||
|
length: RedisBytes &convert=$$.to_int(10) &requires=self.length <= int64(MAX_SIZE);
|
||||||
|
# NullBulkString is a BulkString with content unset
|
||||||
|
content: bytes &size=uint64(self.length) if(self.length >= 0);
|
||||||
|
|
||||||
|
# Consume last CLRF if not a null bulk string
|
||||||
|
: skip RedisBytes if(self.length >= 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
type Array = unit(depth: uint8&) {
|
||||||
|
num_elements: RedisBytes &convert=$$.to_int(10) &requires=self.num_elements <= int64(MAX_SIZE);
|
||||||
|
# Null array is an array with elements unset. This is different from an empty array
|
||||||
|
elements: Data(depth)[uint64(self.num_elements)];
|
||||||
|
};
|
||||||
|
|
||||||
|
type Null_ = unit {
|
||||||
|
# Still must consume CLRF
|
||||||
|
: skip RedisBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Boolean = unit {
|
||||||
|
val: uint8 &convert=$$ == 't';
|
||||||
|
: skip RedisBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Double = unit {
|
||||||
|
val: RedisBytes &convert=$$.to_real();
|
||||||
|
};
|
||||||
|
|
||||||
|
type BigNum = unit {
|
||||||
|
# Big num can be very big so leave it in bytes.
|
||||||
|
val: RedisBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Map = unit(depth: uint8&) {
|
||||||
|
num_elements: RedisBytes &convert=$$.to_uint(10);
|
||||||
|
# TODO: How can I make this into a map? Alternatively, how can I do this better?
|
||||||
|
raw_data: Data(depth)[self.num_elements * 2];
|
||||||
|
|
||||||
|
# TODO: This is broken. See https://github.com/zeek/spicy/issues/2061
|
||||||
|
# var key_val_pairs: vector<tuple<Data, Data>>;
|
||||||
|
# on raw_data {
|
||||||
|
# while (local i = 0; i < self.num_elements) {
|
||||||
|
# self.key_val_pairs.push_back(($$[i], $$[i + 1]));
|
||||||
|
# i += 2;
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
};
|
||||||
|
|
||||||
|
type Set = unit(depth: uint8&) {
|
||||||
|
num_elements: RedisBytes &convert=$$.to_uint(10) &requires=self.num_elements <= MAX_SIZE;
|
||||||
|
# TODO: This should be a set but doesn't go in the backed C++ set
|
||||||
|
elements: Data(depth)[self.num_elements];
|
||||||
|
};
|
||||||
|
|
||||||
|
on ServerData::%done {
|
||||||
|
spicy::accept_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
on ServerData::%error {
|
||||||
|
spicy::decline_input("error while parsing RESP server data");
|
||||||
|
}
|
|
@ -46,6 +46,7 @@
|
||||||
1 614
|
1 614
|
||||||
1 631
|
1 631
|
||||||
1 636
|
1 636
|
||||||
|
1 6379
|
||||||
1 6666
|
1 6666
|
||||||
1 6667
|
1 6667
|
||||||
1 6668
|
1 6668
|
||||||
|
@ -66,8 +67,8 @@
|
||||||
1 992
|
1 992
|
||||||
1 993
|
1 993
|
||||||
1 995
|
1 995
|
||||||
75 and
|
76 and
|
||||||
74 or
|
75 or
|
||||||
75 port
|
76 port
|
||||||
47 tcp
|
48 tcp
|
||||||
28 udp
|
28 udp
|
||||||
|
|
|
@ -466,6 +466,9 @@ scripts/base/init-default.zeek
|
||||||
scripts/base/protocols/rdp/__load__.zeek
|
scripts/base/protocols/rdp/__load__.zeek
|
||||||
scripts/base/protocols/rdp/consts.zeek
|
scripts/base/protocols/rdp/consts.zeek
|
||||||
scripts/base/protocols/rdp/main.zeek
|
scripts/base/protocols/rdp/main.zeek
|
||||||
|
scripts/base/protocols/redis/__load__.zeek
|
||||||
|
scripts/base/protocols/redis/spicy-events.zeek
|
||||||
|
scripts/base/protocols/redis/main.zeek
|
||||||
scripts/base/protocols/rfb/__load__.zeek
|
scripts/base/protocols/rfb/__load__.zeek
|
||||||
scripts/base/protocols/rfb/main.zeek
|
scripts/base/protocols/rfb/main.zeek
|
||||||
scripts/base/protocols/sip/__load__.zeek
|
scripts/base/protocols/sip/__load__.zeek
|
||||||
|
|
|
@ -46,6 +46,7 @@ print_log_path
|
||||||
quic
|
quic
|
||||||
radius
|
radius
|
||||||
rdp
|
rdp
|
||||||
|
redis
|
||||||
reporter
|
reporter
|
||||||
rfb
|
rfb
|
||||||
signatures
|
signatures
|
||||||
|
|
|
@ -593,6 +593,39 @@ connection {
|
||||||
* ts: time, log=T, optional=F
|
* ts: time, log=T, optional=F
|
||||||
* uid: string, 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 {
|
||||||
|
* key: string, log=T, optional=T
|
||||||
|
* known: enum Redis::KnownCommand, log=F, optional=T
|
||||||
|
* name: string, log=T, optional=F
|
||||||
|
* raw: vector of string, log=F, optional=F
|
||||||
|
* value: string, log=T, optional=T
|
||||||
|
}
|
||||||
|
* id: record conn_id, log=T, optional=F
|
||||||
|
conn_id { ... }
|
||||||
|
* reply: record Redis::ReplyData, log=T, optional=T
|
||||||
|
Redis::ReplyData {
|
||||||
|
* value: string, log=T, optional=T
|
||||||
|
}
|
||||||
|
* success: bool, log=T, optional=T
|
||||||
|
* ts: time, log=T, optional=F
|
||||||
|
* uid: string, log=T, optional=F
|
||||||
|
}
|
||||||
|
* redis_state: record Redis::State, log=F, optional=T
|
||||||
|
Redis::State {
|
||||||
|
* current_command: count, log=F, optional=T
|
||||||
|
* current_reply: count, log=F, optional=T
|
||||||
|
* no_reply_ranges: vector of record Redis::NoReplyRange, log=F, optional=F
|
||||||
|
Redis::NoReplyRange {
|
||||||
|
* begin: count, log=F, optional=F
|
||||||
|
* end: count, log=F, optional=T
|
||||||
|
}
|
||||||
|
* 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
|
* removal_hooks: set[func], log=F, optional=T
|
||||||
* resp: record endpoint, log=F, optional=F
|
* resp: record endpoint, log=F, optional=F
|
||||||
endpoint { ... }
|
endpoint { ... }
|
||||||
|
|
|
@ -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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53099 127.0.0.1 6379 AUTH - - T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53099 127.0.0.1 6379 PING - - T OK
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,13 @@
|
||||||
|
### 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 failed:, WRONGPASS invalid username-password pair or user is disabled.
|
||||||
|
AUTH
|
||||||
|
username: default
|
||||||
|
password: defaultpassword
|
||||||
|
Auth succeeded:, OK
|
||||||
|
AUTH
|
||||||
|
username: noone
|
||||||
|
password: password
|
||||||
|
Auth failed:, WRONGPASS invalid username-password pair or user is disabled.
|
1001
testing/btest/Baseline/scripts.base.protocols.redis.bulk/output
Normal file
1001
testing/btest/Baseline/scripts.base.protocols.redis.bulk/output
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,16 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 61211 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 61212 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 61211 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 61211 ::1 6379 PING - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 61212 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ::1 61212 ::1 6379 PING - - - -
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,18 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 PING - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 CLIENT - - T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 PING - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 60761 ::1 6379 PING - - T PONG
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,17 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 PING - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 CLIENT - - - -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 CLIENT - - T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56348 ::1 6379 PING - - T PONG
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -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 conn
|
||||||
|
#open XXXX-XX-XX-XX-XX-XX
|
||||||
|
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents ip_proto
|
||||||
|
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string] count
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 tcp redis 13.539827 18106 928 OTH T F 0 DdA 316 34538 158 9144 - 6
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,3 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
Factorial of 100 is 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
|
||||||
|
Found 152 SET commands
|
|
@ -0,0 +1,168 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_3 - T 6
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_3 - T 6
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_50 - T (empty)
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_1 1 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_2 2 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_3 6 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_4 24 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_5 120 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_6 720 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_7 5040 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_8 40320 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_9 362880 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_10 3628800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_11 39916800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_12 479001600 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_13 6227020800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_14 87178291200 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_15 1307674368000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_16 20922789888000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_17 355687428096000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_18 6402373705728000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_19 121645100408832000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_20 2432902008176640000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_21 51090942171709440000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_22 1124000727777607680000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_23 25852016738884976640000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_24 620448401733239439360000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_25 15511210043330985984000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_26 403291461126605635584000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_27 10888869450418352160768000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_28 304888344611713860501504000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_29 8841761993739701954543616000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_30 265252859812191058636308480000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_31 8222838654177922817725562880000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_32 263130836933693530167218012160000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_33 8683317618811886495518194401280000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_34 295232799039604140847618609643520000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_35 10333147966386144929666651337523200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_36 371993326789901217467999448150835200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_37 13763753091226345046315979581580902400000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_38 523022617466601111760007224100074291200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_39 20397882081197443358640281739902897356800000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_40 815915283247897734345611269596115894272000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_41 33452526613163807108170062053440751665152000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_42 1405006117752879898543142606244511569936384000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_43 60415263063373835637355132068513997507264512000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_44 2658271574788448768043625811014615890319638528000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_45 119622220865480194561963161495657715064383733760000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_46 5502622159812088949850305428800254892961651752960000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_47 258623241511168180642964355153611979969197632389120000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_48 12413915592536072670862289047373375038521486354677760000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_49 608281864034267560872252163321295376887552831379210240000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_50 - T 30414093201713378043612608166064768844377641568960512000000000000
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_50 - T 30414093201713378043612608166064768844377641568960512000000000000
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 GET :1:factorial_100 - T (empty)
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_1 1 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_2 2 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_3 6 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_4 24 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_5 120 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_6 720 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_7 5040 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_8 40320 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_9 362880 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_10 3628800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_11 39916800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_12 479001600 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_13 6227020800 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_14 87178291200 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_15 1307674368000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_16 20922789888000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_17 355687428096000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_18 6402373705728000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_19 121645100408832000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_20 2432902008176640000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_21 51090942171709440000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_22 1124000727777607680000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_23 25852016738884976640000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_24 620448401733239439360000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_25 15511210043330985984000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_26 403291461126605635584000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_27 10888869450418352160768000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_28 304888344611713860501504000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_29 8841761993739701954543616000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_30 265252859812191058636308480000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_31 8222838654177922817725562880000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_32 263130836933693530167218012160000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_33 8683317618811886495518194401280000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_34 295232799039604140847618609643520000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_35 10333147966386144929666651337523200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_36 371993326789901217467999448150835200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_37 13763753091226345046315979581580902400000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_38 523022617466601111760007224100074291200000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_39 20397882081197443358640281739902897356800000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_40 815915283247897734345611269596115894272000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_41 33452526613163807108170062053440751665152000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_42 1405006117752879898543142606244511569936384000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_43 60415263063373835637355132068513997507264512000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_44 2658271574788448768043625811014615890319638528000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_45 119622220865480194561963161495657715064383733760000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_46 5502622159812088949850305428800254892961651752960000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_47 258623241511168180642964355153611979969197632389120000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_48 12413915592536072670862289047373375038521486354677760000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_49 608281864034267560872252163321295376887552831379210240000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_50 30414093201713378043612608166064768844377641568960512000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_51 1551118753287382280224243016469303211063259720016986112000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_52 80658175170943878571660636856403766975289505440883277824000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_53 4274883284060025564298013753389399649690343788366813724672000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_54 230843697339241380472092742683027581083278564571807941132288000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_55 12696403353658275925965100847566516959580321051449436762275840000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_56 710998587804863451854045647463724949736497978881168458687447040000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_57 40526919504877216755680601905432322134980384796226602145184481280000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_58 2350561331282878571829474910515074683828862318181142924420699914240000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_59 138683118545689835737939019720389406345902876772687432540821294940160000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_60 8320987112741390144276341183223364380754172606361245952449277696409600000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_61 507580213877224798800856812176625227226004528988036003099405939480985600000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_62 31469973260387937525653122354950764088012280797258232192163168247821107200000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_63 1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_64 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_65 8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_66 544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_67 36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_68 2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_69 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_70 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_71 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_72 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_73 4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_74 330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_75 24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_76 1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_77 145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_78 11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_79 894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_80 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_81 5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_82 475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_83 39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_84 3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_85 281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_86 24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_87 2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_88 185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_89 16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_90 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_91 135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_92 12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_93 1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_94 108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_95 10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_96 991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_97 96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_98 9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_99 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.1.4 50044 18.234.186.95 10625 SET :1:factorial_100 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 T OK
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,22 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 - - - T PONG
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -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 weird
|
||||||
|
#open XXXX-XX-XX-XX-XX-XX
|
||||||
|
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source
|
||||||
|
#types time string addr port addr port string string bool string string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 57156 ::1 6379 Redis_excessive_pipelining - F zeek -
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,18 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key "my value with spaces" T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key2 'my value with single quotes' T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key3 'my value with "double" inners' T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key4 "my value with 'single' inners" T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key5 "my value with \\"escaped\\" quotes" T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET key6 'my value with \\'escaped\\' quotes' T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET bad1 "unclosed double quotes F ERR Protocol error: unbalanced quotes in request
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 63754 ::1 6379 SET bad2 'unclosed single quotes - -
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +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: HI
|
|
@ -0,0 +1,14 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56731 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56731 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56731 ::1 6379 SET HI 3 T OK
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 56731 ::1 6379 GET HI - T 3
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,13 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 51122 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 51122 ::1 6379 PING - - T PONG
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ::1 51122 ::1 6379 PING - - T PONG
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,13 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 56162 127.0.0.1 6379 SUBSCRIBE - - T -
|
||||||
|
XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 56163 127.0.0.1 6379 PUBLISH - - T -
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 56162 127.0.0.1 6379 - - - T -
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
|
@ -0,0 +1,4 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
Key: test Value: hi
|
||||||
|
Key: one:1 Value: 2
|
||||||
|
Key: two:2 Value: three
|
|
@ -0,0 +1 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
|
@ -0,0 +1,14 @@
|
||||||
|
### 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.name cmd.key cmd.value success reply.value
|
||||||
|
#types time string addr port addr port string string string bool string
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49992 127.0.0.1 6379 XADD - - T 1729622832637-0
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49992 127.0.0.1 6379 XADD - - T 1729622836953-0
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49992 127.0.0.1 6379 XADD - - T 1729622840530-0
|
||||||
|
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 49992 127.0.0.1 6379 XRANGE - - T -
|
||||||
|
#close XXXX-XX-XX-XX-XX-XX
|
BIN
testing/btest/Traces/redis/almost-resp.pcap
Normal file
BIN
testing/btest/Traces/redis/almost-resp.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/auth.pcap
Normal file
BIN
testing/btest/Traces/redis/auth.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/bulk-loading.pcap
Normal file
BIN
testing/btest/Traces/redis/bulk-loading.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/client-skip-while-off.pcap
Normal file
BIN
testing/btest/Traces/redis/client-skip-while-off.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/django-cloud.pcap
Normal file
BIN
testing/btest/Traces/redis/django-cloud.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/excessive-pipelining.pcap
Normal file
BIN
testing/btest/Traces/redis/excessive-pipelining.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/pipeline-quotes.pcap
Normal file
BIN
testing/btest/Traces/redis/pipeline-quotes.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/pipeline-with-commands.pcap
Normal file
BIN
testing/btest/Traces/redis/pipeline-with-commands.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/pipelining-example.pcap
Normal file
BIN
testing/btest/Traces/redis/pipelining-example.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/pubsub.pcap
Normal file
BIN
testing/btest/Traces/redis/pubsub.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/reply-off-on-2conn.pcap
Normal file
BIN
testing/btest/Traces/redis/reply-off-on-2conn.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/reply-off-on.pcap
Normal file
BIN
testing/btest/Traces/redis/reply-off-on.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/set.pcap
Normal file
BIN
testing/btest/Traces/redis/set.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/start-with-server.pcap
Normal file
BIN
testing/btest/Traces/redis/start-with-server.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/redis/stream.pcap
Normal file
BIN
testing/btest/Traces/redis/stream.pcap
Normal file
Binary file not shown.
11
testing/btest/scripts/base/protocols/redis/almost-redis.zeek
Normal file
11
testing/btest/scripts/base/protocols/redis/almost-redis.zeek
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# @TEST-DOC: Test 2 commands that look like RESP, then server responses don't
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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
|
28
testing/btest/scripts/base/protocols/redis/auth.zeek
Normal file
28
testing/btest/scripts/base/protocols/redis/auth.zeek
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# @TEST-DOC: Test Zeek with AUTH commands
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/auth.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
||||||
|
|
||||||
|
event Redis::auth_command(c: connection, command: Redis::AuthCommand)
|
||||||
|
{
|
||||||
|
print "AUTH";
|
||||||
|
if ( command?$username )
|
||||||
|
print fmt("username: %s", command$username);
|
||||||
|
else
|
||||||
|
print "username: default";
|
||||||
|
|
||||||
|
print fmt("password: %s", command$password);
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::reply(c: connection, data: Redis::ReplyData)
|
||||||
|
{
|
||||||
|
print "Auth succeeded:", data$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::error(c: connection, data: Redis::ReplyData)
|
||||||
|
{
|
||||||
|
print "Auth failed:", data$value;
|
||||||
|
}
|
17
testing/btest/scripts/base/protocols/redis/bulk.zeek
Normal file
17
testing/btest/scripts/base/protocols/redis/bulk.zeek
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing a trace file made with bulk-created SET commands
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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/
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
||||||
|
|
||||||
|
event Redis::set_command(c: connection, command: Redis::SetCommand)
|
||||||
|
{
|
||||||
|
print fmt("SET: %s %s", command$key, command$value);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# @TEST-DOC: Test CLIENT REPLY OFF, but turns on with new connection
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/reply-off-on-2conn.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff redis.log
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
|
@ -0,0 +1,7 @@
|
||||||
|
# @TEST-DOC: Test CLIENT REPLY OFF then ON again and a SKIP
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/reply-off-on.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff redis.log
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
|
@ -0,0 +1,7 @@
|
||||||
|
# @TEST-DOC: Test CLIENT REPLY OFF then ON again and a SKIP
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/client-skip-while-off.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff redis.log
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
39
testing/btest/scripts/base/protocols/redis/django-cloud.zeek
Normal file
39
testing/btest/scripts/base/protocols/redis/django-cloud.zeek
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# @TEST-DOC: Test Redis traffic from a django app using Redis (in the cloud) as a cache
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/django-cloud.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
# @TEST-EXEC: btest-diff redis.log
|
||||||
|
# @TEST-EXEC: btest-diff conn.log
|
||||||
|
|
||||||
|
# This test has a bunch of factorial commands, try to test for the correct
|
||||||
|
# factorial without exploding the baseline
|
||||||
|
|
||||||
|
@load base/protocols/conn
|
||||||
|
@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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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_commands = 5;
|
|
@ -0,0 +1,12 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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
|
|
@ -0,0 +1,22 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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.
|
||||||
|
|
||||||
|
@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, key: string)
|
||||||
|
{
|
||||||
|
print fmt("GET: %s", key);
|
||||||
|
}
|
15
testing/btest/scripts/base/protocols/redis/pipelined.zeek
Normal file
15
testing/btest/scripts/base/protocols/redis/pipelined.zeek
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing "pipelined" data responses
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/pipelining-example.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
# @TEST-EXEC: btest-diff redis.log
|
||||||
|
|
||||||
|
# Testing the example of "pipelining" in REDIS docs:
|
||||||
|
# https://redis.io/docs/latest/develop/use/pipelining/
|
||||||
|
# Namely sending three PINGs. This does not get sent as RESP data, but we should
|
||||||
|
# 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
|
12
testing/btest/scripts/base/protocols/redis/pubsub.zeek
Normal file
12
testing/btest/scripts/base/protocols/redis/pubsub.zeek
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing pubsub commands
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
12
testing/btest/scripts/base/protocols/redis/set.zeek
Normal file
12
testing/btest/scripts/base/protocols/redis/set.zeek
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing SET commands
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/set.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
||||||
|
|
||||||
|
event Redis::set_command(c: connection, command: Redis::SetCommand)
|
||||||
|
{
|
||||||
|
print fmt("Key: %s Value: %s", command$key, command$value);
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
# @TEST-DOC: Test that Redis does not parse if it starts with the server data
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $TRACES/redis/start-with-server.pcap %INPUT >output
|
||||||
|
# @TEST-EXEC: btest-diff output
|
||||||
|
|
||||||
|
@load base/protocols/redis
|
||||||
|
|
||||||
|
event Redis::command(c: connection, command: Redis::Command)
|
||||||
|
{
|
||||||
|
print "BAD", command;
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::reply(c: connection, dat: Redis::ReplyData)
|
||||||
|
{
|
||||||
|
print "BAD", dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
event Redis::error(c: connection, dat: Redis::ReplyData)
|
||||||
|
{
|
||||||
|
print "BAD", dat;
|
||||||
|
}
|
10
testing/btest/scripts/base/protocols/redis/stream.zeek
Normal file
10
testing/btest/scripts/base/protocols/redis/stream.zeek
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# @TEST-DOC: Test Zeek parsing pubsub commands
|
||||||
|
# @TEST-REQUIRES: have-spicy
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b -r $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
|
|
@ -1 +1 @@
|
||||||
d20f3027e30434d340f1d3b45b5f86c84e5c74e0
|
f7c740ab3c2781252ab7d0620715091f6b61ae5d
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue