output/jsonbuilder: helper function SCJbSetPrintAsciiString

To replace C PrintStringsToBuffer and avoid a stack alloc
+ copy

Ticket: 8004
pull/14238/head
Philippe Antoine 5 days ago committed by Victor Julien
parent 7e705269e0
commit 7447651fa0

@ -563,6 +563,52 @@ impl JsonBuilder {
}
}
/// Set a key with a string value taking only ascii-printable bytes.
/// Non-printable characters are replaced by a dot `.`, except
/// CR and LF which are escaped the regular json way \r and \n
pub fn set_print_ascii(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
match self.current_state() {
State::ObjectNth => {
self.push(',')?;
}
State::ObjectFirst => {
self.set_state(State::ObjectNth);
}
_ => {
debug_validate_fail!("invalid state");
return Err(JsonError::InvalidState);
}
}
self.push('"')?;
self.push_str(key)?;
self.push_str("\":\"")?;
for &x in val.iter() {
match x {
b'\r' => {
self.push_str("\\r")?;
}
b'\n'=> {
self.push_str("\\n")?;
}
b'"'=> {
self.push_str("\\\"")?;
}
b'\\'=> {
self.push_str("\\\\")?;
}
_ => {
if !x.is_ascii() || x.is_ascii_control() {
self.push('.')?;
} else {
self.push(x as char)?;
}
}
}
}
self.push('"')?;
Ok(self)
}
/// Set a key and a string value (from bytes) on an object, with a limited size
pub fn set_string_from_bytes_limited(
&mut self, key: &str, val: &[u8], limit: usize,
@ -933,6 +979,20 @@ pub unsafe extern "C" fn SCJbSetStringFromBytes(
return false;
}
#[no_mangle]
pub unsafe extern "C" fn SCJbSetPrintAsciiString(
js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,
) -> bool {
if bytes.is_null() || len == 0 {
return false;
}
if let Ok(key) = CStr::from_ptr(key).to_str() {
let val = std::slice::from_raw_parts(bytes, len as usize);
return js.set_print_ascii(key, val).is_ok();
}
return false;
}
#[no_mangle]
pub unsafe extern "C" fn SCJbSetBase64(
js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,

@ -51,6 +51,11 @@ extern "C" {
js: *mut SCJsonBuilder, key: *const ::std::os::raw::c_char, bytes: *const u8, len: u32,
) -> bool;
}
extern "C" {
pub fn SCJbSetPrintAsciiString(
js: *mut SCJsonBuilder, key: *const ::std::os::raw::c_char, bytes: *const u8, len: u32,
) -> bool;
}
extern "C" {
pub fn SCJbSetBase64(
js: *mut SCJsonBuilder, key: *const ::std::os::raw::c_char, bytes: *const u8, len: u32,

@ -315,13 +315,7 @@ static void AlertAddPayload(AlertJsonOutputCtx *json_output_ctx, SCJsonBuilder *
}
if (json_output_ctx->flags & LOG_JSON_PAYLOAD) {
uint8_t printable_buf[p->payload_len + 1];
uint32_t offset = 0;
PrintStringsToBuffer(printable_buf, &offset,
p->payload_len + 1,
p->payload, p->payload_len);
printable_buf[p->payload_len] = '\0';
SCJbSetString(js, "payload_printable", (char *)printable_buf);
SCJbSetPrintAsciiString(js, "payload_printable", p->payload, p->payload_len);
}
}
@ -638,11 +632,8 @@ static bool AlertJsonStreamData(const AlertJsonOutputCtx *json_output_ctx, JsonA
}
if (json_output_ctx->flags & LOG_JSON_PAYLOAD) {
uint8_t printable_buf[cbd.payload->offset + 1];
uint32_t offset = 0;
PrintStringsToBuffer(printable_buf, &offset, cbd.payload->offset + 1,
cbd.payload->buffer, cbd.payload->offset);
SCJbSetString(jb, "payload_printable", (char *)printable_buf);
SCJbSetPrintAsciiString(
jb, "payload_printable", cbd.payload->buffer, cbd.payload->offset);
}
return true;
}

@ -200,11 +200,7 @@ static void FrameAddPayloadTCP(Flow *f, const TcpSession *ssn, const TcpStream *
if (cbd.payload->offset) {
SCJbSetBase64(jb, "payload", cbd.payload->buffer, cbd.payload->offset);
uint8_t printable_buf[cbd.payload->offset + 1];
uint32_t offset = 0;
PrintStringsToBuffer(printable_buf, &offset, cbd.payload->offset + 1, cbd.payload->buffer,
cbd.payload->offset);
SCJbSetString(jb, "payload_printable", (char *)printable_buf);
SCJbSetPrintAsciiString(jb, "payload_printable", cbd.payload->buffer, cbd.payload->offset);
SCJbSetBool(jb, "complete", complete);
}
}
@ -233,11 +229,7 @@ static void FrameAddPayloadUDP(SCJsonBuilder *js, const Packet *p, const Frame *
const uint32_t log_data_len = MIN(data_len, 256);
SCJbSetBase64(js, "payload", data, log_data_len);
uint8_t printable_buf[log_data_len + 1];
uint32_t o = 0;
PrintStringsToBuffer(printable_buf, &o, log_data_len + 1, data, log_data_len);
printable_buf[log_data_len] = '\0';
SCJbSetString(js, "payload_printable", (char *)printable_buf);
SCJbSetPrintAsciiString(js, "payload_printable", data, log_data_len);
#if 0
char pretty_buf[data_len * 4 + 1];
pretty_buf[0] = '\0';

@ -370,7 +370,6 @@ static void EveHttpLogJSONHeaders(
static void BodyPrintableBuffer(SCJsonBuilder *js, HtpBody *body, const char *key)
{
if (body->sb != NULL && body->sb->region.buf != NULL) {
uint32_t offset = 0;
const uint8_t *body_data;
uint32_t body_data_len;
uint64_t body_offset;
@ -380,11 +379,7 @@ static void BodyPrintableBuffer(SCJsonBuilder *js, HtpBody *body, const char *ke
return;
}
uint8_t printable_buf[body_data_len + 1];
PrintStringsToBuffer(printable_buf, &offset, body_data_len + 1, body_data, body_data_len);
if (offset > 0) {
SCJbSetString(js, key, (char *)printable_buf);
}
SCJbSetPrintAsciiString(js, key, body_data, body_data_len);
}
}

@ -200,18 +200,10 @@ static void EveAddPacketVars(const Packet *p, SCJsonBuilder *js_vars)
uint32_t offset = 0;
uint8_t keybuf[pv->key_len + 1];
PrintStringsToBuffer(keybuf, &offset, pv->key_len + 1, pv->key, pv->key_len);
uint32_t len = pv->value_len;
uint8_t printable_buf[len + 1];
offset = 0;
PrintStringsToBuffer(printable_buf, &offset, len + 1, pv->value, pv->value_len);
SCJbSetString(js_vars, (char *)keybuf, (char *)printable_buf);
SCJbSetPrintAsciiString(js_vars, (char *)keybuf, pv->value, pv->value_len);
} else {
const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR);
uint32_t len = pv->value_len;
uint8_t printable_buf[len + 1];
uint32_t offset = 0;
PrintStringsToBuffer(printable_buf, &offset, len + 1, pv->value, pv->value_len);
SCJbSetString(js_vars, varname, (char *)printable_buf);
SCJbSetPrintAsciiString(js_vars, varname, pv->value, pv->value_len);
}
SCJbClose(js_vars);
}
@ -263,14 +255,9 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
break;
}
uint32_t len = fv->data.fv_str.value_len;
uint8_t printable_buf[len + 1];
uint32_t offset = 0;
PrintStringsToBuffer(printable_buf, &offset, len + 1, fv->data.fv_str.value,
fv->data.fv_str.value_len);
SCJbStartObject(js_flowvars);
SCJbSetString(js_flowvars, varname, (char *)printable_buf);
SCJbSetPrintAsciiString(
js_flowvars, varname, fv->data.fv_str.value, fv->data.fv_str.value_len);
SCJbClose(js_flowvars);
}
} else if (fv->datatype == FLOWVAR_TYPE_STR && fv->key != NULL) {
@ -284,14 +271,9 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
uint32_t offset = 0;
PrintStringsToBuffer(keybuf, &offset, fv->keylen + 1, fv->key, fv->keylen);
uint32_t len = fv->data.fv_str.value_len;
uint8_t printable_buf[len + 1];
offset = 0;
PrintStringsToBuffer(printable_buf, &offset, len + 1, fv->data.fv_str.value,
fv->data.fv_str.value_len);
SCJbStartObject(js_flowvars);
SCJbSetString(js_flowvars, (const char *)keybuf, (char *)printable_buf);
SCJbSetPrintAsciiString(js_flowvars, (const char *)keybuf, fv->data.fv_str.value,
fv->data.fv_str.value_len);
SCJbClose(js_flowvars);
} else if (fv->datatype == FLOWVAR_TYPE_FLOAT) {
const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_FLOAT);

Loading…
Cancel
Save