/* \summary: REdis Serialization Protocol (RESP) printer */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
#include "netdissect.h"
#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
#include "extract.h"
-static const char tstr[] = " [|RESP]";
/*
- * For information regarding RESP, see: http://redis.io/topics/protocol
+ * For information regarding RESP, see: https://redis.io/topics/protocol
*/
#define RESP_SIMPLE_STRING '+'
#define RESP_BULK_STRING '$'
#define RESP_ARRAY '*'
-#define resp_print_empty(ndo) ND_PRINT((ndo, " empty"))
-#define resp_print_null(ndo) ND_PRINT((ndo, " null"))
-#define resp_print_length_too_large(ndo) ND_PRINT((ndo, " length too large"))
-#define resp_print_length_negative(ndo) ND_PRINT((ndo, " length negative and not -1"))
-#define resp_print_invalid(ndo) ND_PRINT((ndo, " invalid"))
+#define resp_print_empty(ndo) ND_PRINT(" empty")
+#define resp_print_null(ndo) ND_PRINT(" null")
+#define resp_print_length_too_large(ndo) ND_PRINT(" length too large")
+#define resp_print_length_negative(ndo) ND_PRINT(" length negative and not -1")
+#define resp_print_invalid(ndo) ND_PRINT(" invalid")
-void resp_print(netdissect_options *, const u_char *, u_int);
static int resp_parse(netdissect_options *, const u_char *, int);
static int resp_print_string_error_integer(netdissect_options *, const u_char *, int);
static int resp_print_simple_string(netdissect_options *, const u_char *, int);
#define FIND_CRLF(_ptr, _len) \
for (;;) { \
LCHECK2(_len, 2); \
- ND_TCHECK_2(_ptr); \
- if (*_ptr == '\r' && *(_ptr+1) == '\n') \
+ ND_TCHECK_2(_ptr); \
+ if (GET_U_1(_ptr) == '\r' && \
+ GET_U_1(_ptr+1) == '\n') \
break; \
_ptr++; \
_len--; \
#define FIND_CR_OR_LF(_ptr, _len) \
for (;;) { \
LCHECK(_len); \
- ND_TCHECK(*_ptr); \
- if (*_ptr == '\r' || *_ptr == '\n') \
+ if (GET_U_1(_ptr) == '\r' || \
+ GET_U_1(_ptr) == '\n') \
break; \
_ptr++; \
_len--; \
/* \
* Have we hit the end of data? \
*/ \
- if (_len == 0 || !ND_TTEST(*_ptr)) { \
+ if (_len == 0 || !ND_TTEST_1(_ptr)) {\
/* \
* Yes. Have we seen a \r \
* or \n? \
*/ \
goto trunc; \
} \
- if (*_ptr != '\r' && *_ptr != '\n') \
+ if (GET_U_1(_ptr) != '\r' && \
+ GET_U_1(_ptr) != '\n') \
break; \
_found_cr_or_lf = 1; \
_ptr++; \
* TEST_RET_LEN
* If ret_len is < 0, jump to the trunc tag which returns (-1)
* and 'bubbles up' to printing tstr. Otherwise, return ret_len.
+ *
+ * Note that using this macro with a semicolon at the end emits a warning from
+ * Sun C about an unreachable statement (the semicolon is the statement).
*/
#define TEST_RET_LEN(rl) \
if (rl < 0) { goto trunc; } else { return rl; }
* Assumes the data has already been verified as present.
*/
#define RESP_PRINT_SEGMENT(_ndo, _bp, _len) \
- ND_PRINT((_ndo, " \"")); \
- if (fn_printn(_ndo, _bp, _len, _ndo->ndo_snapend)) \
+ ND_PRINT(" \""); \
+ if (nd_printn(_ndo, _bp, _len, _ndo->ndo_snapend)) \
goto trunc; \
- fn_print_char(_ndo, '"');
+ ND_PRINT("\"");
void
resp_print(netdissect_options *ndo, const u_char *bp, u_int length)
{
- int ret_len = 0, length_cur = length;
+ int ret_len = 0;
- if(!bp || length <= 0)
- return;
+ ndo->ndo_protocol = "resp";
- ND_PRINT((ndo, ": RESP"));
- while (length_cur > 0) {
+ ND_PRINT(": RESP");
+ while (length != 0) {
/*
* This block supports redis pipelining.
* For example, multiple operations can be pipelined within the same string:
* In order to handle this case, we must try and parse 'bp' until
* 'length' bytes have been processed or we reach a trunc condition.
*/
- ret_len = resp_parse(ndo, bp, length_cur);
+ ret_len = resp_parse(ndo, bp, length);
TEST_RET_LEN_NORETURN(ret_len);
bp += ret_len;
- length_cur -= ret_len;
+ length -= ret_len;
}
return;
trunc:
- ND_PRINT((ndo, "%s", tstr));
+ nd_print_trunc(ndo);
}
static int
int ret_len;
LCHECK2(length, 1);
- ND_TCHECK_1(bp);
- op = EXTRACT_U_1(bp);
+ op = GET_U_1(bp);
/* bp now points to the op, so these routines must skip it */
switch(op) {
* including invalid packet errors; that's what we want, as
* we have to give up on further parsing in that case.
*/
- TEST_RET_LEN(ret_len);
+ TEST_RET_LEN(ret_len) // without a semicolon
trunc:
return (-1);
* preceding the \r\n. That includes the opcode, so don't print
* that.
*/
- len = (bp_ptr - bp);
+ len = ND_BYTES_BETWEEN(bp, bp_ptr);
RESP_PRINT_SEGMENT(ndo, bp, len);
ret_len = 1 /*<opcode>*/ + len /*<string>*/ + 2 /*<CRLF>*/;
- TEST_RET_LEN(ret_len);
+ TEST_RET_LEN(ret_len) // without a semicolon
trunc:
return (-1);
/*
* Found it; bp_ptr points to the \r or \n, so bp_ptr - bp is the
- * Length of the line text that preceeds it. Print it.
+ * Length of the line text that precedes it. Print it.
*/
- len = (bp_ptr - bp);
+ len = ND_BYTES_BETWEEN(bp, bp_ptr);
RESP_PRINT_SEGMENT(ndo, bp, len);
/*
if (len == 0)
goto trunc;
- ND_TCHECK_1(bp);
too_large = 0;
neg = 0;
- if (EXTRACT_U_1(bp) == '-') {
+ if (GET_U_1(bp) == '-') {
neg = 1;
bp++;
len--;
for (;;) {
if (len == 0)
goto trunc;
- ND_TCHECK_1(bp);
- c = EXTRACT_U_1(bp);
+ c = GET_U_1(bp);
if (!(c >= '0' && c <= '9')) {
if (!saw_digit) {
bp++;
* OK, we found a non-digit character. It should be a \r, followed
* by a \n.
*/
- if (EXTRACT_U_1(bp) != '\r') {
+ if (GET_U_1(bp) != '\r') {
bp++;
goto invalid;
}
len--;
if (len == 0)
goto trunc;
- ND_TCHECK_1(bp);
- if (EXTRACT_U_1(bp) != '\n') {
+ if (GET_U_1(bp) != '\n') {
bp++;
goto invalid;
}