|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* @file ptree.c
|
|
Packit |
1422b7 |
* @brief Implementation of the parse tree object.
|
|
Packit |
1422b7 |
* @class ln_ptree ptree.h
|
|
Packit |
1422b7 |
*//*
|
|
Packit |
1422b7 |
* Copyright 2010 by Rainer Gerhards and Adiscon GmbH.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Modified by Pavel Levshin (pavel@levshin.spb.ru) in 2013
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* This file is part of liblognorm.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
1422b7 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
1422b7 |
* License as published by the Free Software Foundation; either
|
|
Packit |
1422b7 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
1422b7 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
1422b7 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
1422b7 |
* Lesser General Public License for more details.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
1422b7 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
1422b7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* A copy of the LGPL v2.1 can be found in the file "COPYING" in this distribution.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#include "config.h"
|
|
Packit |
1422b7 |
#include <stdlib.h>
|
|
Packit |
1422b7 |
#include <stdio.h>
|
|
Packit |
1422b7 |
#include <stdarg.h>
|
|
Packit |
1422b7 |
#include <string.h>
|
|
Packit |
1422b7 |
#include <assert.h>
|
|
Packit |
1422b7 |
#include <ctype.h>
|
|
Packit |
1422b7 |
#include <libestr.h>
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#define LOGNORM_V1_SUBSYSTEM /* indicate we are old cruft */
|
|
Packit |
1422b7 |
#include "v1_liblognorm.h"
|
|
Packit |
1422b7 |
#include "annot.h"
|
|
Packit |
1422b7 |
#include "internal.h"
|
|
Packit |
1422b7 |
#include "lognorm.h"
|
|
Packit |
1422b7 |
#include "v1_ptree.h"
|
|
Packit |
1422b7 |
#include "v1_samp.h"
|
|
Packit |
1422b7 |
#include "v1_parser.h"
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Get base addr of common prefix. Takes length of prefix in account
|
|
Packit |
1422b7 |
* and selects the right buffer.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline unsigned char*
|
|
Packit |
1422b7 |
prefixBase(struct ln_ptree *tree)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
return (tree->lenPrefix <= sizeof(tree->prefix))
|
|
Packit |
1422b7 |
? tree->prefix.data : tree->prefix.ptr;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct ln_ptree*
|
|
Packit |
1422b7 |
ln_newPTree(ln_ctx ctx, struct ln_ptree **parentptr)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_ptree *tree;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((tree = calloc(1, sizeof(struct ln_ptree))) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
tree->parentptr = parentptr;
|
|
Packit |
1422b7 |
tree->ctx = ctx;
|
|
Packit |
1422b7 |
ctx->nNodes++;
|
|
Packit |
1422b7 |
done: return tree;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_deletePTreeNode(ln_fieldList_t *node)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_deletePTree(node->subtree);
|
|
Packit |
1422b7 |
es_deleteStr(node->name);
|
|
Packit |
1422b7 |
if(node->data != NULL)
|
|
Packit |
1422b7 |
es_deleteStr(node->data);
|
|
Packit |
1422b7 |
if(node->raw_data != NULL)
|
|
Packit |
1422b7 |
es_deleteStr(node->raw_data);
|
|
Packit |
1422b7 |
if(node->parser_data != NULL && node->parser_data_destructor != NULL)
|
|
Packit |
1422b7 |
node->parser_data_destructor(&(node->parser_data));
|
|
Packit |
1422b7 |
free(node);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_deletePTree(struct ln_ptree *tree)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_fieldList_t *node, *nextnode;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(tree == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(tree->tags != NULL)
|
|
Packit |
1422b7 |
json_object_put(tree->tags);
|
|
Packit |
1422b7 |
for(node = tree->froot; node != NULL; node = nextnode) {
|
|
Packit |
1422b7 |
nextnode = node->next;
|
|
Packit |
1422b7 |
ln_deletePTreeNode(node);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* need to free a large prefix buffer? */
|
|
Packit |
1422b7 |
if(tree->lenPrefix > sizeof(tree->prefix))
|
|
Packit |
1422b7 |
free(tree->prefix.ptr);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(i = 0 ; i < 256 ; ++i)
|
|
Packit |
1422b7 |
if(tree->subtree[i] != NULL)
|
|
Packit |
1422b7 |
ln_deletePTree(tree->subtree[i]);
|
|
Packit |
1422b7 |
free(tree);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Set the common prefix inside a note, taking into account the subtle
|
|
Packit |
1422b7 |
* issues associated with it.
|
|
Packit |
1422b7 |
* @return 0 on success, something else otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
setPrefix(struct ln_ptree *tree, unsigned char *buf, size_t lenBuf, size_t offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "setPrefix lenBuf %zu, offs %zu", lenBuf, offs);
|
|
Packit |
1422b7 |
tree->lenPrefix = lenBuf - offs;
|
|
Packit |
1422b7 |
if(tree->lenPrefix > sizeof(tree->prefix)) {
|
|
Packit |
1422b7 |
/* too-large for standard buffer, need to alloc one */
|
|
Packit |
1422b7 |
if((tree->prefix.ptr = malloc(tree->lenPrefix * sizeof(unsigned char))) == NULL) {
|
|
Packit |
1422b7 |
r = LN_NOMEM;
|
|
Packit |
1422b7 |
goto done; /* fail! */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
memcpy(tree->prefix.ptr, buf, tree->lenPrefix);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* note: r->lenPrefix may be 0, but that is OK */
|
|
Packit |
1422b7 |
memcpy(tree->prefix.data, buf, tree->lenPrefix);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Check if the provided tree is a leaf. This means that it
|
|
Packit |
1422b7 |
* does not contain any subtrees.
|
|
Packit |
1422b7 |
* @return 1 if it is a leaf, 0 otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
isLeaf(struct ln_ptree *tree)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(tree->froot != NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(i = 0 ; i < 256 ; ++i) {
|
|
Packit |
1422b7 |
if(tree->subtree[i] != NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 1;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Check if the provided tree is a true leaf. This means that it
|
|
Packit |
1422b7 |
* does not contain any subtrees of any kind and no prefix,
|
|
Packit |
1422b7 |
* and it is not terminal leaf.
|
|
Packit |
1422b7 |
* @return 1 if it is a leaf, 0 otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
isTrueLeaf(struct ln_ptree *tree)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
return((tree->lenPrefix == 0) && isLeaf(tree)) && !tree->flags.isTerminal;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct ln_ptree *
|
|
Packit |
1422b7 |
ln_addPTree(struct ln_ptree *tree, es_str_t *str, size_t offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_ptree *r;
|
|
Packit |
1422b7 |
struct ln_ptree **parentptr; /**< pointer in parent that needs to be updated */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "addPTree: offs %zu", offs);
|
|
Packit |
1422b7 |
parentptr = &(tree->subtree[es_getBufAddr(str)[offs]]);
|
|
Packit |
1422b7 |
/* First check if tree node is totaly empty. If so, we can simply add
|
|
Packit |
1422b7 |
* the prefix to this node. This case is important, because it happens
|
|
Packit |
1422b7 |
* every time with a new field.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(isTrueLeaf(tree)) {
|
|
Packit |
1422b7 |
if(setPrefix(tree, es_getBufAddr(str), es_strlen(str), offs) != 0) {
|
|
Packit |
1422b7 |
r = NULL;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
r = tree;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(tree->ctx->debug) {
|
|
Packit |
1422b7 |
char *cstr = es_str2cstr(str, NULL);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "addPTree: add '%s', offs %zu, tree %p",
|
|
Packit |
1422b7 |
cstr + offs, offs, tree);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((r = ln_newPTree(tree->ctx, parentptr)) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(setPrefix(r, es_getBufAddr(str) + offs + 1, es_strlen(str) - offs - 1, 0) != 0) {
|
|
Packit |
1422b7 |
free(r);
|
|
Packit |
1422b7 |
r = NULL;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*parentptr = r;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Split the provided tree (node) into two at the provided index into its
|
|
Packit |
1422b7 |
* common prefix. This function exists to support splitting nodes when
|
|
Packit |
1422b7 |
* a mismatch in the common prefix requires that. This function more or less
|
|
Packit |
1422b7 |
* keeps the tree as it is, just changes the structure. No new node is added.
|
|
Packit |
1422b7 |
* Usually, it is desired to add a new node. This must be made afterwards.
|
|
Packit |
1422b7 |
* Note that we need to create a new tree *in front of* the current one, as
|
|
Packit |
1422b7 |
* the current one contains field etc. subtree pointers.
|
|
Packit |
1422b7 |
* @param[in] tree tree to split
|
|
Packit |
1422b7 |
* @param[in] offs offset into common prefix (must be less than prefix length!)
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static struct ln_ptree*
|
|
Packit |
1422b7 |
splitTree(struct ln_ptree *tree, unsigned short offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
unsigned char *c;
|
|
Packit |
1422b7 |
struct ln_ptree *r;
|
|
Packit |
1422b7 |
unsigned short newlen;
|
|
Packit |
1422b7 |
ln_ptree **newparentptr; /**< pointer in parent that needs to be updated */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(offs < tree->lenPrefix);
|
|
Packit |
1422b7 |
if((r = ln_newPTree(tree->ctx, tree->parentptr)) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "splitTree %p at offs %u", tree, offs);
|
|
Packit |
1422b7 |
/* note: the overall prefix is reduced by one char, which is now taken
|
|
Packit |
1422b7 |
* care of inside the "branch table".
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
c = prefixBase(tree);
|
|
Packit |
1422b7 |
//LN_DBGPRINTF(tree->ctx, "splitTree new bb, *(c+offs): '%s'", c);
|
|
Packit |
1422b7 |
if(setPrefix(r, c, offs, 0) != 0) {
|
|
Packit |
1422b7 |
ln_deletePTree(r);
|
|
Packit |
1422b7 |
r = NULL;
|
|
Packit |
1422b7 |
goto done; /* fail! */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "splitTree new tree %p lenPrefix=%u, char '%c'", r, r->lenPrefix, r->prefix.data[0]);
|
|
Packit |
1422b7 |
/* add the proper branch table entry for the new node. must be done
|
|
Packit |
1422b7 |
* here, because the next step will destroy the required index char!
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
newparentptr = &(r->subtree[c[offs]]);
|
|
Packit |
1422b7 |
r->subtree[c[offs]] = tree;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* finally fix existing common prefix */
|
|
Packit |
1422b7 |
newlen = tree->lenPrefix - offs - 1;
|
|
Packit |
1422b7 |
if(tree->lenPrefix > sizeof(tree->prefix) && (newlen <= sizeof(tree->prefix))) {
|
|
Packit |
1422b7 |
/* note: c is a different pointer; the original
|
|
Packit |
1422b7 |
* pointer is overwritten by memcpy! */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "splitTree new case one bb, offs %u, lenPrefix %u, newlen %u", offs, tree->lenPrefix, newlen);
|
|
Packit |
1422b7 |
//LN_DBGPRINTF(tree->ctx, "splitTree new case one bb, *(c+offs): '%s'", c);
|
|
Packit |
1422b7 |
memcpy(tree->prefix.data, c+offs+1, newlen);
|
|
Packit |
1422b7 |
free(c);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "splitTree new case two bb, offs=%u, newlen %u", offs, newlen);
|
|
Packit |
1422b7 |
memmove(c, c+offs+1, newlen);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
tree->lenPrefix = tree->lenPrefix - offs - 1;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(tree->parentptr == 0)
|
|
Packit |
1422b7 |
tree->ctx->ptree = r; /* root does not have a parent! */
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
*(tree->parentptr) = r;
|
|
Packit |
1422b7 |
tree->parentptr = newparentptr;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct ln_ptree *
|
|
Packit |
1422b7 |
ln_buildPTree(struct ln_ptree *tree, es_str_t *str, size_t offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct ln_ptree *r;
|
|
Packit |
1422b7 |
unsigned char *c;
|
|
Packit |
1422b7 |
unsigned char *cpfix;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
unsigned short ipfix;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(tree != NULL);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "buildPTree: begin at %p, offs %zu", tree, offs);
|
|
Packit |
1422b7 |
c = es_getBufAddr(str);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if the prefix matches and, if not, at what offset it is different */
|
|
Packit |
1422b7 |
ipfix = 0;
|
|
Packit |
1422b7 |
cpfix = prefixBase(tree);
|
|
Packit |
1422b7 |
for( i = offs
|
|
Packit |
1422b7 |
; (i < es_strlen(str)) && (ipfix < tree->lenPrefix) && (c[i] == cpfix[ipfix])
|
|
Packit |
1422b7 |
; ++i, ++ipfix) {
|
|
Packit |
1422b7 |
; /*DO NOTHING - just find end of match */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "buildPTree: tree %p, i %zu, char '%c'", tree, i, c[i]);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* if we reach this point, we have processed as much of the common prefix
|
|
Packit |
1422b7 |
* as we could. The following code now does the proper actions based on
|
|
Packit |
1422b7 |
* the possible cases.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(i == es_strlen(str)) {
|
|
Packit |
1422b7 |
/* all of our input is consumed, no more recursion */
|
|
Packit |
1422b7 |
if(ipfix == tree->lenPrefix) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "case 1.1");
|
|
Packit |
1422b7 |
/* exact match, we are done! */
|
|
Packit |
1422b7 |
r = tree;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "case 1.2");
|
|
Packit |
1422b7 |
/* we need to split the node at the current position */
|
|
Packit |
1422b7 |
r = splitTree(tree, ipfix);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(ipfix < tree->lenPrefix) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "case 2, i=%zu, ipfix=%u", i, ipfix);
|
|
Packit |
1422b7 |
/* we need to split the node at the current position */
|
|
Packit |
1422b7 |
if((r = splitTree(tree, ipfix)) == NULL)
|
|
Packit |
1422b7 |
goto done; /* fail */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "pre addPTree: i %zu", i);
|
|
Packit |
1422b7 |
if((r = ln_addPTree(r, str, i)) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
//r = ln_buildPTree(r, str, i + 1);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* we could consume the current common prefix, but now need
|
|
Packit |
1422b7 |
* to traverse the rest of the tree based on the next char.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(tree->subtree[c[i]] == NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "case 3.1");
|
|
Packit |
1422b7 |
/* non-match, need new subtree */
|
|
Packit |
1422b7 |
r = ln_addPTree(tree, str, i);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "case 3.2");
|
|
Packit |
1422b7 |
/* match, follow subtree */
|
|
Packit |
1422b7 |
r = ln_buildPTree(tree->subtree[c[i]], str, i + 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
//LN_DBGPRINTF(tree->ctx, "---------------------------------------");
|
|
Packit |
1422b7 |
//ln_displayPTree(tree, 0);
|
|
Packit |
1422b7 |
//LN_DBGPRINTF(tree->ctx, "=======================================");
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_addFDescrToPTree(struct ln_ptree **tree, ln_fieldList_t *node)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
ln_fieldList_t *curr;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(tree != NULL);assert(*tree != NULL);
|
|
Packit |
1422b7 |
assert(node != NULL);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((node->subtree = ln_newPTree((*tree)->ctx, &node->subtree)) == NULL) {
|
|
Packit |
1422b7 |
r = -1;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF((*tree)->ctx, "got new subtree %p", node->subtree);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if we already have this field, if so, merge
|
|
Packit |
1422b7 |
* TODO: optimized, check logic
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
for(curr = (*tree)->froot ; curr != NULL ; curr = curr->next) {
|
|
Packit |
1422b7 |
if(!es_strcmp(curr->name, node->name)
|
|
Packit |
1422b7 |
&& curr->parser == node->parser
|
|
Packit |
1422b7 |
&& ((curr->raw_data == NULL && node->raw_data == NULL)
|
|
Packit |
1422b7 |
|| (curr->raw_data != NULL && node->raw_data != NULL
|
|
Packit |
1422b7 |
&& !es_strcmp(curr->raw_data, node->raw_data)))) {
|
|
Packit |
1422b7 |
*tree = curr->subtree;
|
|
Packit |
1422b7 |
ln_deletePTreeNode(node);
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
LN_DBGPRINTF((*tree)->ctx, "merging with tree %p\n", *tree);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((*tree)->froot == NULL) {
|
|
Packit |
1422b7 |
(*tree)->froot = (*tree)->ftail = node;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
(*tree)->ftail->next = node;
|
|
Packit |
1422b7 |
(*tree)->ftail = node;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
LN_DBGPRINTF((*tree)->ctx, "prev subtree %p", *tree);
|
|
Packit |
1422b7 |
*tree = node->subtree;
|
|
Packit |
1422b7 |
LN_DBGPRINTF((*tree)->ctx, "new subtree %p", *tree);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_displayPTree(struct ln_ptree *tree, int level)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
int nChildLit;
|
|
Packit |
1422b7 |
int nChildField;
|
|
Packit |
1422b7 |
es_str_t *str;
|
|
Packit |
1422b7 |
char *cstr;
|
|
Packit |
1422b7 |
ln_fieldList_t *node;
|
|
Packit |
1422b7 |
char indent[2048];
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(level > 1023)
|
|
Packit |
1422b7 |
level = 1023;
|
|
Packit |
1422b7 |
memset(indent, ' ', level * 2);
|
|
Packit |
1422b7 |
indent[level * 2] = '\0';
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
nChildField = 0;
|
|
Packit |
1422b7 |
for(node = tree->froot ; node != NULL ; node = node->next ) {
|
|
Packit |
1422b7 |
++nChildField;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
nChildLit = 0;
|
|
Packit |
1422b7 |
for(i = 0 ; i < 256 ; ++i) {
|
|
Packit |
1422b7 |
if(tree->subtree[i] != NULL) {
|
|
Packit |
1422b7 |
nChildLit++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
str = es_newStr(sizeof(tree->prefix));
|
|
Packit |
1422b7 |
es_addBuf(&str, (char*) prefixBase(tree), tree->lenPrefix);
|
|
Packit |
1422b7 |
cstr = es_str2cstr(str, NULL);
|
|
Packit |
1422b7 |
es_deleteStr(str);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%ssubtree%s %p (prefix: '%s', children: %d literals, %d fields) [visited %u "
|
|
Packit |
1422b7 |
"backtracked %u terminated %u]",
|
|
Packit |
1422b7 |
indent, tree->flags.isTerminal ? " TERM" : "", tree, cstr, nChildLit, nChildField,
|
|
Packit |
1422b7 |
tree->stats.visited, tree->stats.backtracked, tree->stats.terminated);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
/* display char subtrees */
|
|
Packit |
1422b7 |
for(i = 0 ; i < 256 ; ++i) {
|
|
Packit |
1422b7 |
if(tree->subtree[i] != NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%schar %2.2x(%c):", indent, i, i);
|
|
Packit |
1422b7 |
ln_displayPTree(tree->subtree[i], level + 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* display field subtrees */
|
|
Packit |
1422b7 |
for(node = tree->froot ; node != NULL ; node = node->next ) {
|
|
Packit |
1422b7 |
cstr = es_str2cstr(node->name, NULL);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%sfield %s:", indent, cstr);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
ln_displayPTree(node->subtree, level + 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* the following is a quick hack, which should be moved to the
|
|
Packit |
1422b7 |
* string class.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline void dotAddPtr(es_str_t **str, void *p)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
char buf[64];
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
i = snprintf(buf, sizeof(buf), "%p", p);
|
|
Packit |
1422b7 |
es_addBuf(str, buf, i);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* recursive handler for DOT graph generator.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
ln_genDotPTreeGraphRec(struct ln_ptree *tree, es_str_t **str)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int i;
|
|
Packit |
1422b7 |
ln_fieldList_t *node;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
dotAddPtr(str, tree);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " [label=\"");
|
|
Packit |
1422b7 |
if(tree->lenPrefix > 0) {
|
|
Packit |
1422b7 |
es_addChar(str, '\'');
|
|
Packit |
1422b7 |
es_addBuf(str, (char*) prefixBase(tree), tree->lenPrefix);
|
|
Packit |
1422b7 |
es_addChar(str, '\'');
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "\"");
|
|
Packit |
1422b7 |
if(isLeaf(tree)) {
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " style=\"bold\"");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "]\n");
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* display char subtrees */
|
|
Packit |
1422b7 |
for(i = 0 ; i < 256 ; ++i) {
|
|
Packit |
1422b7 |
if(tree->subtree[i] != NULL) {
|
|
Packit |
1422b7 |
dotAddPtr(str, tree);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " -> ");
|
|
Packit |
1422b7 |
dotAddPtr(str, tree->subtree[i]);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " [label=\"");
|
|
Packit |
1422b7 |
es_addChar(str, (char) i);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "\"]\n");
|
|
Packit |
1422b7 |
ln_genDotPTreeGraphRec(tree->subtree[i], str);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* display field subtrees */
|
|
Packit |
1422b7 |
for(node = tree->froot ; node != NULL ; node = node->next ) {
|
|
Packit |
1422b7 |
dotAddPtr(str, tree);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " -> ");
|
|
Packit |
1422b7 |
dotAddPtr(str, node->subtree);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, " [label=\"");
|
|
Packit |
1422b7 |
es_addStr(str, node->name);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "\" style=\"dotted\"]\n");
|
|
Packit |
1422b7 |
ln_genDotPTreeGraphRec(node->subtree, str);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_genDotPTreeGraph(struct ln_ptree *tree, es_str_t **str)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "digraph ptree {\n");
|
|
Packit |
1422b7 |
ln_genDotPTreeGraphRec(tree, str);
|
|
Packit |
1422b7 |
es_addBufConstcstr(str, "}\n");
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* add unparsed string to event.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
addUnparsedField(const char *str, size_t strLen, int offs, struct json_object *json)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 1;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
char *s = NULL;
|
|
Packit |
1422b7 |
CHKN(s = strndup(str, strLen));
|
|
Packit |
1422b7 |
value = json_object_new_string(s);
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_object_add(json, ORIGINAL_MSG_KEY, value);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
value = json_object_new_string(s + offs);
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_object_add(json, UNPARSED_DATA_KEY, value);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(s);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Special parser for iptables-like name/value pairs.
|
|
Packit |
1422b7 |
* The pull multiple fields. Note that once this parser has been selected,
|
|
Packit |
1422b7 |
* it is very unlikely to be left, as it is *very* generic. This parser is
|
|
Packit |
1422b7 |
* required because practice shows that already-structured data like iptables
|
|
Packit |
1422b7 |
* can otherwise not be processed by liblognorm in a meaningful way.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @param[in] tree current tree to process
|
|
Packit |
1422b7 |
* @param[in] str string to be matched against (the to-be-normalized data)
|
|
Packit |
1422b7 |
* @param[in] strLen length of str
|
|
Packit |
1422b7 |
* @param[in/out] offs start position in input data, on exit first unparsed position
|
|
Packit |
1422b7 |
* @param[in/out] event handle to event that is being created during normalization
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @return 0 if parser was successfully, something else on error
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_iptablesParser(struct ln_ptree *tree, const char *str, size_t strLen, size_t *offs,
|
|
Packit |
1422b7 |
struct json_object *json)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
size_t o = *offs;
|
|
Packit |
1422b7 |
es_str_t *fname;
|
|
Packit |
1422b7 |
es_str_t *fval;
|
|
Packit |
1422b7 |
const char *pstr;
|
|
Packit |
1422b7 |
const char *end;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu enter iptables parser, len %zu", *offs, strLen);
|
|
Packit |
1422b7 |
if(o == strLen) {
|
|
Packit |
1422b7 |
r = -1; /* can not be, we have no n/v pairs! */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
end = str + strLen;
|
|
Packit |
1422b7 |
pstr = str + o;
|
|
Packit |
1422b7 |
while(pstr < end) {
|
|
Packit |
1422b7 |
while(pstr < end && isspace(*pstr))
|
|
Packit |
1422b7 |
++pstr;
|
|
Packit |
1422b7 |
CHKN(fname = es_newStr(16));
|
|
Packit |
1422b7 |
while(pstr < end && !isspace(*pstr) && *pstr != '=') {
|
|
Packit |
1422b7 |
es_addChar(&fname, *pstr);
|
|
Packit |
1422b7 |
++pstr;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(pstr < end && *pstr == '=') {
|
|
Packit |
1422b7 |
CHKN(fval = es_newStr(16));
|
|
Packit |
1422b7 |
++pstr;
|
|
Packit |
1422b7 |
/* error on space */
|
|
Packit |
1422b7 |
while(pstr < end && !isspace(*pstr)) {
|
|
Packit |
1422b7 |
es_addChar(&fval, *pstr);
|
|
Packit |
1422b7 |
++pstr;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
CHKN(fval = es_newStrFromCStr("[*PRESENT*]",
|
|
Packit |
1422b7 |
sizeof("[*PRESENT*]")-1));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
char *cn, *cv;
|
|
Packit |
1422b7 |
CHKN(cn = ln_es_str2cstr(&fname));
|
|
Packit |
1422b7 |
CHKN(cv = ln_es_str2cstr(&fval));
|
|
Packit |
1422b7 |
if (tree->ctx->debug) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "iptables parser extracts %s=%s", cn, cv);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
CHKN(value = json_object_new_string(cv));
|
|
Packit |
1422b7 |
json_object_object_add(json, cn, value);
|
|
Packit |
1422b7 |
es_deleteStr(fval);
|
|
Packit |
1422b7 |
es_deleteStr(fname);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
*offs = strLen;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu iptables parser returns %d", *offs, r);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Recursive step of the normalizer. It walks the parse tree and calls itself
|
|
Packit |
1422b7 |
* recursively when this is appropriate. It also implements backtracking in
|
|
Packit |
1422b7 |
* those (hopefully rare) cases where it is required.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @param[in] tree current tree to process
|
|
Packit |
1422b7 |
* @param[in] string string to be matched against (the to-be-normalized data)
|
|
Packit |
1422b7 |
* @param[in] strLen length of the to-be-matched string
|
|
Packit |
1422b7 |
* @param[in] offs start position in input data
|
|
Packit |
1422b7 |
* @param[in/out] json ... that is being created during normalization
|
|
Packit |
1422b7 |
* @param[out] endNode if a match was found, this is the matching node (undefined otherwise)
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @return number of characters left unparsed by following the subtree, negative if
|
|
Packit |
1422b7 |
* the to-be-parsed message is shorter than the rule sample by this number of
|
|
Packit |
1422b7 |
* characters.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
ln_v1_normalizeRec(struct ln_ptree *tree, const char *str, size_t strLen, size_t offs, struct json_object *json,
|
|
Packit |
1422b7 |
struct ln_ptree **endNode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
int localR;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
int left;
|
|
Packit |
1422b7 |
ln_fieldList_t *node;
|
|
Packit |
1422b7 |
ln_fieldList_t *restMotifNode = NULL;
|
|
Packit |
1422b7 |
char *cstr;
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
unsigned char *cpfix;
|
|
Packit |
1422b7 |
unsigned ipfix;
|
|
Packit |
1422b7 |
size_t parsed;
|
|
Packit |
1422b7 |
char *namestr;
|
|
Packit |
1422b7 |
struct json_object *value;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
++tree->stats.visited;
|
|
Packit |
1422b7 |
if(offs >= strLen) {
|
|
Packit |
1422b7 |
*endNode = tree;
|
|
Packit |
1422b7 |
r = -tree->lenPrefix;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: enter parser, tree %p", offs, tree);
|
|
Packit |
1422b7 |
c = str;
|
|
Packit |
1422b7 |
cpfix = prefixBase(tree);
|
|
Packit |
1422b7 |
node = tree->froot;
|
|
Packit |
1422b7 |
r = strLen - offs;
|
|
Packit |
1422b7 |
/* first we need to check if the common prefix matches (and consume input data while we do) */
|
|
Packit |
1422b7 |
ipfix = 0;
|
|
Packit |
1422b7 |
while(offs < strLen && ipfix < tree->lenPrefix) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: prefix compare '%c', '%c'", offs, c[offs], cpfix[ipfix]);
|
|
Packit |
1422b7 |
if(c[offs] != cpfix[ipfix]) {
|
|
Packit |
1422b7 |
r -= ipfix;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
++offs, ++ipfix;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ipfix != tree->lenPrefix) {
|
|
Packit |
1422b7 |
/* incomplete prefix match --> to-be-normalized string too short */
|
|
Packit |
1422b7 |
r = ipfix - tree->lenPrefix;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r -= ipfix;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: prefix compare succeeded, still valid", offs);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* now try the parsers */
|
|
Packit |
1422b7 |
while(node != NULL) {
|
|
Packit |
1422b7 |
if(tree->ctx->debug) {
|
|
Packit |
1422b7 |
cstr = es_str2cstr(node->name, NULL);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu:trying parser for field '%s': %p",
|
|
Packit |
1422b7 |
offs, cstr, node->parser);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
i = offs;
|
|
Packit |
1422b7 |
if(node->isIPTables) {
|
|
Packit |
1422b7 |
localR = ln_iptablesParser(tree, str, strLen, &i, json);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu iptables parser return, i=%zu",
|
|
Packit |
1422b7 |
offs, i);
|
|
Packit |
1422b7 |
if(localR == 0) {
|
|
Packit |
1422b7 |
/* potential hit, need to verify */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "potential hit, trying subtree");
|
|
Packit |
1422b7 |
left = ln_v1_normalizeRec(node->subtree, str, strLen, i, json, endNode);
|
|
Packit |
1422b7 |
if(left == 0 && (*endNode)->flags.isTerminal) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: parser matches at %zu", offs, i);
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu nonmatch, backtracking required, left=%d",
|
|
Packit |
1422b7 |
offs, left);
|
|
Packit |
1422b7 |
++tree->stats.backtracked;
|
|
Packit |
1422b7 |
if(left < r)
|
|
Packit |
1422b7 |
r = left;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(node->parser == ln_parseRest) {
|
|
Packit |
1422b7 |
/* This is a quick and dirty adjustment to handle "rest" more intelligently.
|
|
Packit |
1422b7 |
* It's just a tactical fix: in the longer term, we'll handle the whole
|
|
Packit |
1422b7 |
* situation differently. However, it makes sense to fix this now, as this
|
|
Packit |
1422b7 |
* solves some real-world problems immediately. -- rgerhards, 2015-04-15
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
restMotifNode = node;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
value = NULL;
|
|
Packit |
1422b7 |
localR = node->parser(str, strLen, &i, node, &parsed, &value);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "parser returns %d, parsed %zu", localR, parsed);
|
|
Packit |
1422b7 |
if(localR == 0) {
|
|
Packit |
1422b7 |
/* potential hit, need to verify */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: potential hit, trying subtree %p", offs, node->subtree);
|
|
Packit |
1422b7 |
left = ln_v1_normalizeRec(node->subtree, str, strLen, i + parsed, json, endNode);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: subtree returns %d", offs, r);
|
|
Packit |
1422b7 |
if(left == 0 && (*endNode)->flags.isTerminal) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: parser matches at %zu", offs, i);
|
|
Packit |
1422b7 |
if(es_strbufcmp(node->name, (unsigned char*)"-", 1)) {
|
|
Packit |
1422b7 |
/* Store the value here; create json if not already created */
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
CHKN(cstr = strndup(str + i, parsed));
|
|
Packit |
1422b7 |
value = json_object_new_string(cstr);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "unable to create json");
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
namestr = ln_es_str2cstr(&node->name);
|
|
Packit |
1422b7 |
json_object_object_add(json, namestr, value);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if (value != NULL) {
|
|
Packit |
1422b7 |
/* Free the unneeded value */
|
|
Packit |
1422b7 |
json_object_put(value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu nonmatch, backtracking required, left=%d",
|
|
Packit |
1422b7 |
offs, left);
|
|
Packit |
1422b7 |
if (value != NULL) {
|
|
Packit |
1422b7 |
/* Free the value if it was created */
|
|
Packit |
1422b7 |
json_object_put(value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(left > 0 && left < r)
|
|
Packit |
1422b7 |
r = left;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu nonmatch, backtracking required, left=%d, r now %d",
|
|
Packit |
1422b7 |
offs, left, r);
|
|
Packit |
1422b7 |
++tree->stats.backtracked;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
node = node->next;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(offs == strLen) {
|
|
Packit |
1422b7 |
*endNode = tree;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(offs < strLen) {
|
|
Packit |
1422b7 |
unsigned char cc = str[offs];
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu no field, trying subtree char '%c': %p", offs, cc, tree->subtree[cc]);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu no field, offset already beyond end", offs);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* now let's see if we have a literal */
|
|
Packit |
1422b7 |
if(tree->subtree[(unsigned char)str[offs]] != NULL) {
|
|
Packit |
1422b7 |
left = ln_v1_normalizeRec(tree->subtree[(unsigned char)str[offs]],
|
|
Packit |
1422b7 |
str, strLen, offs + 1, json, endNode);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu got left %d, r %d", offs, left, r);
|
|
Packit |
1422b7 |
if(left < r)
|
|
Packit |
1422b7 |
r = left;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu got return %d", offs, r);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(r == 0 && (*endNode)->flags.isTerminal)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* and finally give "rest" a try if it was present. Note that we MUST do this after
|
|
Packit |
1422b7 |
* literal evaluation, otherwise "rest" can never be overriden by other rules.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(restMotifNode != NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "rule has rest motif, forcing match via it");
|
|
Packit |
1422b7 |
value = NULL;
|
|
Packit |
1422b7 |
restMotifNode->parser(str, strLen, &i, restMotifNode, &parsed, &value);
|
|
Packit |
1422b7 |
# ifndef NDEBUG
|
|
Packit |
1422b7 |
left = /* we only need this for the assert below */
|
|
Packit |
1422b7 |
# endif
|
|
Packit |
1422b7 |
ln_v1_normalizeRec(restMotifNode->subtree, str, strLen, i + parsed, json, endNode);
|
|
Packit |
1422b7 |
assert(left == 0); /* with rest, we have this invariant */
|
|
Packit |
1422b7 |
assert((*endNode)->flags.isTerminal); /* this one also */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu: parser matches at %zu", offs, i);
|
|
Packit |
1422b7 |
if(es_strbufcmp(restMotifNode->name, (unsigned char*)"-", 1)) {
|
|
Packit |
1422b7 |
/* Store the value here; create json if not already created */
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
CHKN(cstr = strndup(str + i, parsed));
|
|
Packit |
1422b7 |
value = json_object_new_string(cstr);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if (value == NULL) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "unable to create json");
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
namestr = ln_es_str2cstr(&restMotifNode->name);
|
|
Packit |
1422b7 |
json_object_object_add(json, namestr, value);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if (value != NULL) {
|
|
Packit |
1422b7 |
/* Free the unneeded value */
|
|
Packit |
1422b7 |
json_object_put(value);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
LN_DBGPRINTF(tree->ctx, "%zu returns %d", offs, r);
|
|
Packit |
1422b7 |
if(r == 0 && *endNode == tree)
|
|
Packit |
1422b7 |
++tree->stats.terminated;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_v1_normalize(ln_ctx ctx, const char *str, size_t strLen, struct json_object **json_p)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r;
|
|
Packit |
1422b7 |
int left;
|
|
Packit |
1422b7 |
struct ln_ptree *endNode = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*json_p == NULL) {
|
|
Packit |
1422b7 |
CHKN(*json_p = json_object_new_object());
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
left = ln_v1_normalizeRec(ctx->ptree, str, strLen, 0, *json_p, &endNode);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(ctx->debug) {
|
|
Packit |
1422b7 |
if(left == 0) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "final result for normalizer: left %d, endNode %p, "
|
|
Packit |
1422b7 |
"isTerminal %d, tagbucket %p",
|
|
Packit |
1422b7 |
left, endNode, endNode->flags.isTerminal, endNode->tags);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "final result for normalizer: left %d, endNode %p",
|
|
Packit |
1422b7 |
left, endNode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(left != 0 || !endNode->flags.isTerminal) {
|
|
Packit |
1422b7 |
/* we could not successfully parse, some unparsed items left */
|
|
Packit |
1422b7 |
if(left < 0) {
|
|
Packit |
1422b7 |
addUnparsedField(str, strLen, strLen, *json_p);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
addUnparsedField(str, strLen, strLen - left, *json_p);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* success, finalize event */
|
|
Packit |
1422b7 |
if(endNode->tags != NULL) {
|
|
Packit |
1422b7 |
/* add tags to an event */
|
|
Packit |
1422b7 |
json_object_get(endNode->tags);
|
|
Packit |
1422b7 |
json_object_object_add(*json_p, "event.tags", endNode->tags);
|
|
Packit |
1422b7 |
CHKR(ln_annotate(ctx, *json_p, endNode->tags));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Gather and output pdag statistics for the full pdag (ctx)
|
|
Packit |
1422b7 |
* including all disconnected components (type defs).
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* Data is sent to given file ptr.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
void
|
|
Packit |
1422b7 |
ln_fullPTreeStats(ln_ctx ctx, FILE __attribute__((unused)) *const fp,
|
|
Packit |
1422b7 |
const int __attribute__((unused)) extendedStats)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
ln_displayPTree(ctx->ptree, 0);
|
|
Packit |
1422b7 |
}
|