From f29bc2f772ac4a880e2d20eb8e72eaac2877bc02 Mon Sep 17 00:00:00 2001 From: Adrian Serrano Date: Fri, 20 Mar 2020 18:31:46 +0100 Subject: [PATCH] fix #14872: fix incorrectly handle with two-words redis command (#14873) (#17153) Updated redis protocol decoder to support two-word commands. Fixes #14872 (cherry picked from commit 30a5687e8929574923065ee9c9affa205b7e0697) Co-authored-by: shawshank --- CHANGELOG.next.asciidoc | 1 + packetbeat/protos/redis/redis_parse.go | 20 ++++++++++++++++---- packetbeat/protos/redis/redis_test.go | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index c0549a7c0101..5a7951dcc74c 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -55,6 +55,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - TLS: The behavior of send_certificates and include_raw_certificates options has changed. {pull}15497[15497] - Added redact_headers configuration option, to allow HTTP request headers to be redacted whilst keeping the header field included in the beat. {pull}15353[15353] - Add dns.question.subdomain and dns.question.top_level_domain fields. {pull}14578[14578] +- Redis: fix incorrectly handle with two-words redis command. {issue}14872[14872] {pull}14873[14873] *Winlogbeat* diff --git a/packetbeat/protos/redis/redis_parse.go b/packetbeat/protos/redis/redis_parse.go index c99679a1ba6f..321f022ad0d1 100644 --- a/packetbeat/protos/redis/redis_parse.go +++ b/packetbeat/protos/redis/redis_parse.go @@ -18,6 +18,7 @@ package redis import ( + "bytes" "time" "github.com/elastic/beats/v7/libbeat/common" @@ -423,11 +424,22 @@ func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (common.NetString, } // handle top-level request command - if depth == 0 && isRedisCommand(content[0]) { + var oneWordCommand, twoWordsCommand bool + oneWordCommand = isRedisCommand(content[0]) + twoWordsCommand = count > 1 && isRedisCommand(bytes.Join(content[0:2], []byte(" "))) + + if depth == 0 && (oneWordCommand || twoWordsCommand) { p.message.isRequest = true - p.message.method = content[0] - if len(content) > 1 { - p.message.path = content[1] + if oneWordCommand { + p.message.method = content[0] + if len(content) > 1 { + p.message.path = content[1] + } + } else if twoWordsCommand { + p.message.method = bytes.Join(content[0:2], []byte(" ")) + if len(content) > 2 { + p.message.path = content[2] + } } var value common.NetString diff --git a/packetbeat/protos/redis/redis_test.go b/packetbeat/protos/redis/redis_test.go index 7e0b91b1e885..9916c100852e 100644 --- a/packetbeat/protos/redis/redis_test.go +++ b/packetbeat/protos/redis/redis_test.go @@ -67,9 +67,31 @@ func TestRedisParser_ArrayRequest(t *testing.T) { assert.True(t, complete) assert.True(t, msg.isRequest) assert.Equal(t, "SET key1 Hello", string(msg.message)) + assert.Equal(t, "SET", string(msg.method)) + assert.Equal(t, "key1", string(msg.path)) assert.Equal(t, len(arrayRequest), msg.size) } +var arrayRequest2 = []byte("*3\r\n" + + "$6\r\n" + + "CONFIG\r\n" + + "$3\r\n" + + "GET\r\n" + + "$1\r\n" + + "*\r\n") + +func TestRedisParser_ArrayRequest2(t *testing.T) { + msg, ok, complete := parse(arrayRequest2) + + assert.True(t, ok) + assert.True(t, complete) + assert.True(t, msg.isRequest) + assert.Equal(t, "CONFIG GET *", string(msg.message)) + assert.Equal(t, "CONFIG GET", string(msg.method)) + assert.Equal(t, "*", string(msg.path)) + assert.Equal(t, len(arrayRequest2), msg.size) +} + var arrayResponse = []byte("*4\r\n" + "$3\r\n" + "foo\r\n" +