Пример #1
0
static inline int
ln_addTags_Syslog(struct json_object *taglist, es_str_t **str)
{
    int r = 0;
    struct json_object *tagObj;
    int needComma = 0;
    const char *tagCstr;
    int i;

    assert(json_object_is_type(taglist, json_type_array));

    CHKR(es_addBuf(str, " event.tags=\"", 13));
    for (i = json_object_array_length(taglist) - 1; i >= 0; i--) {
        if(needComma)
            es_addChar(str, ',');
        else
            needComma = 1;
        CHKN(tagObj = json_object_array_get_idx(taglist, i));
        CHKN(tagCstr = json_object_get_string(tagObj));
        CHKR(es_addBuf(str, (char*)tagCstr, strlen(tagCstr)));
    }
    es_addChar(str, '"');

done:
    return r;
}
Пример #2
0
/**
 * add unparsed string to event.
 */
static inline int
addUnparsedField(const char *str, size_t strLen, int offs, struct json_object *json)
{
	int r = 1;
	struct json_object *value;
	char *s = NULL;
	CHKN(s = strndup(str, strLen));
	value = json_object_new_string(s);
	if (value == NULL) {
		goto done;
	}
	json_object_object_add(json, ORIGINAL_MSG_KEY, value);
	
	if (offs != 0) {
		value = json_object_new_string(s + offs);
		if (value == NULL) {
			goto done;
		}
		json_object_object_add(json, UNPARSED_DATA_KEY, value);
	}

	r = 0;
done:
	free(s);
	return r;
}
Пример #3
0
static int
ln_addField_Syslog(char *name, struct json_object *field, es_str_t **str)
{
    int r;
    const char *value;
    int needComma = 0;
    struct json_object *obj;
    int i;

    assert(field != NULL);
    assert(str != NULL);
    assert(*str != NULL);

    CHKR(es_addBuf(str, name, strlen(name)));
    CHKR(es_addBuf(str, "=\"", 2));
    switch(json_object_get_type(field)) {
    case json_type_array:
        for (i = json_object_array_length(field) - 1; i >= 0; i--) {
            if(needComma)
                es_addChar(str, ',');
            else
                needComma = 1;
            CHKN(obj = json_object_array_get_idx(field, i));
            CHKN(value = json_object_get_string(obj));
            CHKR(ln_addValue_Syslog(value, str));
        }
        break;
    case json_type_string:
    case json_type_int:
        CHKN(value = json_object_get_string(field));
        CHKR(ln_addValue_Syslog(value, str));
        break;
    case json_type_null:
    case json_type_boolean:
    case json_type_double:
    case json_type_object:
        CHKR(es_addBuf(str, "***unsupported type***", sizeof("***unsupported type***")-1));
        break;
    default:
        CHKR(es_addBuf(str, "***OBJECT***", sizeof("***OBJECT***")-1));
    }
    CHKR(es_addChar(str, '\"'));
    r = 0;

done:
    return r;
}
Пример #4
0
/**
 * Special parser for iptables-like name/value pairs.
 * The pull multiple fields. Note that once this parser has been selected,
 * it is very unlikely to be left, as it is *very* generic. This parser is
 * required because practice shows that already-structured data like iptables
 * can otherwise not be processed by liblognorm in a meaningful way.
 *
 * @param[in] tree current tree to process
 * @param[in] str string to be matched against (the to-be-normalized data)
 * @param[in] strLen length of str
 * @param[in/out] offs start position in input data, on exit first unparsed position
 * @param[in/out] event handle to event that is being created during normalization
 *
 * @return 0 if parser was successfully, something else on error
 */
static int
ln_iptablesParser(struct ln_ptree *tree, const char *str, size_t strLen, size_t *offs,
		  struct json_object *json)
{
	int r;
	size_t o = *offs;
	es_str_t *fname;
	es_str_t *fval;
	const char *pstr;
	const char *end;
	struct json_object *value;

ln_dbgprintf(tree->ctx, "%zu enter iptables parser, len %zu", *offs, strLen);
	if(o == strLen) {
		r = -1; /* can not be, we have no n/v pairs! */
		goto done;
	}
	
	end = str + strLen;
	pstr = str + o;
	while(pstr < end) {
		while(pstr < end && isspace(*pstr))
			++pstr;
		CHKN(fname = es_newStr(16));
		while(pstr < end && !isspace(*pstr) && *pstr != '=') {
			es_addChar(&fname, *pstr);
			++pstr;
		}
		if(pstr < end && *pstr == '=') {
			CHKN(fval = es_newStr(16));
			++pstr;
			/* error on space */
			while(pstr < end && !isspace(*pstr)) {
				es_addChar(&fval, *pstr);
				++pstr;
			}
		} else {
			CHKN(fval = es_newStrFromCStr("[*PRESENT*]", 
					sizeof("[*PRESENT*]")-1));
		}
		char *cn, *cv;
		CHKN(cn = ln_es_str2cstr(&fname));
		CHKN(cv = ln_es_str2cstr(&fval));
		if (tree->ctx->debug) {
			ln_dbgprintf(tree->ctx, "iptables parser extracts %s=%s", cn, cv);
		}
		CHKN(value = json_object_new_string(cv));
		json_object_object_add(json, cn, value);
		es_deleteStr(fval);
		es_deleteStr(fname);
	}

	r = 0;
	*offs = strLen;

done:
	ln_dbgprintf(tree->ctx, "%zu iptables parser returns %d", *offs, r);
	return r;
}
Пример #5
0
int
ln_normalize(ln_ctx ctx, const char *str, size_t strLen, struct json_object **json_p)
{
	int r;
	int left;
	struct ln_ptree *endNode = NULL;
	while (isspace(*str)) {
		++str;
		--strLen;
	}

	if(*json_p == NULL) {
		CHKN(*json_p = json_object_new_object());
	}

	left = ln_normalizeRec(ctx->ptree, str, strLen, 0, *json_p, &endNode);

	if(ctx->debug) {
		if(left == 0) {
			ln_dbgprintf(ctx, "final result for normalizer: left %d, endNode %p, "
				     "isTerminal %d, tagbucket %p",
				     left, endNode, endNode->flags.isTerminal, endNode->tags);
		} else {
			ln_dbgprintf(ctx, "final result for normalizer: left %d, endNode %p",
				     left, endNode);
		}
	}
	if(left != 0 || !endNode->flags.isTerminal) {
		/* we could not successfully parse, some unparsed items left */
		if(left < 0) {
			addUnparsedField(str, strLen, strLen, *json_p);
		} else {
			addUnparsedField(str, strLen, strLen - left, *json_p);
		}
	} else {
		/* success, finalize event */
		if(endNode->tags != NULL) {
			/* add tags to an event */
			json_object_get(endNode->tags);
			json_object_object_add(*json_p, "event.tags", endNode->tags);
			CHKR(ln_annotate(ctx, *json_p, endNode->tags));
		}
	}

	r = 0;

done:	return r;
}
Пример #6
0
/**
 * Recursive step of the normalizer. It walks the parse tree and calls itself
 * recursively when this is appropriate. It also implements backtracking in
 * those (hopefully rare) cases where it is required.
 *
 * @param[in] tree current tree to process
 * @param[in] string string to be matched against (the to-be-normalized data)
 * @param[in] offs start position in input data
 * @param[in/out] event handle to event that is being created during normalization
 * @param[out] endNode if a match was found, this is the matching node (undefined otherwise)
 *
 * @return number of characters left unparsed by following the subtree, negative if
 *         the to-be-parsed message is shorter than the rule sample by this number of
 *         characters.
 */
static int
ln_normalizeRec(struct ln_ptree *tree, const char *str, size_t strLen, size_t offs, struct json_object *json,
		struct ln_ptree **endNode)
{
	int r;
	int localR;
	size_t i;
	int left;
	ln_fieldList_t *node;
	char *cstr;
	const char *c;
	unsigned char *cpfix;
	unsigned ipfix;
	size_t parsed;
	char *namestr;
	struct json_object *value;
	
	if(offs >= strLen) {
		*endNode = tree;
		r = -tree->lenPrefix;
		goto done;
	}

	c = str;
	cpfix = prefixBase(tree);
	node = tree->froot;
	r = strLen - offs;
	/* first we need to check if the common prefix matches (and consume input data while we do) */
	ipfix = 0;
	while(offs < strLen && ipfix < tree->lenPrefix) {
		ln_dbgprintf(tree->ctx, "%zu: prefix compare '%c', '%c'", offs, c[offs], cpfix[ipfix]);
		if(c[offs] != cpfix[ipfix]) {
			r -= ipfix;
			goto done;
		}
		++offs, ++ipfix;
	}
	
	if(ipfix != tree->lenPrefix) {
		/* incomplete prefix match --> to-be-normalized string too short */
		r = ipfix - tree->lenPrefix;
		goto done;
	}

	r -= ipfix;
	ln_dbgprintf(tree->ctx, "%zu: prefix compare succeeded, still valid", offs);

	/* now try the parsers */
	while(node != NULL) {
		if(tree->ctx->debug) {
			cstr = es_str2cstr(node->name, NULL);
			ln_dbgprintf(tree->ctx, "%zu:trying parser for field '%s': %p",
					offs, cstr, node->parser);
			free(cstr);
		}
		i = offs;
		if(node->isIPTables) {
			localR = ln_iptablesParser(tree, str, strLen, &i, json);
			ln_dbgprintf(tree->ctx, "%zu iptables parser return, i=%zu",
						offs, i);
			if(localR == 0) {
				/* potential hit, need to verify */
				ln_dbgprintf(tree->ctx, "potential hit, trying subtree");
				left = ln_normalizeRec(node->subtree, str, strLen, i, json, endNode);
				if(left == 0 && (*endNode)->flags.isTerminal) {
					ln_dbgprintf(tree->ctx, "%zu: parser matches at %zu", offs, i);
					r = 0;
					goto done;
				}
				ln_dbgprintf(tree->ctx, "%zu nonmatch, backtracking required, left=%d",
						offs, left);
				if(left < r)
					r = left;
			}
		} else {
			value = NULL;
			localR = node->parser(str, strLen, &i, node, &parsed, &value);
			ln_dbgprintf(tree->ctx, "parser returns %d, parsed %zu", localR, parsed);
			if(localR == 0) {
				/* potential hit, need to verify */
				ln_dbgprintf(tree->ctx, "potential hit, trying subtree");
				left = ln_normalizeRec(node->subtree, str, strLen, i + parsed, json, endNode);
				if(left == 0 && (*endNode)->flags.isTerminal) {
					ln_dbgprintf(tree->ctx, "%zu: parser matches at %zu", offs, i);
					if(es_strbufcmp(node->name, (unsigned char*)"-", 1)) {
						/* Store the value here; create json if not already created */
						if (value == NULL) { 
							CHKN(cstr = strndup(str + i, parsed));
							value = json_object_new_string(cstr);
							free(cstr);
						}
						if (value == NULL) {
							ln_dbgprintf(tree->ctx, "unable to create json");
							goto done;
						}
						namestr = ln_es_str2cstr(&node->name);
						json_object_object_add(json, namestr, value);
					} else {
						if (value != NULL) {
							/* Free the unneeded value */
							json_object_put(value);
						}
					}
					r = 0;
					goto done;
				}
				ln_dbgprintf(tree->ctx, "%zu nonmatch, backtracking required, left=%d",
						offs, left);
				if (value != NULL) {
					/* Free the value if it was created */
					json_object_put(value);
				}
				if(left < r)
					r = left;
			}
		}
		node = node->next;
	}

	if(offs == strLen) {
		*endNode = tree;
		r = 0;
		goto done;
	}

if(offs < strLen) {
unsigned char cc = str[offs];
ln_dbgprintf(tree->ctx, "%zu no field, trying subtree char '%c': %p", offs, cc, tree->subtree[cc]);
} else {
ln_dbgprintf(tree->ctx, "%zu no field, offset already beyond end", offs);
}
	/* now let's see if we have a literal */
	if(tree->subtree[(int)str[offs]] != NULL) {
		left = ln_normalizeRec(tree->subtree[(int)str[offs]],
				       str, strLen, offs + 1, json, endNode);
		if(left < r)
			r = left;
	}

done:
	ln_dbgprintf(tree->ctx, "%zu returns %d", offs, r);
	return r;
}