5
#include "logpatterns.h"
21
#define BOOL(x) ((x) ? "TRUE" : "FALSE")
23
static gchar *full_colors[] =
25
"\33[01;34m", /* blue */
26
"\33[01;33m", /* yellow */
27
"\33[01;32m", /* green */
28
"\33[01;31m" /* red */
31
static gchar *empty_colors[] =
37
#define COLOR_YELLOW 1
41
static gchar *no_color = "\33[01;0m";
42
static gchar **colors = empty_colors;
45
static gchar *patterndb_file = PATH_PATTERNDB_FILE;
46
static gboolean color_out = FALSE;
48
static gchar *merge_dir = NULL;
50
typedef struct _PdbToolMergeState
58
pdbtool_merge_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names,
59
const gchar **attribute_values, gpointer user_data, GError **error)
61
PdbToolMergeState *state = (PdbToolMergeState *) user_data;
65
if (g_str_equal(element_name, "patterndb"))
67
for (i = 0; attribute_names[i]; i++)
69
if (g_str_equal(attribute_names[i], "version"))
70
state->version = strtol(attribute_values[i], NULL, 10);
74
else if (g_str_equal(element_name, "rule"))
75
state->in_rule = TRUE;
77
if (g_str_equal(element_name, "program"))
78
g_string_append(state->merged, "<ruleset");
79
else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "pattern"))
80
g_string_append_printf(state->merged, "<patterns>\n<%s", element_name);
81
else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "url"))
82
g_string_append_printf(state->merged, "<urls>\n<%s", element_name);
84
g_string_append_printf(state->merged, "<%s", element_name);
86
for (i = 0; attribute_names[i]; i++)
88
buff = g_markup_printf_escaped(" %s='%s'", attribute_names[i], attribute_values[i]);
89
g_string_append_printf(state->merged, "%s", buff);
93
g_string_append(state->merged, ">");
98
pdbtool_merge_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
100
PdbToolMergeState *state = (PdbToolMergeState *) user_data;
102
if (g_str_equal(element_name, "patterndb"))
104
else if (g_str_equal(element_name, "rule"))
105
state->in_rule = FALSE;
107
if (g_str_equal(element_name, "program"))
108
g_string_append(state->merged, "</ruleset>");
109
else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "pattern"))
110
g_string_append_printf(state->merged, "</%s>\n</patterns>", element_name);
111
else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "url"))
112
g_string_append_printf(state->merged, "</%s>\n</urls>", element_name);
114
g_string_append_printf(state->merged, "</%s>", element_name);
118
pdbtool_merge_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
120
PdbToolMergeState *state = (PdbToolMergeState *) user_data;
121
gchar *buff = g_markup_printf_escaped("%s", text);
123
g_string_append(state->merged, buff);
128
GMarkupParser pdbtool_merge_parser =
130
.start_element = pdbtool_merge_start_element,
131
.end_element = pdbtool_merge_end_element,
132
.text = pdbtool_merge_text,
138
pdbtool_merge_file(const gchar *filename, GString *merged)
140
GMarkupParseContext *parse_ctx = NULL;
141
gchar *full_name = g_build_filename(merge_dir, filename, NULL);
142
PdbToolMergeState state;
143
GError *error = NULL;
144
gboolean success = TRUE;
148
if (!g_file_get_contents(full_name, &buff, &buff_len, &error))
150
fprintf(stderr, "Error reading pattern database file; filename='%s', error='%s'\n",
151
filename, error ? error->message : "Unknown error");
157
state.merged = merged;
158
state.in_rule = FALSE;
160
parse_ctx = g_markup_parse_context_new(&pdbtool_merge_parser, 0, &state, NULL);
161
if (!g_markup_parse_context_parse(parse_ctx, buff, buff_len, &error))
163
fprintf(stderr, "Error parsing pattern database file; filename='%s', error='%s'\n",
164
filename, error ? error->message : "Unknown error");
169
if (!g_markup_parse_context_end_parse(parse_ctx, &error))
171
fprintf(stderr, "Error parsing pattern database file; filename='%s', error='%s'\n",
172
filename, error ? error->message : "Unknown error");
184
g_markup_parse_context_free(parse_ctx);
190
pdbtool_merge(int argc, char *argv[])
194
const gchar *filename;
195
GError *error = NULL;
196
GString *merged = NULL;
202
fprintf(stderr, "No directory is specified to merge from\n");
208
fprintf(stderr, "No patterndb file is specified to merge to\n");
212
if ((pdb_dir = g_dir_open(merge_dir, 0, &error)) == NULL)
214
fprintf(stderr, "Error opening patterndb directory; errror='%s'\n", error ? error->message : "Unknown error");
218
merged = g_string_sized_new(4096);
219
g_date_clear(&date, 1);
220
g_date_set_time_t(&date, time (NULL));
222
buff = g_markup_printf_escaped("<?xml version='1.0' encoding='UTF-8'?>\n<patterndb version='3' pub_date='%04d-%02d-%02d'>",
223
g_date_get_year(&date), g_date_get_month(&date), g_date_get_day(&date));
224
g_string_append(merged, buff);
227
while ((filename = g_dir_read_name(pdb_dir)) != NULL && ok)
228
ok = pdbtool_merge_file(filename, merged);
230
g_dir_close(pdb_dir);
232
g_string_append(merged, "</patterndb>\n");
235
if (!g_file_set_contents(patterndb_file, merged->str, merged->len, &error))
237
fprintf(stderr, "Error storing patterndb; filename='%s', errror='%s'\n", patterndb_file, error ? error->message : "Unknown error");
241
g_string_free(merged, TRUE);
246
static GOptionEntry merge_options[] =
248
{ "directory", 'D', 0, G_OPTION_ARG_STRING, &merge_dir,
249
"Directory from merge pattern databases", "<directory>" },
250
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
253
static gchar *match_program = NULL;
254
static gchar *match_message = NULL;
255
static gboolean debug_pattern = FALSE;
256
static gboolean debug_pattern_parse = FALSE;
259
pdbtool_match_values(NVHandle handle, const gchar *name, const gchar *value, gssize length, gpointer user_data)
261
gint *ret = user_data;
263
printf("%s=%.*s\n", name, (gint) length, value);
264
if (g_str_equal(name, ".classifier.rule_id"))
270
pdbtool_match(int argc, char *argv[])
272
LogPatternDatabase patterndb;
273
LogMessage *msg = log_msg_new_empty();
274
GSList *dbg_list = NULL, *p;
275
RDebugInfo *dbg_info;
283
fprintf(stderr, "No message is given\n");
287
memset(&patterndb, 0x0, sizeof(LogPatternDatabase));
289
if (!log_pattern_database_load(&patterndb, patterndb_file))
292
log_msg_set_value(msg, LM_V_MESSAGE, match_message, strlen(match_message));
293
if (match_program && match_program[0])
294
log_msg_set_value(msg, LM_V_PROGRAM, match_program, strlen(match_program));
296
log_db_parser_process_lookup(&patterndb, msg, debug_pattern ? &dbg_list : NULL);
298
if (debug_pattern && !debug_pattern_parse)
300
printf("Pattern matching part:\n");
310
name = nv_registry_get_handle_name(logmsg_registry, dbg_info->pnode->handle, &name_len);
312
printf("%s@%s:%s=%.*s@%s",
313
colors[COLOR_YELLOW],
314
r_parser_type_name(dbg_info->pnode->type),
315
name_len ? name : "",
316
name_len ? dbg_info->match_len : 0,
317
name_len ? match_message + dbg_info->match_off : "",
321
else if (dbg_info->i == dbg_info->node->keylen)
323
printf("%s%s%s", colors[COLOR_GREEN], dbg_info->node->key, no_color);
327
printf("%s%.*s%s", colors[COLOR_RED], dbg_info->i, dbg_info->node->key, no_color);
332
printf("%s%s%s", colors[COLOR_BLUE], match_message + pos, no_color);
334
printf("\nMatching part:\n");
337
if (debug_pattern && debug_pattern_parse)
338
printf("PDBTOOL_HEADER=i:len:key;keylen:match_off;match_len:parser_type:parser_name\n");
343
/* NOTE: if i is smaller than node->keylen than we did not match the full node
344
* so matching failed on this node, we need to highlight it somehow
346
dbg_info = dbg_list->data;
347
if (debug_pattern_parse)
350
name = nv_registry_get_handle_name(logmsg_registry, dbg_info->pnode->handle, &name_len);
352
printf("PDBTOOL_DEBUG=%d:%d:%d:%d:%d:%s:%s\n",
353
i++, dbg_info->i, dbg_info->node->keylen, dbg_info->match_off, dbg_info->match_len,
354
dbg_info->pnode ? r_parser_type_name(dbg_info->pnode->type) : "",
355
dbg_info->pnode && name_len ? name : ""
360
if (dbg_info->i == dbg_info->node->keylen || dbg_info->pnode)
361
printf("%s%.*s%s", dbg_info->pnode ? colors[COLOR_YELLOW] : colors[COLOR_GREEN], dbg_info->i, match_message + pos, no_color);
363
printf("%s%.*s%s", colors[COLOR_RED], dbg_info->i, match_message + pos, no_color);
368
dbg_list = g_slist_delete_link(dbg_list, dbg_list);
371
if (debug_pattern && !debug_pattern_parse)
372
printf("\nValues:\n");
374
nv_table_foreach(msg->payload, logmsg_registry, pdbtool_match_values, &ret);
376
log_pattern_database_free(&patterndb);
381
static GOptionEntry match_options[] =
383
{ "program", 'P', 0, G_OPTION_ARG_STRING, &match_program,
384
"Program name to match as $PROGRAM", "<program>" },
385
{ "message", 'M', 0, G_OPTION_ARG_STRING, &match_message,
386
"Message to match as $MSG", "<message>" },
387
{ "debug-pattern", 'D', 0, G_OPTION_ARG_NONE, &debug_pattern,
388
"Print debuging information on pattern matching", NULL },
389
{ "csv-out", 'C', 0, G_OPTION_ARG_NONE, &debug_pattern_parse,
390
"Output debuging information in parseable format", NULL },
391
{ "color-out", 'c', 0, G_OPTION_ARG_NONE, &color_out,
392
"Color terminal output", NULL },
393
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
396
static gboolean dump_program_tree = FALSE;
399
pdbtool_walk_tree(RNode *root, gint level, gboolean program)
403
for (i = 0; i < level; i++)
407
printf("@%s:%s@ ", r_parser_type_name(root->parser->type), log_msg_get_value_name(root->parser->handle, NULL));
408
printf("'%s' ", root->key ? root->key : "");
413
printf("rule_id='%s'", ((LogDBResult*)root->value)->rule_id);
420
for (i = 0; i < root->num_children; i++)
421
pdbtool_walk_tree(root->children[i], level + 1, program);
423
for (i = 0; i < root->num_pchildren; i++)
424
pdbtool_walk_tree(root->pchildren[i], level + 1, program);
428
pdbtool_dump(int argc, char *argv[])
430
LogPatternDatabase patterndb;
432
memset(&patterndb, 0x0, sizeof(LogPatternDatabase));
434
if (!log_pattern_database_load(&patterndb, patterndb_file))
437
if (dump_program_tree)
438
pdbtool_walk_tree(patterndb.programs, 0, TRUE);
439
else if (match_program)
441
RNode *ruleset = r_find_node(patterndb.programs, g_strdup(match_program), g_strdup(match_program), strlen(match_program), NULL);
442
if (ruleset && ruleset->value)
443
pdbtool_walk_tree(((LogDBProgram *)ruleset->value)->rules, 0, FALSE);
449
static GOptionEntry dump_options[] =
451
{ "program", 'P', 0, G_OPTION_ARG_STRING, &match_program,
452
"Program name ($PROGRAM) to dump", "<program>" },
453
{ "program-tree", 'T', 0, G_OPTION_ARG_NONE, &dump_program_tree,
454
"Dump the program ($PROGRAM) tree", NULL },
455
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
461
pdbtool_mode(int *argc, char **argv[])
466
for (i = 1; i < (*argc); i++)
468
if ((*argv)[i][0] != '-')
471
memmove(&(*argv)[i], &(*argv)[i+1], ((*argc) - i) * sizeof(gchar *));
479
static GOptionEntry pdbtool_options[] =
481
{ "pdb", 'p', 0, G_OPTION_ARG_STRING, &patterndb_file,
482
"Name of the patterndb file", "<patterndb_file>" },
483
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
489
const GOptionEntry *options;
490
const gchar *description;
491
gint (*main)(gint argc, gchar *argv[]);
494
{ "match", match_options, "Match a message against the pattern database", pdbtool_match },
495
{ "dump", dump_options, "Dump pattern datebase tree", pdbtool_dump },
496
{ "merge", merge_options, "Merge pattern databases", pdbtool_merge },
505
fprintf(stderr, "Syntax: pdbtool <command> [options]\nPossible commands are:\n");
506
for (mode = 0; modes[mode].mode; mode++)
508
fprintf(stderr, " %-12s %s\n", modes[mode].mode, modes[mode].description);
514
main(int argc, char *argv[])
516
const gchar *mode_string;
519
GError *error = NULL;
523
log_msg_registry_init();
524
log_db_parser_global_init();
525
mode_string = pdbtool_mode(&argc, &argv);
532
for (mode = 0; modes[mode].mode; mode++)
534
if (strcmp(modes[mode].mode, mode_string) == 0)
536
ctx = g_option_context_new(mode_string);
537
g_option_context_set_summary(ctx, modes[mode].description);
538
g_option_context_add_main_entries(ctx, modes[mode].options, NULL);
539
g_option_context_add_main_entries(ctx, pdbtool_options, NULL);
540
msg_add_option_group(ctx);
546
fprintf(stderr, "Unknown command\n");
550
setlocale(LC_ALL, "");
551
if (!g_option_context_parse(ctx, &argc, &argv, &error))
553
fprintf(stderr, "Error parsing command line arguments: %s\n", error ? error->message : "Invalid arguments");
554
g_clear_error(&error);
555
g_option_context_free(ctx);
558
g_option_context_free(ctx);
563
colors = full_colors;
565
ret = modes[mode].main(argc, argv);