If a field value contains the separator, that is now escape with hex

characters.
This commit is contained in:
Robin Sommer 2011-03-09 16:26:11 -08:00
parent c6d20dbfdf
commit cb9e0a5d5a
6 changed files with 96 additions and 4 deletions

View file

@ -41,6 +41,8 @@ ODesc::ODesc(desc_type t, BroFile* arg_f)
want_quotes = 0; want_quotes = 0;
do_flush = 1; do_flush = 1;
include_stats = 0; include_stats = 0;
escape = 0;
escape_len = 0;
} }
ODesc::~ODesc() ODesc::~ODesc()
@ -54,6 +56,12 @@ ODesc::~ODesc()
free(base); free(base);
} }
void ODesc::SetEscape(const char* arg_escape, int len)
{
escape = arg_escape;
escape_len = len;
}
void ODesc::PushIndent() void ODesc::PushIndent()
{ {
++indent_level; ++indent_level;
@ -183,8 +191,44 @@ void ODesc::Indent()
Add("\t", 0); Add("\t", 0);
} }
static const char hex_chars[] = "0123456789ABCDEF";
void ODesc::AddBytes(const void* bytes, unsigned int n) void ODesc::AddBytes(const void* bytes, unsigned int n)
{
if ( ! escape )
return AddBytesRaw(bytes, n);
const char* s = (const char*) bytes;
const char* e = (const char*) bytes + n;
while ( s < e )
{
const char* t = (const char*) memchr(s, escape[0], e - s);
if ( ! t )
break;
if ( memcmp(t, escape, escape_len) != 0 )
break;
AddBytesRaw(s, t - s);
for ( int i = 0; i < escape_len; ++i )
{
char hex[5] = "\\x00";
hex[2] = hex_chars[(*t) >> 4];
hex[3] = hex_chars[(*t) & 0x0f];
AddBytesRaw(hex, sizeof(hex));
++t;
}
s = t;
}
AddBytesRaw(s, e - s);
}
void ODesc::AddBytesRaw(const void* bytes, unsigned int n)
{ {
if ( n == 0 ) if ( n == 0 )
return; return;

View file

@ -49,6 +49,9 @@ public:
void SetFlush(int arg_do_flush) { do_flush = arg_do_flush; } void SetFlush(int arg_do_flush) { do_flush = arg_do_flush; }
// The string passed in must remain valid as long as this object lives.
void SetEscape(const char* escape, int len);
void PushIndent(); void PushIndent();
void PopIndent(); void PopIndent();
int GetIndentLevel() const { return indent_level; } int GetIndentLevel() const { return indent_level; }
@ -93,6 +96,9 @@ public:
Add("\n", 0); Add("\n", 0);
} }
// Bypasses the escaping enabled via SetEscape().
void AddRaw(const char* s, int len) { AddBytesRaw(s, len); }
// Returns the description as a string. // Returns the description as a string.
const char* Description() const { return (const char*) base; } const char* Description() const { return (const char*) base; }
@ -115,6 +121,7 @@ protected:
void Indent(); void Indent();
void AddBytes(const void* bytes, unsigned int n); void AddBytes(const void* bytes, unsigned int n);
void AddBytesRaw(const void* bytes, unsigned int n);
// Make buffer big enough for n bytes beyond bufp. // Make buffer big enough for n bytes beyond bufp.
void Grow(unsigned int n); void Grow(unsigned int n);
@ -128,6 +135,9 @@ protected:
unsigned int offset; // where we are in the buffer unsigned int offset; // where we are in the buffer
unsigned int size; // size of buffer in bytes unsigned int size; // size of buffer in bytes
int escape_len; // number of bytes in to escape sequence
const char* escape; // bytes to escape on output
BroFile* f; // or the file we're using. BroFile* f; // or the file we're using.
int indent_level; int indent_level;

View file

@ -11,7 +11,10 @@ LogWriterAscii::LogWriterAscii()
output_to_stdout = BifConst::LogAscii::output_to_stdout; output_to_stdout = BifConst::LogAscii::output_to_stdout;
include_header = BifConst::LogAscii::include_header; include_header = BifConst::LogAscii::include_header;
separator = strdup(BifConst::LogAscii::separator->CheckString());
separator_len = BifConst::LogAscii::separator->Len();
separator = new char[separator_len];
memcpy(separator, BifConst::LogAscii::separator->Bytes(), separator_len);
} }
LogWriterAscii::~LogWriterAscii() LogWriterAscii::~LogWriterAscii()
@ -19,7 +22,7 @@ LogWriterAscii::~LogWriterAscii()
if ( file ) if ( file )
fclose(file); fclose(file);
free(separator); delete [] separator;
} }
bool LogWriterAscii::DoInit(string path, int num_fields, const LogField* const * fields) bool LogWriterAscii::DoInit(string path, int num_fields, const LogField* const * fields)
@ -46,7 +49,7 @@ bool LogWriterAscii::DoInit(string path, int num_fields, const LogField* const *
if ( fputs(field->name.c_str(), file) == EOF ) if ( fputs(field->name.c_str(), file) == EOF )
goto write_error; goto write_error;
if ( fputs(separator, file) == EOF ) if ( fwrite(separator, separator_len, 1, file) != 1 )
goto write_error; goto write_error;
} }
@ -74,11 +77,12 @@ void LogWriterAscii::DoFinish()
bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, LogVal** vals) bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, LogVal** vals)
{ {
ODesc desc(DESC_READABLE); ODesc desc(DESC_READABLE);
desc.SetEscape(separator, separator_len);
for ( int i = 0; i < num_fields; i++ ) for ( int i = 0; i < num_fields; i++ )
{ {
if ( i > 0 ) if ( i > 0 )
desc.Add(separator); desc.AddRaw(separator, separator_len);
LogVal* val = vals[i]; LogVal* val = vals[i];
const LogField* field = fields[i]; const LogField* field = fields[i];

View file

@ -32,6 +32,7 @@ private:
bool output_to_stdout; bool output_to_stdout;
bool include_header; bool include_header;
char* separator; char* separator;
int separator_len;
}; };
#endif #endif

Binary file not shown.

View file

@ -0,0 +1,33 @@
#
# @TEST-EXEC: bro %INPUT
# @TEST-EXEC: btest-diff ssh.log
redef LogAscii::separator = "||";
module SSH;
export {
redef enum Log::ID += { SSH };
type Log: record {
t: time;
id: conn_id; # Will be rolled out into individual columns.
status: string &optional;
country: string &default="unknown";
};
}
event bro_init()
{
Log::create_stream(SSH, [$columns=Log]);
local cid = [$orig_h=1.2.3.4, $orig_p=1234/tcp, $resp_h=2.3.4.5, $resp_p=80/tcp];
Log::write(SSH, [$t=network_time(), $id=cid, $status="success"]);
Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="US"]);
Log::write(SSH, [$t=network_time(), $id=cid, $status="fa||ure", $country="UK"]);
Log::write(SSH, [$t=network_time(), $id=cid, $status="su||ess", $country="BR"]);
Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="MX"]);
}