|
Packit |
1422b7 |
/*
|
|
Packit |
1422b7 |
* liblognorm - a fast samples-based log normalization library
|
|
Packit |
1422b7 |
* Copyright 2010-2018 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 <assert.h>
|
|
Packit |
1422b7 |
#include <ctype.h>
|
|
Packit |
1422b7 |
#include <sys/types.h>
|
|
Packit |
1422b7 |
#include <string.h>
|
|
Packit |
1422b7 |
#include <strings.h>
|
|
Packit |
1422b7 |
#include <errno.h>
|
|
Packit |
1422b7 |
#include <inttypes.h>
|
|
Packit |
1422b7 |
#include <time.h>
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#include "liblognorm.h"
|
|
Packit |
1422b7 |
#include "lognorm.h"
|
|
Packit |
1422b7 |
#include "internal.h"
|
|
Packit |
1422b7 |
#include "parser.h"
|
|
Packit |
1422b7 |
#include "samp.h"
|
|
Packit |
1422b7 |
#include "helpers.h"
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#ifdef FEATURE_REGEXP
|
|
Packit |
1422b7 |
#include <pcre.h>
|
|
Packit |
1422b7 |
#include <errno.h>
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* how should output values be formatted? */
|
|
Packit |
1422b7 |
enum FMT_MODE {
|
|
Packit |
1422b7 |
FMT_AS_STRING = 0,
|
|
Packit |
1422b7 |
FMT_AS_NUMBER = 1,
|
|
Packit |
1422b7 |
FMT_AS_TIMESTAMP_UX = 2,
|
|
Packit |
1422b7 |
FMT_AS_TIMESTAMP_UX_MS = 3
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* some helpers */
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
hParseInt(const unsigned char **buf, size_t *lenBuf)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const unsigned char *p = *buf;
|
|
Packit |
1422b7 |
size_t len = *lenBuf;
|
|
Packit |
1422b7 |
int i = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
while(len > 0 && myisdigit(*p)) {
|
|
Packit |
1422b7 |
i = i * 10 + *p - '0';
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*buf = p;
|
|
Packit |
1422b7 |
*lenBuf = len;
|
|
Packit |
1422b7 |
return i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parser _parse interface
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* All parsers receive
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* @param[in] npb->str the to-be-parsed string
|
|
Packit |
1422b7 |
* @param[in] npb->strLen length of the to-be-parsed string
|
|
Packit |
1422b7 |
* @param[in] offs an offset into the string
|
|
Packit |
1422b7 |
* @param[in] pointer to parser data block
|
|
Packit |
1422b7 |
* @param[out] parsed bytes
|
|
Packit |
1422b7 |
* @param[out] value ptr to json object containing parsed data
|
|
Packit |
1422b7 |
* (can be unused, but if used *value MUST be NULL on entry)
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* They will try to parse out "their" object from the string. If they
|
|
Packit |
1422b7 |
* succeed, they:
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* return 0 on success and LN_WRONGPARSER if this parser could
|
|
Packit |
1422b7 |
* not successfully parse (but all went well otherwise) and something
|
|
Packit |
1422b7 |
* else in case of an error.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PARSER_Parse(ParserName) \
|
|
Packit |
1422b7 |
int ln_v2_parse##ParserName( \
|
|
Packit |
1422b7 |
npb_t *const npb, \
|
|
Packit |
1422b7 |
size_t *const offs, \
|
|
Packit |
1422b7 |
__attribute__((unused)) void *const pdata, \
|
|
Packit |
1422b7 |
size_t *parsed, \
|
|
Packit |
1422b7 |
struct json_object **value) \
|
|
Packit |
1422b7 |
{ \
|
|
Packit |
1422b7 |
int r = LN_WRONGPARSER; \
|
|
Packit |
1422b7 |
*parsed = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#define FAILParser \
|
|
Packit |
1422b7 |
goto parserdone; /* suppress warnings */ \
|
|
Packit |
1422b7 |
parserdone: \
|
|
Packit |
1422b7 |
r = 0; \
|
|
Packit |
1422b7 |
goto done; /* suppress warnings */ \
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
#define ENDFailParser \
|
|
Packit |
1422b7 |
return r; \
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Return printable representation of parser content for
|
|
Packit |
1422b7 |
* display purposes. This must not be 100% exact, but provide
|
|
Packit |
1422b7 |
* a good indication of what it contains for a human.
|
|
Packit |
1422b7 |
* @param[data] data parser data block
|
|
Packit |
1422b7 |
* @return pointer to c string, NOT to be freed
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PARSER_DataForDisplay(ParserName) \
|
|
Packit |
1422b7 |
const char * ln_DataForDisplay##ParserName(__attribute__((unused)) ln_ctx ctx, void *const pdata)
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Return JSON parser config. This is primarily for comparison
|
|
Packit |
1422b7 |
* of parser equalness.
|
|
Packit |
1422b7 |
* @param[data] data parser data block
|
|
Packit |
1422b7 |
* @return pointer to c string, NOT to be freed
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PARSER_JsonConf(ParserName) \
|
|
Packit |
1422b7 |
const char * ln_JsonConf##ParserName(__attribute__((unused)) ln_ctx ctx, void *const pdata)
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parser constructor
|
|
Packit |
1422b7 |
* @param[in] json config json items
|
|
Packit |
1422b7 |
* @param[out] data parser data block (to be allocated)
|
|
Packit |
1422b7 |
* At minimum, *data must be set to NULL
|
|
Packit |
1422b7 |
* @return error status (0 == OK)
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PARSER_Construct(ParserName) \
|
|
Packit |
1422b7 |
int ln_construct##ParserName( \
|
|
Packit |
1422b7 |
__attribute__((unused)) ln_ctx ctx, \
|
|
Packit |
1422b7 |
__attribute__((unused)) json_object *const json, \
|
|
Packit |
1422b7 |
void **pdata)
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parser destructor
|
|
Packit |
1422b7 |
* @param[data] data parser data block (to be de-allocated)
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define PARSER_Destruct(ParserName) \
|
|
Packit |
1422b7 |
void ln_destruct##ParserName(__attribute__((unused)) ln_ctx ctx, void *const pdata)
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* the following table saves us from computing an additional date to get
|
|
Packit |
1422b7 |
* the ordinal day of the year - at least from 1967-2099
|
|
Packit |
1422b7 |
* Note: non-2038+ compliant systems (Solaris) will generate compiler
|
|
Packit |
1422b7 |
* warnings on the post 2038-rollover years.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static const int yearInSec_startYear = 1967;
|
|
Packit |
1422b7 |
/* for x in $(seq 1967 2099) ; do
|
|
Packit |
1422b7 |
* printf %s', ' $(date --date="Dec 31 ${x} UTC 23:59:59" +%s)
|
|
Packit |
1422b7 |
* done |fold -w 70 -s */
|
|
Packit |
1422b7 |
static const time_t yearInSecs[] = {
|
|
Packit |
1422b7 |
-63158401, -31536001, -1, 31535999, 63071999, 94694399, 126230399,
|
|
Packit |
1422b7 |
157766399, 189302399, 220924799, 252460799, 283996799, 315532799,
|
|
Packit |
1422b7 |
347155199, 378691199, 410227199, 441763199, 473385599, 504921599,
|
|
Packit |
1422b7 |
536457599, 567993599, 599615999, 631151999, 662687999, 694223999,
|
|
Packit |
1422b7 |
725846399, 757382399, 788918399, 820454399, 852076799, 883612799,
|
|
Packit |
1422b7 |
915148799, 946684799, 978307199, 1009843199, 1041379199, 1072915199,
|
|
Packit |
1422b7 |
1104537599, 1136073599, 1167609599, 1199145599, 1230767999,
|
|
Packit |
1422b7 |
1262303999, 1293839999, 1325375999, 1356998399, 1388534399,
|
|
Packit |
1422b7 |
1420070399, 1451606399, 1483228799, 1514764799, 1546300799,
|
|
Packit |
1422b7 |
1577836799, 1609459199, 1640995199, 1672531199, 1704067199,
|
|
Packit |
1422b7 |
1735689599, 1767225599, 1798761599, 1830297599, 1861919999,
|
|
Packit |
1422b7 |
1893455999, 1924991999, 1956527999, 1988150399, 2019686399,
|
|
Packit |
1422b7 |
2051222399, 2082758399, 2114380799, 2145916799, 2177452799,
|
|
Packit |
1422b7 |
2208988799, 2240611199, 2272147199, 2303683199, 2335219199,
|
|
Packit |
1422b7 |
2366841599, 2398377599, 2429913599, 2461449599, 2493071999,
|
|
Packit |
1422b7 |
2524607999, 2556143999, 2587679999, 2619302399, 2650838399,
|
|
Packit |
1422b7 |
2682374399, 2713910399, 2745532799, 2777068799, 2808604799,
|
|
Packit |
1422b7 |
2840140799, 2871763199, 2903299199, 2934835199, 2966371199,
|
|
Packit |
1422b7 |
2997993599, 3029529599, 3061065599, 3092601599, 3124223999,
|
|
Packit |
1422b7 |
3155759999, 3187295999, 3218831999, 3250454399, 3281990399,
|
|
Packit |
1422b7 |
3313526399, 3345062399, 3376684799, 3408220799, 3439756799,
|
|
Packit |
1422b7 |
3471292799, 3502915199, 3534451199, 3565987199, 3597523199,
|
|
Packit |
1422b7 |
3629145599, 3660681599, 3692217599, 3723753599, 3755375999,
|
|
Packit |
1422b7 |
3786911999, 3818447999, 3849983999, 3881606399, 3913142399,
|
|
Packit |
1422b7 |
3944678399, 3976214399, 4007836799, 4039372799, 4070908799,
|
|
Packit |
1422b7 |
4102444799};
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* convert syslog timestamp to time_t
|
|
Packit |
1422b7 |
* Note: it would be better to use something similar to mktime() here.
|
|
Packit |
1422b7 |
* Unfortunately, mktime() semantics are problematic: first of all, it
|
|
Packit |
1422b7 |
* works on local time, on the machine's time zone. In syslog, we have
|
|
Packit |
1422b7 |
* to deal with multiple time zones at once, so we cannot plainly rely
|
|
Packit |
1422b7 |
* on the local zone, and so we cannot rely on mktime(). One solution would
|
|
Packit |
1422b7 |
* be to refactor all time-related functions so that they are all guarded
|
|
Packit |
1422b7 |
* by a mutex to ensure TZ consistency (which would also enable us to
|
|
Packit |
1422b7 |
* change the TZ at will for specific function calls). But that would
|
|
Packit |
1422b7 |
* potentially mean a lot of overhead.
|
|
Packit |
1422b7 |
* Also, mktime() has some side effects, at least setting of tzname. With
|
|
Packit |
1422b7 |
* a refactoring as described above that should probably not be a problem,
|
|
Packit |
1422b7 |
* but would also need more work. For some more thoughts on this topic,
|
|
Packit |
1422b7 |
* have a look here:
|
|
Packit |
1422b7 |
* http://stackoverflow.com/questions/18355101/is-standard-c-mktime-thread-safe-on-linux
|
|
Packit |
1422b7 |
* In conclusion, we keep our own code for generating the unix timestamp.
|
|
Packit |
1422b7 |
* rgerhards, 2016-03-02 (taken from rsyslog sources)
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static time_t
|
|
Packit |
1422b7 |
syslogTime2time_t(const int year, const int month, const int day,
|
|
Packit |
1422b7 |
const int hour, const int minute, const int second,
|
|
Packit |
1422b7 |
const int OffsetHour, const int OffsetMinute, const char OffsetMode)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
long MonthInDays, NumberOfYears, NumberOfDays;
|
|
Packit |
1422b7 |
int utcOffset;
|
|
Packit |
1422b7 |
time_t TimeInUnixFormat;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(year < 1970 || year > 2100) {
|
|
Packit |
1422b7 |
TimeInUnixFormat = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Counting how many Days have passed since the 01.01 of the
|
|
Packit |
1422b7 |
* selected Year (Month level), according to the selected Month*/
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
switch(month)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
case 1:
|
|
Packit |
1422b7 |
MonthInDays = 0; //until 01 of January
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 2:
|
|
Packit |
1422b7 |
MonthInDays = 31; //until 01 of February - leap year handling down below!
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 3:
|
|
Packit |
1422b7 |
MonthInDays = 59; //until 01 of March
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 4:
|
|
Packit |
1422b7 |
MonthInDays = 90; //until 01 of April
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 5:
|
|
Packit |
1422b7 |
MonthInDays = 120; //until 01 of Mai
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 6:
|
|
Packit |
1422b7 |
MonthInDays = 151; //until 01 of June
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 7:
|
|
Packit |
1422b7 |
MonthInDays = 181; //until 01 of July
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 8:
|
|
Packit |
1422b7 |
MonthInDays = 212; //until 01 of August
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 9:
|
|
Packit |
1422b7 |
MonthInDays = 243; //until 01 of September
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 10:
|
|
Packit |
1422b7 |
MonthInDays = 273; //until 01 of Oktober
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 11:
|
|
Packit |
1422b7 |
MonthInDays = 304; //until 01 of November
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 12:
|
|
Packit |
1422b7 |
MonthInDays = 334; //until 01 of December
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
default: /* this cannot happen (and would be a program error)
|
|
Packit |
1422b7 |
* but we need the code to keep the compiler silent.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
MonthInDays = 0; /* any value fits ;) */
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* adjust for leap years */
|
|
Packit |
1422b7 |
if((year % 100 != 0 && year % 4 == 0) || (year == 2000)) {
|
|
Packit |
1422b7 |
if(month > 2)
|
|
Packit |
1422b7 |
MonthInDays++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* 1) Counting how many Years have passed since 1970
|
|
Packit |
1422b7 |
2) Counting how many Days have passed since the 01.01 of the selected Year
|
|
Packit |
1422b7 |
(Day level) according to the Selected Month and Day. Last day doesn't count,
|
|
Packit |
1422b7 |
it should be until last day
|
|
Packit |
1422b7 |
3) Calculating this period (NumberOfDays) in seconds*/
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
NumberOfYears = year - yearInSec_startYear - 1;
|
|
Packit |
1422b7 |
NumberOfDays = MonthInDays + day - 1;
|
|
Packit |
1422b7 |
TimeInUnixFormat = (yearInSecs[NumberOfYears] + 1) + NumberOfDays * 86400;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/*Add Hours, minutes and seconds */
|
|
Packit |
1422b7 |
TimeInUnixFormat += hour*60*60;
|
|
Packit |
1422b7 |
TimeInUnixFormat += minute*60;
|
|
Packit |
1422b7 |
TimeInUnixFormat += second;
|
|
Packit |
1422b7 |
/* do UTC offset */
|
|
Packit |
1422b7 |
utcOffset = OffsetHour*3600 + OffsetMinute*60;
|
|
Packit |
1422b7 |
if(OffsetMode == '+')
|
|
Packit |
1422b7 |
utcOffset *= -1; /* if timestamp is ahead, we need to "go back" to UTC */
|
|
Packit |
1422b7 |
TimeInUnixFormat += utcOffset;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return TimeInUnixFormat;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_RFC5424Date {
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a TIMESTAMP as specified in RFC5424 (subset of RFC3339).
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(RFC5424Date)
|
|
Packit |
1422b7 |
const unsigned char *pszTS;
|
|
Packit |
1422b7 |
struct data_RFC5424Date *const data = (struct data_RFC5424Date*) pdata;
|
|
Packit |
1422b7 |
/* variables to temporarily hold time information while we parse */
|
|
Packit |
1422b7 |
int year;
|
|
Packit |
1422b7 |
int month;
|
|
Packit |
1422b7 |
int day;
|
|
Packit |
1422b7 |
int hour; /* 24 hour clock */
|
|
Packit |
1422b7 |
int minute;
|
|
Packit |
1422b7 |
int second;
|
|
Packit |
1422b7 |
int secfrac; /* fractional seconds (must be 32 bit!) */
|
|
Packit |
1422b7 |
int secfracPrecision;
|
|
Packit |
1422b7 |
int OffsetHour; /* UTC offset in hours */
|
|
Packit |
1422b7 |
int OffsetMinute; /* UTC offset in minutes */
|
|
Packit |
1422b7 |
char OffsetMode;
|
|
Packit |
1422b7 |
size_t len;
|
|
Packit |
1422b7 |
size_t orglen;
|
|
Packit |
1422b7 |
/* end variables to temporarily hold time information while we parse */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
pszTS = (unsigned char*) npb->str + *offs;
|
|
Packit |
1422b7 |
len = orglen = npb->strLen - *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
year = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* We take the liberty to accept slightly malformed timestamps e.g. in
|
|
Packit |
1422b7 |
* the format of 2003-9-1T1:0:0. */
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != '-') goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
month = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(month < 1 || month > 12) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != '-')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
day = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(day < 1 || day > 31) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != 'T') goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
hour = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(hour < 0 || hour > 23) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != ':')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
minute = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(minute < 0 || minute > 59) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != ':') goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
second = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(second < 0 || second > 60) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Now let's see if we have secfrac */
|
|
Packit |
1422b7 |
if(len > 0 && *pszTS == '.') {
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
const unsigned char *pszStart = ++pszTS;
|
|
Packit |
1422b7 |
secfrac = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
secfracPrecision = (int) (pszTS - pszStart);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
secfracPrecision = 0;
|
|
Packit |
1422b7 |
secfrac = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check the timezone */
|
|
Packit |
1422b7 |
if(len == 0) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*pszTS == 'Z') {
|
|
Packit |
1422b7 |
OffsetHour = 0;
|
|
Packit |
1422b7 |
OffsetMinute = 0;
|
|
Packit |
1422b7 |
OffsetMode = '+';
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
pszTS++; /* eat Z */
|
|
Packit |
1422b7 |
} else if((*pszTS == '+') || (*pszTS == '-')) {
|
|
Packit |
1422b7 |
OffsetMode = *pszTS;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
pszTS++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
OffsetHour = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(OffsetHour < 0 || OffsetHour > 23)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *pszTS++ != ':')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
OffsetMinute = hParseInt(&pszTS, &len;;
|
|
Packit |
1422b7 |
if(OffsetMinute < 0 || OffsetMinute > 59)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* there MUST be TZ information */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len > 0) {
|
|
Packit |
1422b7 |
if(*pszTS != ' ') /* if it is not a space, it can not be a "good" time */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we had success, so update parse pointer */
|
|
Packit |
1422b7 |
*parsed = orglen - len;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_STRING) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
int64_t timestamp = syslogTime2time_t(year, month, day,
|
|
Packit |
1422b7 |
hour, minute, second, OffsetHour, OffsetMinute, OffsetMode);
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_TIMESTAMP_UX_MS) {
|
|
Packit |
1422b7 |
timestamp *= 1000;
|
|
Packit |
1422b7 |
/* simulate pow(), do not use math lib! */
|
|
Packit |
1422b7 |
int div = 1;
|
|
Packit |
1422b7 |
if(secfracPrecision == 1) {
|
|
Packit |
1422b7 |
secfrac *= 100;
|
|
Packit |
1422b7 |
} else if(secfracPrecision == 2) {
|
|
Packit |
1422b7 |
secfrac *= 10;
|
|
Packit |
1422b7 |
} else if(secfracPrecision > 3) {
|
|
Packit |
1422b7 |
for(int i = 0 ; i < (secfracPrecision - 3) ; ++i)
|
|
Packit |
1422b7 |
div *= 10;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
timestamp += secfrac / div;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
*value = json_object_new_int64(timestamp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(RFC5424Date)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_RFC5424Date *data =
|
|
Packit |
1422b7 |
(struct data_RFC5424Date*) calloc(1, sizeof(struct data_RFC5424Date));
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "format")) {
|
|
Packit |
1422b7 |
const char *fmtmode = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcmp(fmtmode, "timestamp-unix")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_TIMESTAMP_UX;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "timestamp-unix-ms")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_TIMESTAMP_UX_MS;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "string")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid value for date-rfc5424:format %s",
|
|
Packit |
1422b7 |
fmtmode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for date-rfc5424 %s", key);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(RFC5424Date)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_RFC3164Date {
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a RFC3164 Date.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(RFC3164Date)
|
|
Packit |
1422b7 |
const unsigned char *p;
|
|
Packit |
1422b7 |
size_t len, orglen;
|
|
Packit |
1422b7 |
struct data_RFC3164Date *const data = (struct data_RFC3164Date*) pdata;
|
|
Packit |
1422b7 |
/* variables to temporarily hold time information while we parse */
|
|
Packit |
1422b7 |
int year;
|
|
Packit |
1422b7 |
int month;
|
|
Packit |
1422b7 |
int day;
|
|
Packit |
1422b7 |
int hour; /* 24 hour clock */
|
|
Packit |
1422b7 |
int minute;
|
|
Packit |
1422b7 |
int second;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
p = (unsigned char*) npb->str + *offs;
|
|
Packit |
1422b7 |
orglen = len = npb->strLen - *offs;
|
|
Packit |
1422b7 |
/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
|
|
Packit |
1422b7 |
* we may see the following character sequences occur:
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* We will use this for parsing, as it probably is the
|
|
Packit |
1422b7 |
* fastest way to parse it.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(len < 3)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
switch(*p++)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
case 'j':
|
|
Packit |
1422b7 |
case 'J':
|
|
Packit |
1422b7 |
if(*p == 'a' || *p == 'A') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'n' || *p == 'N') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 1;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else if(*p == 'u' || *p == 'U') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'n' || *p == 'N') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 6;
|
|
Packit |
1422b7 |
} else if(*p == 'l' || *p == 'L') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 7;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'f':
|
|
Packit |
1422b7 |
case 'F':
|
|
Packit |
1422b7 |
if(*p == 'e' || *p == 'E') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'b' || *p == 'B') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 2;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'm':
|
|
Packit |
1422b7 |
case 'M':
|
|
Packit |
1422b7 |
if(*p == 'a' || *p == 'A') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'r' || *p == 'R') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 3;
|
|
Packit |
1422b7 |
} else if(*p == 'y' || *p == 'Y') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 5;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'a':
|
|
Packit |
1422b7 |
case 'A':
|
|
Packit |
1422b7 |
if(*p == 'p' || *p == 'P') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'r' || *p == 'R') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 4;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else if(*p == 'u' || *p == 'U') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'g' || *p == 'G') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 8;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 's':
|
|
Packit |
1422b7 |
case 'S':
|
|
Packit |
1422b7 |
if(*p == 'e' || *p == 'E') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'p' || *p == 'P') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 9;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'o':
|
|
Packit |
1422b7 |
case 'O':
|
|
Packit |
1422b7 |
if(*p == 'c' || *p == 'C') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 't' || *p == 'T') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 10;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'n':
|
|
Packit |
1422b7 |
case 'N':
|
|
Packit |
1422b7 |
if(*p == 'o' || *p == 'O') {
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'v' || *p == 'V') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 11;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'd':
|
|
Packit |
1422b7 |
case 'D':
|
|
Packit |
1422b7 |
if(*p == 'e' || *p == 'E') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
if(*p == 'c' || *p == 'C') {
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
month = 12;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
} else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
default:
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
len -= 3;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* done month */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *p++ != ' ')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we accept a slightly malformed timestamp with one-digit days. */
|
|
Packit |
1422b7 |
if(*p == ' ') {
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
++p;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
day = hParseInt(&p, &len;;
|
|
Packit |
1422b7 |
if(day < 1 || day > 31)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *p++ != ' ')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* time part */
|
|
Packit |
1422b7 |
hour = hParseInt(&p, &len;;
|
|
Packit |
1422b7 |
if(hour > 1970 && hour < 2100) {
|
|
Packit |
1422b7 |
/* if so, we assume this actually is a year. This is a format found
|
|
Packit |
1422b7 |
* e.g. in Cisco devices.
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
year = hour;
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* re-query the hour, this time it must be valid */
|
|
Packit |
1422b7 |
if(len == 0 || *p++ != ' ')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
hour = hParseInt(&p, &len;;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(hour < 0 || hour > 23)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *p++ != ':')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
minute = hParseInt(&p, &len;;
|
|
Packit |
1422b7 |
if(minute < 0 || minute > 59)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(len == 0 || *p++ != ':')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
second = hParseInt(&p, &len;;
|
|
Packit |
1422b7 |
if(second < 0 || second > 60)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we provide support for an extra ":" after the date. While this is an
|
|
Packit |
1422b7 |
* invalid format, it occurs frequently enough (e.g. with Cisco devices)
|
|
Packit |
1422b7 |
* to permit it as a valid case. -- rgerhards, 2008-09-12
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(len > 0 && *p == ':') {
|
|
Packit |
1422b7 |
++p; /* just skip past it */
|
|
Packit |
1422b7 |
--len;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we had success, so update parse pointer */
|
|
Packit |
1422b7 |
*parsed = orglen - len;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_STRING) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
/* we assume year == current year, so let's obtain current year */
|
|
Packit |
1422b7 |
struct tm tm;
|
|
Packit |
1422b7 |
const time_t curr = time(NULL);
|
|
Packit |
1422b7 |
gmtime_r(&curr, &tm;;
|
|
Packit |
1422b7 |
year = tm.tm_year + 1900;
|
|
Packit |
1422b7 |
int64_t timestamp = syslogTime2time_t(year, month, day,
|
|
Packit |
1422b7 |
hour, minute, second, 0, 0, '+');
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_TIMESTAMP_UX_MS) {
|
|
Packit |
1422b7 |
/* we do not have more precise info, just bring
|
|
Packit |
1422b7 |
* into common format!
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
timestamp *= 1000;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
*value = json_object_new_int64(timestamp);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(RFC3164Date)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_RFC3164Date *data = (struct data_RFC3164Date*) calloc(1, sizeof(struct data_RFC3164Date));
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "format")) {
|
|
Packit |
1422b7 |
const char *fmtmode = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcmp(fmtmode, "timestamp-unix")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_TIMESTAMP_UX;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "timestamp-unix-ms")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_TIMESTAMP_UX_MS;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "string")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid value for date-rfc3164:format %s",
|
|
Packit |
1422b7 |
fmtmode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for date-rfc3164 %s", key);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(RFC3164Date)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_Number {
|
|
Packit |
1422b7 |
int64_t maxval;
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a Number.
|
|
Packit |
1422b7 |
* Note that a number is an abstracted concept. We always represent it
|
|
Packit |
1422b7 |
* as 64 bits (but may later change our mind if performance dictates so).
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Number)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
int64_t val = 0;
|
|
Packit |
1422b7 |
struct data_Number *const data = (struct data_Number*) pdata;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
int64_t maxval = 0;
|
|
Packit |
1422b7 |
if(data != NULL) {
|
|
Packit |
1422b7 |
fmt_mode = data->fmt_mode;
|
|
Packit |
1422b7 |
maxval = data->maxval;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for (i = *offs; i < npb->strLen && myisdigit(c[i]); i++)
|
|
Packit |
1422b7 |
val = val * 10 + c[i] - '0';
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(maxval > 0 && val > maxval) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "number parser: val too large (max %" PRIu64
|
|
Packit |
1422b7 |
", actual %" PRIu64 ")",
|
|
Packit |
1422b7 |
maxval, val);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if (i == *offs)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
if(fmt_mode == FMT_AS_STRING) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*value = json_object_new_int64(val);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
PARSER_Construct(Number)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_Number *data = (struct data_Number*) calloc(1, sizeof(struct data_Number));
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "maxval")) {
|
|
Packit |
1422b7 |
errno = 0;
|
|
Packit |
1422b7 |
data->maxval = json_object_get_int64(val);
|
|
Packit |
1422b7 |
if(errno != 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, errno, "param 'maxval' must be integer but is: %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(val));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(!strcmp(key, "format")) {
|
|
Packit |
1422b7 |
const char *fmtmode = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcmp(fmtmode, "number")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_NUMBER;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "string")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid value for number:format %s",
|
|
Packit |
1422b7 |
fmtmode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for number: %s", key);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(Number)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_Float {
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a Real-number in floating-pt form.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Float)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
const struct data_Float *const data = (struct data_Float*) pdata;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
int isNeg = 0;
|
|
Packit |
1422b7 |
double val = 0;
|
|
Packit |
1422b7 |
int seen_point = 0;
|
|
Packit |
1422b7 |
double frac = 10;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if (c[i] == '-') {
|
|
Packit |
1422b7 |
isNeg = 1;
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for (; i < npb->strLen; i++) {
|
|
Packit |
1422b7 |
if (c[i] == '.') {
|
|
Packit |
1422b7 |
if (seen_point != 0)
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
seen_point = 1;
|
|
Packit |
1422b7 |
} else if (myisdigit(c[i])) {
|
|
Packit |
1422b7 |
if(seen_point) {
|
|
Packit |
1422b7 |
val += (c[i] - '0') / frac;
|
|
Packit |
1422b7 |
frac *= 10;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
val = val * 10 + c[i] - '0';
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if (i == *offs)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(isNeg)
|
|
Packit |
1422b7 |
val *= -1;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_STRING) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
char *serialized = strndup(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
*value = json_object_new_double_s(val, serialized);
|
|
Packit |
1422b7 |
free(serialized);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(Float)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_Float *data = (struct data_Float*) calloc(1, sizeof(struct data_Float));
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "format")) {
|
|
Packit |
1422b7 |
const char *fmtmode = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcmp(fmtmode, "number")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_NUMBER;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "string")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid value for float:format %s",
|
|
Packit |
1422b7 |
fmtmode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for float: %s", key);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(Float)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_HexNumber {
|
|
Packit |
1422b7 |
uint64_t maxval;
|
|
Packit |
1422b7 |
enum FMT_MODE fmt_mode;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a hex Number.
|
|
Packit |
1422b7 |
* A hex number begins with 0x and contains only hex digits until the terminating
|
|
Packit |
1422b7 |
* whitespace. Note that if a non-hex character is deteced inside the number string,
|
|
Packit |
1422b7 |
* this is NOT considered to be a number.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(HexNumber)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
struct data_HexNumber *const data = (struct data_HexNumber*) pdata;
|
|
Packit |
1422b7 |
uint64_t maxval = data->maxval;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(c[i] != '0' || c[i+1] != 'x')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
uint64_t val = 0;
|
|
Packit |
1422b7 |
for (i += 2 ; i < npb->strLen && isxdigit(c[i]); i++) {
|
|
Packit |
1422b7 |
const char digit = tolower(c[i]);
|
|
Packit |
1422b7 |
val *= 16;
|
|
Packit |
1422b7 |
if(digit >= 'a' && digit <= 'f')
|
|
Packit |
1422b7 |
val += digit - 'a' + 10;
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
val += digit - '0';
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if (i == *offs || !isspace(c[i]))
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
if(maxval > 0 && val > maxval) {
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "hexnumber parser: val too large (max %" PRIu64
|
|
Packit |
1422b7 |
", actual %" PRIu64 ")",
|
|
Packit |
1422b7 |
maxval, val);
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
if(data->fmt_mode == FMT_AS_STRING) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*value = json_object_new_int64((int64_t) val);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(HexNumber)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_HexNumber *data = (struct data_HexNumber*) calloc(1, sizeof(struct data_HexNumber));
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "maxval")) {
|
|
Packit |
1422b7 |
errno = 0;
|
|
Packit |
1422b7 |
data->maxval = json_object_get_int64(val);
|
|
Packit |
1422b7 |
if(errno != 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, errno, "param 'maxval' must be integer but is: %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(val));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(!strcmp(key, "format")) {
|
|
Packit |
1422b7 |
const char *fmtmode = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcmp(fmtmode, "number")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_NUMBER;
|
|
Packit |
1422b7 |
} else if(!strcmp(fmtmode, "string")) {
|
|
Packit |
1422b7 |
data->fmt_mode = FMT_AS_STRING;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid value for hexnumber:format %s",
|
|
Packit |
1422b7 |
fmtmode);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for hexnumber: %s", key);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(HexNumber)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a kernel timestamp.
|
|
Packit |
1422b7 |
* This is a fixed format, see
|
|
Packit |
1422b7 |
* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/printk/printk.c?id=refs/tags/v4.0#n1011
|
|
Packit |
1422b7 |
* This is the code that generates it:
|
|
Packit |
1422b7 |
* sprintf(buf, "[%5lu.%06lu] ", (unsigned long)ts, rem_nsec / 1000);
|
|
Packit |
1422b7 |
* We accept up to 12 digits for ts, everything above that for sure is
|
|
Packit |
1422b7 |
* no timestamp.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
#define LEN_KERNEL_TIMESTAMP 14
|
|
Packit |
1422b7 |
PARSER_Parse(KernelTimestamp)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
if(c[i] != '[' || i+LEN_KERNEL_TIMESTAMP > npb->strLen
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+1])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+2])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+3])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+4])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+5])
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
i += 6;
|
|
Packit |
1422b7 |
for(int j = 0 ; j < 7 && i < npb->strLen && myisdigit(c[i]) ; )
|
|
Packit |
1422b7 |
++i, ++j; /* just scan */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i >= npb->strLen || c[i] != '.')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
++i; /* skip over '.' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if( i+7 > npb->strLen
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+0])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+1])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+2])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+3])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+4])
|
|
Packit |
1422b7 |
|| !myisdigit(c[i+5])
|
|
Packit |
1422b7 |
|| c[i+6] != ']'
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
i += 7;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse whitespace.
|
|
Packit |
1422b7 |
* This parses all whitespace until the first non-whitespace character
|
|
Packit |
1422b7 |
* is found. This is primarily a tool to skip to the next "word" if
|
|
Packit |
1422b7 |
* the exact number of whitspace characters (and type of whitespace)
|
|
Packit |
1422b7 |
* is not known. The current parsing position MUST be on a whitspace,
|
|
Packit |
1422b7 |
* else the parser does not match.
|
|
Packit |
1422b7 |
* This parser is also a forward-compatibility tool for the upcoming
|
|
Packit |
1422b7 |
* slsa (simple log structure analyser) tool.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Whitespace)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(!isspace(c[i]))
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for (i++ ; i < npb->strLen && isspace(c[i]); i++);
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a word.
|
|
Packit |
1422b7 |
* A word is a SP-delimited entity. The parser always works, except if
|
|
Packit |
1422b7 |
* the offset is position on a space upon entry.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Word)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of word */
|
|
Packit |
1422b7 |
while(i < npb->strLen && c[i] != ' ')
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == *offs)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_StringTo {
|
|
Packit |
1422b7 |
const char *toFind;
|
|
Packit |
1422b7 |
size_t len;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse everything up to a specific string.
|
|
Packit |
1422b7 |
* swisskid, 2015-01-21
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(StringTo)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i, j, m;
|
|
Packit |
1422b7 |
int chkstr;
|
|
Packit |
1422b7 |
struct data_StringTo *const data = (struct data_StringTo*) pdata;
|
|
Packit |
1422b7 |
const char *const toFind = data->toFind;
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
chkstr = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Total hunt for letter */
|
|
Packit |
1422b7 |
while(chkstr == 0 && i < npb->strLen ) {
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
if(c[i] == toFind[0]) {
|
|
Packit |
1422b7 |
/* Found the first letter, now find the rest of the string */
|
|
Packit |
1422b7 |
j = 1;
|
|
Packit |
1422b7 |
m = i+1;
|
|
Packit |
1422b7 |
while(m < npb->strLen && j < data->len ) {
|
|
Packit |
1422b7 |
if(c[m] != toFind[j])
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
if(j == data->len - 1) { /* full match? */
|
|
Packit |
1422b7 |
chkstr = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
j++;
|
|
Packit |
1422b7 |
m++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i == *offs || i == npb->strLen || chkstr != 1)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
PARSER_Construct(StringTo)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_StringTo *data = (struct data_StringTo*) calloc(1, sizeof(struct data_StringTo));
|
|
Packit |
1422b7 |
struct json_object *ed;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json_object_object_get_ex(json, "extradata", &ed) == 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "string-to type needs 'extradata' parameter");
|
|
Packit |
1422b7 |
r = LN_BADCONFIG ;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->toFind = strdup(json_object_get_string(ed));
|
|
Packit |
1422b7 |
data->len = strlen(data->toFind);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0)
|
|
Packit |
1422b7 |
free(data);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(StringTo)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_StringTo *data = (struct data_StringTo*) pdata;
|
|
Packit |
1422b7 |
free((void*)data->toFind);
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a alphabetic word.
|
|
Packit |
1422b7 |
* A alpha word is composed of characters for which isalpha returns true.
|
|
Packit |
1422b7 |
* The parser dones if there is no alpha character at all.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Alpha)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of word */
|
|
Packit |
1422b7 |
while(i < npb->strLen && isalpha(c[i]))
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == *offs) {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_CharTo {
|
|
Packit |
1422b7 |
char *term_chars;
|
|
Packit |
1422b7 |
size_t n_term_chars;
|
|
Packit |
1422b7 |
char *data_for_display;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse everything up to a specific character.
|
|
Packit |
1422b7 |
* The character must be the only char inside extra data passed to the parser.
|
|
Packit |
1422b7 |
* It is considered a format error if
|
|
Packit |
1422b7 |
* a) the to-be-parsed buffer is already positioned on the terminator character
|
|
Packit |
1422b7 |
* b) there is no terminator until the end of the buffer
|
|
Packit |
1422b7 |
* In those cases, the parsers declares itself as not being successful, in all
|
|
Packit |
1422b7 |
* other cases a string is extracted.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CharTo)
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
struct data_CharTo *const data = (struct data_CharTo*) pdata;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of word */
|
|
Packit |
1422b7 |
int found = 0;
|
|
Packit |
1422b7 |
while(i < npb->strLen && !found) {
|
|
Packit |
1422b7 |
for(size_t j = 0 ; j < data->n_term_chars ; ++j) {
|
|
Packit |
1422b7 |
if(npb->str[i] == data->term_chars[j]) {
|
|
Packit |
1422b7 |
found = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(!found)
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == *offs || i == npb->strLen || !found)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(CharTo)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(ctx, "in parser_construct charTo");
|
|
Packit |
1422b7 |
struct data_CharTo *data = (struct data_CharTo*) calloc(1, sizeof(struct data_CharTo));
|
|
Packit |
1422b7 |
struct json_object *ed;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json_object_object_get_ex(json, "extradata", &ed) == 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "char-to type needs 'extradata' parameter");
|
|
Packit |
1422b7 |
r = LN_BADCONFIG ;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->term_chars = strdup(json_object_get_string(ed));
|
|
Packit |
1422b7 |
data->n_term_chars = strlen(data->term_chars);
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0)
|
|
Packit |
1422b7 |
free(data);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_DataForDisplay(CharTo)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_CharTo *data = (struct data_CharTo*) pdata;
|
|
Packit |
1422b7 |
if(data->data_for_display == NULL) {
|
|
Packit |
1422b7 |
data->data_for_display = malloc(8+data->n_term_chars+2);
|
|
Packit |
1422b7 |
if(data->data_for_display != NULL) {
|
|
Packit |
1422b7 |
memcpy(data->data_for_display, "char-to{", 8);
|
|
Packit |
1422b7 |
size_t i, j;
|
|
Packit |
1422b7 |
for(j = 0, i = 8 ; j < data->n_term_chars ; ++j, ++i) {
|
|
Packit |
1422b7 |
data->data_for_display[i] = data->term_chars[j];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->data_for_display[i++] = '}';
|
|
Packit |
1422b7 |
data->data_for_display[i] = '\0';
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return (data->data_for_display == NULL ) ? "malloc error" : data->data_for_display;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(CharTo)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_CharTo *const data = (struct data_CharTo*) pdata;
|
|
Packit |
1422b7 |
free(data->data_for_display);
|
|
Packit |
1422b7 |
free(data->term_chars);
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_Literal {
|
|
Packit |
1422b7 |
const char *lit;
|
|
Packit |
1422b7 |
const char *json_conf;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a specific literal.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Literal)
|
|
Packit |
1422b7 |
struct data_Literal *const data = (struct data_Literal*) pdata;
|
|
Packit |
1422b7 |
const char *const lit = data->lit;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
size_t j;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(j = 0 ; i < npb->strLen ; ++j) {
|
|
Packit |
1422b7 |
if(lit[j] != npb->str[i])
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*parsed = j; /* we must always return how far we parsed! */
|
|
Packit |
1422b7 |
if(lit[j] == '\0') {
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_DataForDisplay(Literal)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_Literal *data = (struct data_Literal*) pdata;
|
|
Packit |
1422b7 |
return data->lit;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_JsonConf(Literal)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_Literal *data = (struct data_Literal*) pdata;
|
|
Packit |
1422b7 |
return data->json_conf;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(Literal)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_Literal *data = (struct data_Literal*) calloc(1, sizeof(struct data_Literal));
|
|
Packit |
1422b7 |
struct json_object *text;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json_object_object_get_ex(json, "text", &text) == 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "literal type needs 'text' parameter");
|
|
Packit |
1422b7 |
r = LN_BADCONFIG ;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->lit = strdup(json_object_get_string(text));
|
|
Packit |
1422b7 |
data->json_conf = strdup(json_object_to_json_string(json));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0)
|
|
Packit |
1422b7 |
free(data);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(Literal)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_Literal *data = (struct data_Literal*) pdata;
|
|
Packit |
1422b7 |
free((void*)data->lit);
|
|
Packit |
1422b7 |
free((void*)data->json_conf);
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* for path compaction, we need a special handler to combine two
|
|
Packit |
1422b7 |
* literal data elements.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int
|
|
Packit |
1422b7 |
ln_combineData_Literal(void *const porg, void *const padd)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_Literal *const __restrict__ org = porg;
|
|
Packit |
1422b7 |
struct data_Literal *const __restrict__ add = padd;
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
const size_t len = strlen(org->lit);
|
|
Packit |
1422b7 |
const size_t add_len = strlen(add->lit);
|
|
Packit |
1422b7 |
char *const newlit = (char*)realloc((void*)org->lit, len+add_len+1);
|
|
Packit |
1422b7 |
CHKN(newlit);
|
|
Packit |
1422b7 |
org->lit = newlit;
|
|
Packit |
1422b7 |
memcpy((char*)org->lit+len, add->lit, add_len+1);
|
|
Packit |
1422b7 |
done: return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct data_CharSeparated {
|
|
Packit |
1422b7 |
char *term_chars;
|
|
Packit |
1422b7 |
size_t n_term_chars;
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse everything up to a specific character, or up to the end of string.
|
|
Packit |
1422b7 |
* The character must be the only char inside extra data passed to the parser.
|
|
Packit |
1422b7 |
* This parser always returns success.
|
|
Packit |
1422b7 |
* By nature of the parser, it is required that end of string or the separator
|
|
Packit |
1422b7 |
* follows this field in rule.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CharSeparated)
|
|
Packit |
1422b7 |
struct data_CharSeparated *const data = (struct data_CharSeparated*) pdata;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of word */
|
|
Packit |
1422b7 |
int found = 0;
|
|
Packit |
1422b7 |
while(i < npb->strLen && !found) {
|
|
Packit |
1422b7 |
for(size_t j = 0 ; j < data->n_term_chars ; ++j) {
|
|
Packit |
1422b7 |
if(npb->str[i] == data->term_chars[j]) {
|
|
Packit |
1422b7 |
found = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(!found)
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(CharSeparated)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_CharSeparated *data = (struct data_CharSeparated*) calloc(1, sizeof(struct data_CharSeparated));
|
|
Packit |
1422b7 |
struct json_object *ed;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json_object_object_get_ex(json, "extradata", &ed) == 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "char-separated type needs 'extradata' parameter");
|
|
Packit |
1422b7 |
r = LN_BADCONFIG ;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
data->term_chars = strdup(json_object_get_string(ed));
|
|
Packit |
1422b7 |
data->n_term_chars = strlen(data->term_chars);
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0)
|
|
Packit |
1422b7 |
free(data);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(CharSeparated)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_CharSeparated *const data = (struct data_CharSeparated*) pdata;
|
|
Packit |
1422b7 |
free(data->term_chars);
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Just get everything till the end of string.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Rest)
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* silence the warning about unused variable */
|
|
Packit |
1422b7 |
(void)npb->str;
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = npb->strLen - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a possibly quoted string. In this initial implementation, escaping of the quote
|
|
Packit |
1422b7 |
* char is not supported. A quoted string is one start starts with a double quote,
|
|
Packit |
1422b7 |
* has some text (not containing double quotes) and ends with the first double
|
|
Packit |
1422b7 |
* quote character seen. The extracted string does NOT include the quote characters.
|
|
Packit |
1422b7 |
* swisskid, 2015-01-21
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(OpQuotedString)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
char *cstr = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(c[i] != '"') {
|
|
Packit |
1422b7 |
while(i < npb->strLen && c[i] != ' ')
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == *offs)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
/* create JSON value to save quoted string contents */
|
|
Packit |
1422b7 |
CHKN(cstr = strndup((char*)c + *offs, *parsed));
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of string */
|
|
Packit |
1422b7 |
while(i < npb->strLen && c[i] != '"')
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i] != '"')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i + 1 - *offs; /* "eat" terminal double quote */
|
|
Packit |
1422b7 |
/* create JSON value to save quoted string contents */
|
|
Packit |
1422b7 |
CHKN(cstr = strndup((char*)c + *offs + 1, *parsed - 2));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_string(cstr));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a quoted string. In this initial implementation, escaping of the quote
|
|
Packit |
1422b7 |
* char is not supported. A quoted string is one start starts with a double quote,
|
|
Packit |
1422b7 |
* has some text (not containing double quotes) and ends with the first double
|
|
Packit |
1422b7 |
* quote character seen. The extracted string does NOT include the quote characters.
|
|
Packit |
1422b7 |
* rgerhards, 2011-01-14
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(QuotedString)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
if(i + 2 > npb->strLen)
|
|
Packit |
1422b7 |
goto done; /* needs at least 2 characters */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(c[i] != '"')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* search end of string */
|
|
Packit |
1422b7 |
while(i < npb->strLen && c[i] != '"')
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i] != '"')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i + 1 - *offs; /* "eat" terminal double quote */
|
|
Packit |
1422b7 |
/* create JSON value to save quoted string contents */
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse an ISO date, that is YYYY-MM-DD (exactly this format).
|
|
Packit |
1422b7 |
* Note: we do manual loop unrolling -- this is fast AND efficient.
|
|
Packit |
1422b7 |
* rgerhards, 2011-01-14
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(ISODate)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*offs+10 > npb->strLen)
|
|
Packit |
1422b7 |
goto done; /* if it is not 10 chars, it can't be an ISO date */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* year */
|
|
Packit |
1422b7 |
if(!myisdigit(c[i])) goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+1])) goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+2])) goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+3])) goto done;
|
|
Packit |
1422b7 |
if(c[i+4] != '-') goto done;
|
|
Packit |
1422b7 |
/* month */
|
|
Packit |
1422b7 |
if(c[i+5] == '0') {
|
|
Packit |
1422b7 |
if(c[i+6] < '1' || c[i+6] > '9') goto done;
|
|
Packit |
1422b7 |
} else if(c[i+5] == '1') {
|
|
Packit |
1422b7 |
if(c[i+6] < '0' || c[i+6] > '2') goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(c[i+7] != '-') goto done;
|
|
Packit |
1422b7 |
/* day */
|
|
Packit |
1422b7 |
if(c[i+8] == '0') {
|
|
Packit |
1422b7 |
if(c[i+9] < '1' || c[i+9] > '9') goto done;
|
|
Packit |
1422b7 |
} else if(c[i+8] == '1' || c[i+8] == '2') {
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+9])) goto done;
|
|
Packit |
1422b7 |
} else if(c[i+8] == '3') {
|
|
Packit |
1422b7 |
if(c[i+9] != '0' && c[i+9] != '1') goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = 10;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a Cisco interface spec. Sample for such a spec are:
|
|
Packit |
1422b7 |
* outside:192.168.52.102/50349
|
|
Packit |
1422b7 |
* inside:192.168.1.15/56543 (192.168.1.112/54543)
|
|
Packit |
1422b7 |
* outside:192.168.1.13/50179 (192.168.1.13/50179)(LOCAL\some.user)
|
|
Packit |
1422b7 |
* outside:192.168.1.25/41850(LOCAL\RG-867G8-DEL88D879BBFFC8)
|
|
Packit |
1422b7 |
* inside:192.168.1.25/53 (192.168.1.25/53) (some.user)
|
|
Packit |
1422b7 |
* 192.168.1.15/0(LOCAL\RG-867G8-DEL88D879BBFFC8)
|
|
Packit |
1422b7 |
* From this, we conclude the format is:
|
|
Packit |
1422b7 |
* [interface:]ip/port [SP (ip2/port2)] [[SP](username)]
|
|
Packit |
1422b7 |
* In order to match, this syntax must start on a non-whitespace char
|
|
Packit |
1422b7 |
* other than colon.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CiscoInterfaceSpec)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(c[i] == ':' || isspace(c[i])) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* first, check if we have an interface. We do this by trying
|
|
Packit |
1422b7 |
* to detect if we have an IP. If we have, obviously no interface
|
|
Packit |
1422b7 |
* is present. Otherwise, we check if we have a valid interface.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int bHaveInterface = 0;
|
|
Packit |
1422b7 |
size_t idxInterface = 0;
|
|
Packit |
1422b7 |
size_t lenInterface = 0;
|
|
Packit |
1422b7 |
int bHaveIP = 0;
|
|
Packit |
1422b7 |
size_t lenIP;
|
|
Packit |
1422b7 |
size_t idxIP = i;
|
|
Packit |
1422b7 |
if(ln_v2_parseIPv4(npb, &i, NULL, &lenIP, NULL) == 0) {
|
|
Packit |
1422b7 |
bHaveIP = 1;
|
|
Packit |
1422b7 |
i += lenIP - 1; /* position on delimiter */
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
idxInterface = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
if(isspace(c[i])) goto done;
|
|
Packit |
1422b7 |
if(c[i] == ':')
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
lenInterface = i - idxInterface;
|
|
Packit |
1422b7 |
bHaveInterface = 1;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto done;
|
|
Packit |
1422b7 |
++i; /* skip over colon */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* we now utilize our other parser helpers */
|
|
Packit |
1422b7 |
if(!bHaveIP) {
|
|
Packit |
1422b7 |
idxIP = i;
|
|
Packit |
1422b7 |
if(ln_v2_parseIPv4(npb, &i, NULL, &lenIP, NULL) != 0) goto done;
|
|
Packit |
1422b7 |
i += lenIP;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i] != '/') goto done;
|
|
Packit |
1422b7 |
++i; /* skip slash */
|
|
Packit |
1422b7 |
const size_t idxPort = i;
|
|
Packit |
1422b7 |
size_t lenPort;
|
|
Packit |
1422b7 |
if(ln_v2_parseNumber(npb, &i, NULL, &lenPort, NULL) != 0) goto done;
|
|
Packit |
1422b7 |
i += lenPort;
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto success;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if optional second ip/port is present
|
|
Packit |
1422b7 |
* We assume we must at least have 5 chars [" (::1)"]
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int bHaveIP2 = 0;
|
|
Packit |
1422b7 |
size_t idxIP2 = 0, lenIP2 = 0;
|
|
Packit |
1422b7 |
size_t idxPort2 = 0, lenPort2 = 0;
|
|
Packit |
1422b7 |
if(i+5 < npb->strLen && c[i] == ' ' && c[i+1] == '(') {
|
|
Packit |
1422b7 |
size_t iTmp = i+2; /* skip over " (" */
|
|
Packit |
1422b7 |
idxIP2 = iTmp;
|
|
Packit |
1422b7 |
if(ln_v2_parseIPv4(npb, &iTmp, NULL, &lenIP2, NULL) == 0) {
|
|
Packit |
1422b7 |
iTmp += lenIP2;
|
|
Packit |
1422b7 |
if(i < npb->strLen || c[iTmp] == '/') {
|
|
Packit |
1422b7 |
++iTmp; /* skip slash */
|
|
Packit |
1422b7 |
idxPort2 = iTmp;
|
|
Packit |
1422b7 |
if(ln_v2_parseNumber(npb, &iTmp, NULL, &lenPort2, NULL) == 0) {
|
|
Packit |
1422b7 |
iTmp += lenPort2;
|
|
Packit |
1422b7 |
if(iTmp < npb->strLen && c[iTmp] == ')') {
|
|
Packit |
1422b7 |
i = iTmp + 1; /* match, so use new index */
|
|
Packit |
1422b7 |
bHaveIP2 = 1;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if optional username is present
|
|
Packit |
1422b7 |
* We assume we must at least have 3 chars ["(n)"]
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int bHaveUser = 0;
|
|
Packit |
1422b7 |
size_t idxUser = 0;
|
|
Packit |
1422b7 |
size_t lenUser = 0;
|
|
Packit |
1422b7 |
if( (i+2 < npb->strLen && c[i] == '(' && !isspace(c[i+1]) )
|
|
Packit |
1422b7 |
|| (i+3 < npb->strLen && c[i] == ' ' && c[i+1] == '(' && !isspace(c[i+2])) ) {
|
|
Packit |
1422b7 |
idxUser = i + ((c[i] == ' ') ? 2 : 1); /* skip [SP]'(' */
|
|
Packit |
1422b7 |
size_t iTmp = idxUser;
|
|
Packit |
1422b7 |
while(iTmp < npb->strLen && !isspace(c[iTmp]) && c[iTmp] != ')')
|
|
Packit |
1422b7 |
++iTmp; /* just scan */
|
|
Packit |
1422b7 |
if(iTmp < npb->strLen && c[iTmp] == ')') {
|
|
Packit |
1422b7 |
i = iTmp + 1; /* we have a match, so use new index */
|
|
Packit |
1422b7 |
bHaveUser = 1;
|
|
Packit |
1422b7 |
lenUser = iTmp - idxUser;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* all done, save data */
|
|
Packit |
1422b7 |
if(value == NULL)
|
|
Packit |
1422b7 |
goto success;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_object());
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
if(bHaveInterface) {
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxInterface, lenInterface));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "interface", json,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxIP, lenIP));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "ip", json, JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxPort, lenPort));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "port", json, JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
if(bHaveIP2) {
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxIP2, lenIP2));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "ip2", json,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxPort2, lenPort2));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "port2", json,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(bHaveUser) {
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(c+idxUser, lenUser));
|
|
Packit |
1422b7 |
json_object_object_add_ex(*value, "user", json,
|
|
Packit |
1422b7 |
JSON_C_OBJECT_ADD_KEY_IS_NEW|JSON_C_OBJECT_KEY_IS_CONSTANT);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
success: /* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0 && value != NULL && *value != NULL) {
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
*value = NULL; /* to be on the save side */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a duration. A duration is similar to a timestamp, except that
|
|
Packit |
1422b7 |
* it tells about time elapsed. As such, hours can be larger than 23
|
|
Packit |
1422b7 |
* and hours may also be specified by a single digit (this, for example,
|
|
Packit |
1422b7 |
* is commonly done in Cisco software).
|
|
Packit |
1422b7 |
* Note: we do manual loop unrolling -- this is fast AND efficient.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Duration)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* hour is a bit tricky */
|
|
Packit |
1422b7 |
if(!myisdigit(c[i])) goto done;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(myisdigit(c[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(c[i] == ':')
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i+5 > npb->strLen)
|
|
Packit |
1422b7 |
goto done;/* if it is not 5 chars from here, it can't be us */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(c[i] < '0' || c[i] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+1])) goto done;
|
|
Packit |
1422b7 |
if(c[i+2] != ':') goto done;
|
|
Packit |
1422b7 |
if(c[i+3] < '0' || c[i+3] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+4])) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = (i + 5) - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a timestamp in 24hr format (exactly HH:MM:SS).
|
|
Packit |
1422b7 |
* Note: we do manual loop unrolling -- this is fast AND efficient.
|
|
Packit |
1422b7 |
* rgerhards, 2011-01-14
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Time24hr)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*offs+8 > npb->strLen)
|
|
Packit |
1422b7 |
goto done; /* if it is not 8 chars, it can't be us */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* hour */
|
|
Packit |
1422b7 |
if(c[i] == '0' || c[i] == '1') {
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+1])) goto done;
|
|
Packit |
1422b7 |
} else if(c[i] == '2') {
|
|
Packit |
1422b7 |
if(c[i+1] < '0' || c[i+1] > '3') goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* TODO: the code below is a duplicate of 24hr parser - create common function */
|
|
Packit |
1422b7 |
if(c[i+2] != ':') goto done;
|
|
Packit |
1422b7 |
if(c[i+3] < '0' || c[i+3] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+4])) goto done;
|
|
Packit |
1422b7 |
if(c[i+5] != ':') goto done;
|
|
Packit |
1422b7 |
if(c[i+6] < '0' || c[i+6] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+7])) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = 8;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a timestamp in 12hr format (exactly HH:MM:SS).
|
|
Packit |
1422b7 |
* Note: we do manual loop unrolling -- this is fast AND efficient.
|
|
Packit |
1422b7 |
* TODO: the code below is a duplicate of 24hr parser - create common function?
|
|
Packit |
1422b7 |
* rgerhards, 2011-01-14
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Time12hr)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(*offs+8 > npb->strLen)
|
|
Packit |
1422b7 |
goto done; /* if it is not 8 chars, it can't be us */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* hour */
|
|
Packit |
1422b7 |
if(c[i] == '0') {
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+1])) goto done;
|
|
Packit |
1422b7 |
} else if(c[i] == '1') {
|
|
Packit |
1422b7 |
if(c[i+1] < '0' || c[i+1] > '2') goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(c[i+2] != ':') goto done;
|
|
Packit |
1422b7 |
if(c[i+3] < '0' || c[i+3] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+4])) goto done;
|
|
Packit |
1422b7 |
if(c[i+5] != ':') goto done;
|
|
Packit |
1422b7 |
if(c[i+6] < '0' || c[i+6] > '5') goto done;
|
|
Packit |
1422b7 |
if(!myisdigit(c[i+7])) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = 8;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* helper to IPv4 address parser, checks the next set of numbers.
|
|
Packit |
1422b7 |
* Syntax 1 to 3 digits, value together not larger than 255.
|
|
Packit |
1422b7 |
* @param[in] npb->str parse buffer
|
|
Packit |
1422b7 |
* @param[in/out] offs offset into buffer, updated if successful
|
|
Packit |
1422b7 |
* @return 0 if OK, 1 otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
chkIPv4AddrByte(npb_t *const npb, size_t *offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int val = 0;
|
|
Packit |
1422b7 |
int r = 1; /* default: done -- simplifies things */
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
if(i == npb->strLen || !myisdigit(c[i]))
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
val = c[i++] - '0';
|
|
Packit |
1422b7 |
if(i < npb->strLen && myisdigit(c[i])) {
|
|
Packit |
1422b7 |
val = val * 10 + c[i++] - '0';
|
|
Packit |
1422b7 |
if(i < npb->strLen && myisdigit(c[i]))
|
|
Packit |
1422b7 |
val = val * 10 + c[i++] - '0';
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(val > 255) /* cannot be a valid IP address byte! */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*offs = i;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for IPv4 addresses.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(IPv4)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
if(i + 7 > npb->strLen) {
|
|
Packit |
1422b7 |
/* IPv4 addr requires at least 7 characters */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* byte 1*/
|
|
Packit |
1422b7 |
if(chkIPv4AddrByte(npb, &i) != 0) goto done;
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i++] != '.') goto done;
|
|
Packit |
1422b7 |
/* byte 2*/
|
|
Packit |
1422b7 |
if(chkIPv4AddrByte(npb, &i) != 0) goto done;
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i++] != '.') goto done;
|
|
Packit |
1422b7 |
/* byte 3*/
|
|
Packit |
1422b7 |
if(chkIPv4AddrByte(npb, &i) != 0) goto done;
|
|
Packit |
1422b7 |
if(i == npb->strLen || c[i++] != '.') goto done;
|
|
Packit |
1422b7 |
/* byte 4 - we do NOT need any char behind it! */
|
|
Packit |
1422b7 |
if(chkIPv4AddrByte(npb, &i) != 0) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* if we reach this point, we found a valid IP address */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* skip past the IPv6 address block, parse pointer is set to
|
|
Packit |
1422b7 |
* first char after the block. Returns an error if already at end
|
|
Packit |
1422b7 |
* of string.
|
|
Packit |
1422b7 |
* @param[in] npb->str parse buffer
|
|
Packit |
1422b7 |
* @param[in/out] offs offset into buffer, updated if successful
|
|
Packit |
1422b7 |
* @return 0 if OK, 1 otherwise
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
skipIPv6AddrBlock(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ offs)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int j;
|
|
Packit |
1422b7 |
if(*offs == npb->strLen)
|
|
Packit |
1422b7 |
return 1;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
for(j = 0 ; j < 4 && *offs+j < npb->strLen && isxdigit(npb->str[*offs+j]) ; ++j)
|
|
Packit |
1422b7 |
/*just skip*/ ;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*offs += j;
|
|
Packit |
1422b7 |
return 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for IPv6 addresses.
|
|
Packit |
1422b7 |
* Bases on RFC4291 Section 2.2. The address must be followed
|
|
Packit |
1422b7 |
* by whitespace or end-of-string, else it is not considered
|
|
Packit |
1422b7 |
* a valid address. This prevents false positives.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(IPv6)
|
|
Packit |
1422b7 |
const char *c;
|
|
Packit |
1422b7 |
size_t i;
|
|
Packit |
1422b7 |
size_t beginBlock; /* last block begin in case we need IPv4 parsing */
|
|
Packit |
1422b7 |
int hasIPv4 = 0;
|
|
Packit |
1422b7 |
int nBlocks = 0; /* how many blocks did we already have? */
|
|
Packit |
1422b7 |
int bHad0Abbrev = 0; /* :: already used? */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
if(i + 2 > npb->strLen) {
|
|
Packit |
1422b7 |
/* IPv6 addr requires at least 2 characters ("::") */
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
c = npb->str;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check that first block is non-empty */
|
|
Packit |
1422b7 |
if(! ( isxdigit(c[i]) || (c[i] == ':' && c[i+1] == ':') ) )
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* try for all potential blocks plus one more (so we see errors!) */
|
|
Packit |
1422b7 |
for(int j = 0 ; j < 9 ; ++j) {
|
|
Packit |
1422b7 |
beginBlock = i;
|
|
Packit |
1422b7 |
if(skipIPv6AddrBlock(npb, &i) != 0) goto done;
|
|
Packit |
1422b7 |
nBlocks++;
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto chk_ok;
|
|
Packit |
1422b7 |
if(isspace(c[i])) goto chk_ok;
|
|
Packit |
1422b7 |
if(c[i] == '.'){ /* IPv4 processing! */
|
|
Packit |
1422b7 |
hasIPv4 = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(c[i] != ':') goto done;
|
|
Packit |
1422b7 |
i++; /* "eat" ':' */
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto chk_ok;
|
|
Packit |
1422b7 |
/* check for :: */
|
|
Packit |
1422b7 |
if(bHad0Abbrev) {
|
|
Packit |
1422b7 |
if(c[i] == ':') goto done;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(c[i] == ':') {
|
|
Packit |
1422b7 |
bHad0Abbrev = 1;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto chk_ok;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(hasIPv4) {
|
|
Packit |
1422b7 |
size_t ipv4_parsed;
|
|
Packit |
1422b7 |
--nBlocks;
|
|
Packit |
1422b7 |
/* prevent pure IPv4 address to be recognized */
|
|
Packit |
1422b7 |
if(beginBlock == *offs) goto done;
|
|
Packit |
1422b7 |
i = beginBlock;
|
|
Packit |
1422b7 |
if(ln_v2_parseIPv4(npb, &i, NULL, &ipv4_parsed, NULL) != 0)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
i += ipv4_parsed;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
chk_ok: /* we are finished parsing, check if things are ok */
|
|
Packit |
1422b7 |
if(nBlocks > 8) goto done;
|
|
Packit |
1422b7 |
if(bHad0Abbrev && nBlocks >= 8) goto done;
|
|
Packit |
1422b7 |
/* now check if trailing block is missing. Note that i is already
|
|
Packit |
1422b7 |
* on next character, so we need to go two back. Two are always
|
|
Packit |
1422b7 |
* present, else we would not reach this code here.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(c[i-1] == ':' && c[i-2] != ':') goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* if we reach this point, we found a valid IP address */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json_object_new_string_len(npb->str+(*offs), *parsed);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if a char is valid inside a name of the iptables motif.
|
|
Packit |
1422b7 |
* We try to keep the set as slim as possible, because the iptables
|
|
Packit |
1422b7 |
* parser may otherwise create a very broad match (especially the
|
|
Packit |
1422b7 |
* inclusion of simple words like "DF" cause grief here).
|
|
Packit |
1422b7 |
* Note: we have taken the permitted set from iptables log samples.
|
|
Packit |
1422b7 |
* Report bugs if we missed some additional rules.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
isValidIPTablesNameChar(const char c)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
/* right now, upper case only is valid */
|
|
Packit |
1422b7 |
return ('A' <= c && c <= 'Z') ? 1 : 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* helper to iptables parser, parses out a a single name=value pair
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
parseIPTablesNameValue(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ offs,
|
|
Packit |
1422b7 |
struct json_object *const __restrict__ valroot)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_WRONGPARSER;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
char *name = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t iName = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen && isValidIPTablesNameChar(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(i == iName || (i < npb->strLen && npb->str[i] != '=' && npb->str[i] != ' '))
|
|
Packit |
1422b7 |
goto done; /* no name at all! */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const ssize_t lenName = i - iName;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
ssize_t iVal = -1;
|
|
Packit |
1422b7 |
size_t lenVal = i - iVal;
|
|
Packit |
1422b7 |
if(i < npb->strLen && npb->str[i] != ' ') {
|
|
Packit |
1422b7 |
/* we have a real value (not just a flag name like "DF") */
|
|
Packit |
1422b7 |
++i; /* skip '=' */
|
|
Packit |
1422b7 |
iVal = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen && !isspace(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
lenVal = i - iVal;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parsing OK */
|
|
Packit |
1422b7 |
*offs = i;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(valroot == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
CHKN(name = malloc(lenName+1));
|
|
Packit |
1422b7 |
memcpy(name, npb->str+iName, lenName);
|
|
Packit |
1422b7 |
name[lenName] = '\0';
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
if(iVal == -1) {
|
|
Packit |
1422b7 |
json = NULL;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(npb->str+iVal, lenVal));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_object_add(valroot, name, json);
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(name);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for iptables logs (the structured part).
|
|
Packit |
1422b7 |
* This parser is named "v2-iptables" because of a traditional
|
|
Packit |
1422b7 |
* parser named "iptables", which we do not want to replace, at
|
|
Packit |
1422b7 |
* least right now (we may re-think this before the first release).
|
|
Packit |
1422b7 |
* For performance reasons, this works in two stages. In the first
|
|
Packit |
1422b7 |
* stage, we only detect if the motif is correct. The second stage is
|
|
Packit |
1422b7 |
* only called when we know it is. In it, we go once again over the
|
|
Packit |
1422b7 |
* message again and actually extract the data. This is done because
|
|
Packit |
1422b7 |
* data extraction is relatively expensive and in most cases we will
|
|
Packit |
1422b7 |
* have much more frequent mismatches than matches.
|
|
Packit |
1422b7 |
* Note that this motif must have at least one field, otherwise it
|
|
Packit |
1422b7 |
* could detect things that are not iptables to be it. Further limits
|
|
Packit |
1422b7 |
* may be imposed in the future as we see additional need.
|
|
Packit |
1422b7 |
* added 2015-04-30 rgerhards
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(v2IPTables)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
int nfields = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* stage one */
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
CHKR(parseIPTablesNameValue(npb, &i, NULL));
|
|
Packit |
1422b7 |
++nfields;
|
|
Packit |
1422b7 |
/* exactly one SP is permitted between fields */
|
|
Packit |
1422b7 |
if(i < npb->strLen && npb->str[i] == ' ')
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(nfields < 2) {
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* stage two */
|
|
Packit |
1422b7 |
if(value == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_object());
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
CHKR(parseIPTablesNameValue(npb, &i, *value));
|
|
Packit |
1422b7 |
while(i < npb->strLen && isspace(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0 && value != NULL && *value != NULL) {
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
*value = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse JSON. This parser tries to find JSON data inside a message.
|
|
Packit |
1422b7 |
* If it finds valid JSON, it will extract it. Extra data after the
|
|
Packit |
1422b7 |
* JSON is permitted.
|
|
Packit |
1422b7 |
* Note: the json-c JSON parser treats whitespace after the actual
|
|
Packit |
1422b7 |
* json to be part of the json. So in essence, any whitespace is
|
|
Packit |
1422b7 |
* processed by this parser. We use the same semantics to keep things
|
|
Packit |
1422b7 |
* neatly in sync. If json-c changes for some reason or we switch to
|
|
Packit |
1422b7 |
* an alternate json lib, we probably need to be sure to keep that
|
|
Packit |
1422b7 |
* behaviour, and probably emulate it.
|
|
Packit |
1422b7 |
* added 2015-04-28 by rgerhards, v1.1.2
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(JSON)
|
|
Packit |
1422b7 |
const size_t i = *offs;
|
|
Packit |
1422b7 |
struct json_tokener *tokener = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(npb->str[i] != '{' && npb->str[i] != ']') {
|
|
Packit |
1422b7 |
/* this can't be json, see RFC4627, Sect. 2
|
|
Packit |
1422b7 |
* see this bug in json-c:
|
|
Packit |
1422b7 |
* https://github.com/json-c/json-c/issues/181
|
|
Packit |
1422b7 |
* In any case, it's better to do this quick check,
|
|
Packit |
1422b7 |
* even if json-c did not have the bug because this
|
|
Packit |
1422b7 |
* check here is much faster than calling the parser.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((tokener = json_tokener_new()) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object *const json
|
|
Packit |
1422b7 |
= json_tokener_parse_ex(tokener, npb->str+i, (int) (npb->strLen - i));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = (i + tokener->char_offset) - *offs;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value == NULL) {
|
|
Packit |
1422b7 |
json_object_put(json);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*value = json;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(tokener != NULL)
|
|
Packit |
1422b7 |
json_tokener_free(tokener);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check if a char is valid inside a name of a NameValue list
|
|
Packit |
1422b7 |
* The set of valid characters may be extended if there is good
|
|
Packit |
1422b7 |
* need to do so. We have selected the current set carefully, but
|
|
Packit |
1422b7 |
* may have overlooked some cases.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
isValidNameChar(const char c)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
return (isalnum(c)
|
|
Packit |
1422b7 |
|| c == '.'
|
|
Packit |
1422b7 |
|| c == '_'
|
|
Packit |
1422b7 |
|| c == '-'
|
|
Packit |
1422b7 |
) ? 1 : 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/* helper to NameValue parser, parses out a a single name=value pair
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* name must be alphanumeric characters, value must be non-whitespace
|
|
Packit |
1422b7 |
* characters, if quoted than with symmetric quotes. Supported formats
|
|
Packit |
1422b7 |
* - name=value
|
|
Packit |
1422b7 |
* - name="value"
|
|
Packit |
1422b7 |
* - name='value'
|
|
Packit |
1422b7 |
* Note "name=" is valid and means a field with empty value.
|
|
Packit |
1422b7 |
* TODO: so far, quote characters are not permitted WITHIN quoted values.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
parseNameValue(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ offs,
|
|
Packit |
1422b7 |
struct json_object *const __restrict__ valroot)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = LN_WRONGPARSER;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
char *name = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t iName = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen && isValidNameChar(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(i == iName || npb->str[i] != '=')
|
|
Packit |
1422b7 |
goto done; /* no name at all! */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t lenName = i - iName;
|
|
Packit |
1422b7 |
++i; /* skip '=' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t iVal = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen && !isspace(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
const size_t lenVal = i - iVal;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parsing OK */
|
|
Packit |
1422b7 |
*offs = i;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(valroot == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
CHKN(name = malloc(lenName+1));
|
|
Packit |
1422b7 |
memcpy(name, npb->str+iName, lenName);
|
|
Packit |
1422b7 |
name[lenName] = '\0';
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string_len(npb->str+iVal, lenVal));
|
|
Packit |
1422b7 |
json_object_object_add(valroot, name, json);
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(name);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse CEE syslog.
|
|
Packit |
1422b7 |
* This essentially is a JSON parser, with additional restrictions:
|
|
Packit |
1422b7 |
* The message must start with "@cee:" and json must immediately follow (whitespace permitted).
|
|
Packit |
1422b7 |
* after the JSON, there must be no other non-whitespace characters.
|
|
Packit |
1422b7 |
* In other words: the message must consist of a single JSON object,
|
|
Packit |
1422b7 |
* only.
|
|
Packit |
1422b7 |
* added 2015-04-28 by rgerhards, v1.1.2
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CEESyslog)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
struct json_tokener *tokener = NULL;
|
|
Packit |
1422b7 |
struct json_object *json = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(npb->strLen < i + 7 || /* "@cee:{}" is minimum text */
|
|
Packit |
1422b7 |
npb->str[i] != '@' ||
|
|
Packit |
1422b7 |
npb->str[i+1] != 'c' ||
|
|
Packit |
1422b7 |
npb->str[i+2] != 'e' ||
|
|
Packit |
1422b7 |
npb->str[i+3] != 'e' ||
|
|
Packit |
1422b7 |
npb->str[i+4] != ':')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* skip whitespace */
|
|
Packit |
1422b7 |
for(i += 5 ; i < npb->strLen && isspace(npb->str[i]) ; ++i)
|
|
Packit |
1422b7 |
/* just skip */;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == npb->strLen || npb->str[i] != '{')
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
/* note: we do not permit arrays in CEE mode */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((tokener = json_tokener_new()) == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json = json_tokener_parse_ex(tokener, npb->str+i, (int) (npb->strLen - i));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i + tokener->char_offset != npb->strLen)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = npb->strLen;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
*value = json;
|
|
Packit |
1422b7 |
json = NULL; /* do NOT free below! */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(tokener != NULL)
|
|
Packit |
1422b7 |
json_tokener_free(tokener);
|
|
Packit |
1422b7 |
if(json != NULL)
|
|
Packit |
1422b7 |
json_object_put(json);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for name/value pairs.
|
|
Packit |
1422b7 |
* On entry must point to alnum char. All following chars must be
|
|
Packit |
1422b7 |
* name/value pairs delimited by whitespace up until the end of string.
|
|
Packit |
1422b7 |
* For performance reasons, this works in two stages. In the first
|
|
Packit |
1422b7 |
* stage, we only detect if the motif is correct. The second stage is
|
|
Packit |
1422b7 |
* only called when we know it is. In it, we go once again over the
|
|
Packit |
1422b7 |
* message again and actually extract the data. This is done because
|
|
Packit |
1422b7 |
* data extraction is relatively expensive and in most cases we will
|
|
Packit |
1422b7 |
* have much more frequent mismatches than matches.
|
|
Packit |
1422b7 |
* added 2015-04-25 rgerhards
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(NameValue)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* stage one */
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
CHKR(parseNameValue(npb, &i, NULL));
|
|
Packit |
1422b7 |
while(i < npb->strLen && isspace(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* stage two */
|
|
Packit |
1422b7 |
if(value == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i = *offs;
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_object());
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
CHKR(parseNameValue(npb, &i, *value));
|
|
Packit |
1422b7 |
while(i < npb->strLen && isspace(npb->str[i]))
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* TODO: fix mem leak if alloc json fails */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parse a MAC layer address.
|
|
Packit |
1422b7 |
* The standard (IEEE 802) format for printing MAC-48 addresses in
|
|
Packit |
1422b7 |
* human-friendly form is six groups of two hexadecimal digits,
|
|
Packit |
1422b7 |
* separated by hyphens (-) or colons (:), in transmission order
|
|
Packit |
1422b7 |
* (e.g. 01-23-45-67-89-ab or 01:23:45:67:89:ab ).
|
|
Packit |
1422b7 |
* This form is also commonly used for EUI-64.
|
|
Packit |
1422b7 |
* from: http://en.wikipedia.org/wiki/MAC_address
|
|
Packit |
1422b7 |
*
|
|
Packit |
1422b7 |
* This parser must start on a hex digit.
|
|
Packit |
1422b7 |
* added 2015-05-04 by rgerhards, v1.1.2
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(MAC48)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
char delim;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(npb->strLen < i + 17 || /* this motif has exactly 17 characters */
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+1])
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(npb->str[i+2] == ':')
|
|
Packit |
1422b7 |
delim = ':';
|
|
Packit |
1422b7 |
else if(npb->str[i+2] == '-')
|
|
Packit |
1422b7 |
delim = '-';
|
|
Packit |
1422b7 |
else
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* first byte ok */
|
|
Packit |
1422b7 |
if(!isxdigit(npb->str[i+3]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+4]) ||
|
|
Packit |
1422b7 |
npb->str[i+5] != delim || /* 2nd byte ok */
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+6]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+7]) ||
|
|
Packit |
1422b7 |
npb->str[i+8] != delim || /* 3rd byte ok */
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+9]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+10]) ||
|
|
Packit |
1422b7 |
npb->str[i+11] != delim || /* 4th byte ok */
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+12]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+13]) ||
|
|
Packit |
1422b7 |
npb->str[i+14] != delim || /* 5th byte ok */
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+15]) ||
|
|
Packit |
1422b7 |
!isxdigit(npb->str[i+16]) /* 6th byte ok */
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = 17;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_string_len(npb->str+i, 17));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* This parses the extension value and updates the index
|
|
Packit |
1422b7 |
* to point to the end of it.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
cefParseExtensionValue(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *__restrict__ iEndVal)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
size_t i = *iEndVal;
|
|
Packit |
1422b7 |
size_t iLastWordBegin;
|
|
Packit |
1422b7 |
/* first find next unquoted equal sign and record begin of
|
|
Packit |
1422b7 |
* last word in front of it - this is the actual end of the
|
|
Packit |
1422b7 |
* current name/value pair and the begin of the next one.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
int hadSP = 0;
|
|
Packit |
1422b7 |
int inEscape = 0;
|
|
Packit |
1422b7 |
for(iLastWordBegin = 0 ; i < npb->strLen ; ++i) {
|
|
Packit |
1422b7 |
if(inEscape) {
|
|
Packit |
1422b7 |
if(npb->str[i] != '=' &&
|
|
Packit |
1422b7 |
npb->str[i] != '\\' &&
|
|
Packit |
1422b7 |
npb->str[i] != 'r' &&
|
|
Packit |
1422b7 |
npb->str[i] != 'n')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
inEscape = 0;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(npb->str[i] == '=') {
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
} else if(npb->str[i] == '\\') {
|
|
Packit |
1422b7 |
inEscape = 1;
|
|
Packit |
1422b7 |
} else if(npb->str[i] == ' ') {
|
|
Packit |
1422b7 |
hadSP = 1;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
if(hadSP) {
|
|
Packit |
1422b7 |
iLastWordBegin = i;
|
|
Packit |
1422b7 |
hadSP = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* Note: iLastWordBegin can never be at offset zero, because
|
|
Packit |
1422b7 |
* the CEF header starts there!
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
if(i < npb->strLen) {
|
|
Packit |
1422b7 |
*iEndVal = (iLastWordBegin == 0) ? i : iLastWordBegin - 1;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*iEndVal = i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* must be positioned on first char of name, returns index
|
|
Packit |
1422b7 |
* of end of name.
|
|
Packit |
1422b7 |
* Note: ArcSight violates the CEF spec ifself: they generate
|
|
Packit |
1422b7 |
* leading underscores in their extension names, which are
|
|
Packit |
1422b7 |
* definetly not alphanumeric. We still accept them...
|
|
Packit |
1422b7 |
* They also seem to use dots.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
cefParseName(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ i)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
while(*i < npb->strLen && npb->str[*i] != '=') {
|
|
Packit |
1422b7 |
if(!(isalnum(npb->str[*i]) || npb->str[*i] == '_' || npb->str[*i] == '.'))
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
++(*i);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* parse CEF extensions. They are basically name=value
|
|
Packit |
1422b7 |
* pairs with the ugly exception that values may contain
|
|
Packit |
1422b7 |
* spaces but need NOT to be quoted. Thankfully, at least
|
|
Packit |
1422b7 |
* names are specified as being alphanumeric without spaces
|
|
Packit |
1422b7 |
* in them. So we must add a lookahead parser to check if
|
|
Packit |
1422b7 |
* a word is a name (and thus the begin of a new pair) or
|
|
Packit |
1422b7 |
* not. This is done by subroutines.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
cefParseExtensions(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ offs,
|
|
Packit |
1422b7 |
json_object *const __restrict__ jroot)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
size_t iName, lenName;
|
|
Packit |
1422b7 |
size_t iValue, lenValue;
|
|
Packit |
1422b7 |
char *name = NULL;
|
|
Packit |
1422b7 |
char *value = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] == ' ')
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
iName = i;
|
|
Packit |
1422b7 |
CHKR(cefParseName(npb, &i);;
|
|
Packit |
1422b7 |
if(i+1 >= npb->strLen || npb->str[i] != '=')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
lenName = i - iName;
|
|
Packit |
1422b7 |
++i; /* skip '=' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
iValue = i;
|
|
Packit |
1422b7 |
CHKR(cefParseExtensionValue(npb, &i);;
|
|
Packit |
1422b7 |
lenValue = i - iValue;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
++i; /* skip past value */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(jroot != NULL) {
|
|
Packit |
1422b7 |
CHKN(name = malloc(sizeof(char) * (lenName + 1)));
|
|
Packit |
1422b7 |
memcpy(name, npb->str+iName, lenName);
|
|
Packit |
1422b7 |
name[lenName] = '\0';
|
|
Packit |
1422b7 |
CHKN(value = malloc(sizeof(char) * (lenValue + 1)));
|
|
Packit |
1422b7 |
/* copy value but escape it */
|
|
Packit |
1422b7 |
size_t iDst = 0;
|
|
Packit |
1422b7 |
for(size_t iSrc = 0 ; iSrc < lenValue ; ++iSrc) {
|
|
Packit |
1422b7 |
if(npb->str[iValue+iSrc] == '\\') {
|
|
Packit |
1422b7 |
++iSrc; /* we know the next char must exist! */
|
|
Packit |
1422b7 |
switch(npb->str[iValue+iSrc]) {
|
|
Packit |
1422b7 |
case '=': value[iDst] = '=';
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'n': value[iDst] = '\n';
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case 'r': value[iDst] = '\r';
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
case '\\': value[iDst] = '\\';
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
default: break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
value[iDst] = npb->str[iValue+iSrc];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
++iDst;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
value[iDst] = '\0';
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(value));
|
|
Packit |
1422b7 |
json_object_object_add(jroot, name, json);
|
|
Packit |
1422b7 |
free(name); name = NULL;
|
|
Packit |
1422b7 |
free(value); value = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
*offs = npb->strLen; /* this parser consume everything or fails */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(name);
|
|
Packit |
1422b7 |
free(value);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* gets a CEF header field. Must be positioned on the
|
|
Packit |
1422b7 |
* first char after the '|' in front of field.
|
|
Packit |
1422b7 |
* Note that '|' may be escaped as "\|", which also means
|
|
Packit |
1422b7 |
* we need to supprot "\\" (see CEF spec for details).
|
|
Packit |
1422b7 |
* We return the string in *val, if val is non-null. In
|
|
Packit |
1422b7 |
* that case we allocate memory that the caller must free.
|
|
Packit |
1422b7 |
* This is necessary because there are potentially escape
|
|
Packit |
1422b7 |
* sequences inside the string.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
cefGetHdrField(npb_t *const npb,
|
|
Packit |
1422b7 |
size_t *const __restrict__ offs,
|
|
Packit |
1422b7 |
char **val)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
assert(npb->str[i] != '|');
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] != '|') {
|
|
Packit |
1422b7 |
if(npb->str[i] == '\\') {
|
|
Packit |
1422b7 |
++i; /* skip esc char */
|
|
Packit |
1422b7 |
if(npb->str[i] != '\\' && npb->str[i] != '|')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
++i; /* scan to next delimiter */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(npb->str[i] != '|')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t iBegin = *offs;
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*offs = i + 1;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(val == NULL) {
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t len = i - iBegin;
|
|
Packit |
1422b7 |
CHKN(*val = malloc(len + 1));
|
|
Packit |
1422b7 |
size_t iDst = 0;
|
|
Packit |
1422b7 |
for(size_t iSrc = 0 ; iSrc < len ; ++iSrc) {
|
|
Packit |
1422b7 |
if(npb->str[iBegin+iSrc] == '\\')
|
|
Packit |
1422b7 |
++iSrc; /* we already checked above that this is OK! */
|
|
Packit |
1422b7 |
(*val)[iDst++] = npb->str[iBegin+iSrc];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
(*val)[iDst] = 0;
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for ArcSight Common Event Format (CEF) version 0.
|
|
Packit |
1422b7 |
* added 2015-05-05 by rgerhards, v1.1.2
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CEF)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
char *vendor = NULL;
|
|
Packit |
1422b7 |
char *product = NULL;
|
|
Packit |
1422b7 |
char *version = NULL;
|
|
Packit |
1422b7 |
char *sigID = NULL;
|
|
Packit |
1422b7 |
char *name = NULL;
|
|
Packit |
1422b7 |
char *severity = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* minumum header: "CEF:0|x|x|x|x|x|x|" --> 17 chars */
|
|
Packit |
1422b7 |
if(npb->strLen < i + 17 ||
|
|
Packit |
1422b7 |
npb->str[i] != 'C' ||
|
|
Packit |
1422b7 |
npb->str[i+1] != 'E' ||
|
|
Packit |
1422b7 |
npb->str[i+2] != 'F' ||
|
|
Packit |
1422b7 |
npb->str[i+3] != ':' ||
|
|
Packit |
1422b7 |
npb->str[i+4] != '0' ||
|
|
Packit |
1422b7 |
npb->str[i+5] != '|'
|
|
Packit |
1422b7 |
) FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i += 6; /* position on '|' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &vendor));
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &product));
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &version));
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &sigID));
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &name));
|
|
Packit |
1422b7 |
CHKR(cefGetHdrField(npb, &i, (value == NULL) ? NULL : &severity));
|
|
Packit |
1422b7 |
++i; /* skip over terminal '|' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* OK, we now know we have a good header. Now, we need
|
|
Packit |
1422b7 |
* to process extensions.
|
|
Packit |
1422b7 |
* This time, we do NOT pre-process the extension, but rather
|
|
Packit |
1422b7 |
* persist them directly to JSON. This is contrary to other
|
|
Packit |
1422b7 |
* parsers, but as the CEF header is pretty unique, this time
|
|
Packit |
1422b7 |
* it is exteremely unlike we will get a no-match during
|
|
Packit |
1422b7 |
* extension processing. Even if so, nothing bad happens, as
|
|
Packit |
1422b7 |
* the extracted data is discarded. But the regular case saves
|
|
Packit |
1422b7 |
* us processing time and complexity. The only time when we
|
|
Packit |
1422b7 |
* cannot directly process it is when the caller asks us not
|
|
Packit |
1422b7 |
* to persist the data. So this must be handled differently.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
size_t iBeginExtensions = i;
|
|
Packit |
1422b7 |
CHKR(cefParseExtensions(npb, &i, NULL));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_object());
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(vendor));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "DeviceVendor", json);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(product));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "DeviceProduct", json);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(version));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "DeviceVersion", json);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(sigID));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "SignatureID", json);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(name));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "Name", json);
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(severity));
|
|
Packit |
1422b7 |
json_object_object_add(*value, "Severity", json);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json_object *jext;
|
|
Packit |
1422b7 |
CHKN(jext = json_object_new_object());
|
|
Packit |
1422b7 |
json_object_object_add(*value, "Extensions", jext);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
i = iBeginExtensions;
|
|
Packit |
1422b7 |
cefParseExtensions(npb, &i, jext);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0 && value != NULL && *value != NULL) {
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
value = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
free(vendor);
|
|
Packit |
1422b7 |
free(product);
|
|
Packit |
1422b7 |
free(version);
|
|
Packit |
1422b7 |
free(sigID);
|
|
Packit |
1422b7 |
free(name);
|
|
Packit |
1422b7 |
free(severity);
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* Parser for Checkpoint LEA on-disk format.
|
|
Packit |
1422b7 |
* added 2015-06-18 by rgerhards, v1.1.2
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(CheckpointLEA)
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
size_t iName, lenName;
|
|
Packit |
1422b7 |
size_t iValue, lenValue;
|
|
Packit |
1422b7 |
int foundFields = 0;
|
|
Packit |
1422b7 |
char *name = NULL;
|
|
Packit |
1422b7 |
char *val = NULL;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] == ' ') /* skip leading SP */
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
if(i == npb->strLen) { /* OK if just trailing space */
|
|
Packit |
1422b7 |
if(foundFields == 0)
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
break; /* we are done with the loop, all processed */
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
++foundFields;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
iName = i;
|
|
Packit |
1422b7 |
/* TODO: do a stricter check? ... but we don't have a spec */
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] != ':') {
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i+1 >= npb->strLen || npb->str[i] != ':')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
lenName = i - iName;
|
|
Packit |
1422b7 |
++i; /* skip ':' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] == ' ') /* skip leading SP */
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
iValue = i;
|
|
Packit |
1422b7 |
while(i < npb->strLen && npb->str[i] != ';') {
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(i+1 > npb->strLen || npb->str[i] != ';')
|
|
Packit |
1422b7 |
FAIL(LN_WRONGPARSER);
|
|
Packit |
1422b7 |
lenValue = i - iValue;
|
|
Packit |
1422b7 |
++i; /* skip ';' */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
CHKN(name = malloc(sizeof(char) * (lenName + 1)));
|
|
Packit |
1422b7 |
memcpy(name, npb->str+iName, lenName);
|
|
Packit |
1422b7 |
name[lenName] = '\0';
|
|
Packit |
1422b7 |
CHKN(val = malloc(sizeof(char) * (lenValue + 1)));
|
|
Packit |
1422b7 |
memcpy(val, npb->str+iValue, lenValue);
|
|
Packit |
1422b7 |
val[lenValue] = '\0';
|
|
Packit |
1422b7 |
if(*value == NULL)
|
|
Packit |
1422b7 |
CHKN(*value = json_object_new_object());
|
|
Packit |
1422b7 |
json_object *json;
|
|
Packit |
1422b7 |
CHKN(json = json_object_new_string(val));
|
|
Packit |
1422b7 |
json_object_object_add(*value, name, json);
|
|
Packit |
1422b7 |
free(name); name = NULL;
|
|
Packit |
1422b7 |
free(val); val = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
free(name);
|
|
Packit |
1422b7 |
free(val);
|
|
Packit |
1422b7 |
if(r != 0 && value != NULL && *value != NULL) {
|
|
Packit |
1422b7 |
json_object_put(*value);
|
|
Packit |
1422b7 |
value = NULL;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* helper to repeat parser constructor: checks that dot field name
|
|
Packit |
1422b7 |
* is only present if there is one field inside the "parser" list.
|
|
Packit |
1422b7 |
* returns 1 if ok, 0 otherwise.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
static int
|
|
Packit |
1422b7 |
chkNoDupeDotInParserDefs(ln_ctx ctx, struct json_object *parsers)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 1;
|
|
Packit |
1422b7 |
int nParsers = 0;
|
|
Packit |
1422b7 |
int nDots = 0;
|
|
Packit |
1422b7 |
if(json_object_get_type(parsers) == json_type_array) {
|
|
Packit |
1422b7 |
const int maxparsers = json_object_array_length(parsers);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < maxparsers ; ++i) {
|
|
Packit |
1422b7 |
++nParsers;
|
|
Packit |
1422b7 |
struct json_object *const parser
|
|
Packit |
1422b7 |
= json_object_array_get_idx(parsers, i);
|
|
Packit |
1422b7 |
struct json_object *fname;
|
|
Packit |
1422b7 |
json_object_object_get_ex(parser, "name", &fname);
|
|
Packit |
1422b7 |
if(fname != NULL) {
|
|
Packit |
1422b7 |
if(!strcmp(json_object_get_string(fname), "."))
|
|
Packit |
1422b7 |
++nDots;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
if(nParsers > 1 && nDots > 0) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "'repeat' parser supports dot name only "
|
|
Packit |
1422b7 |
"if single parser is used in 'parser' part, invalid "
|
|
Packit |
1422b7 |
"construct: %s", json_object_get_string(parsers));
|
|
Packit |
1422b7 |
r = 0;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* "repeat" special parser.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(Repeat)
|
|
Packit |
1422b7 |
struct data_Repeat *const data = (struct data_Repeat*) pdata;
|
|
Packit |
1422b7 |
struct ln_pdag *endNode = NULL;
|
|
Packit |
1422b7 |
size_t strtoffs = *offs;
|
|
Packit |
1422b7 |
size_t lastKnownGood = strtoffs;
|
|
Packit |
1422b7 |
struct json_object *json_arr = NULL;
|
|
Packit |
1422b7 |
const size_t parsedTo_save = npb->parsedTo;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
do {
|
|
Packit |
1422b7 |
struct json_object *parsed_value = json_object_new_object();
|
|
Packit |
1422b7 |
r = ln_normalizeRec(npb, data->parser, strtoffs, 1,
|
|
Packit |
1422b7 |
parsed_value, &endNode);
|
|
Packit |
1422b7 |
strtoffs = npb->parsedTo;
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "repeat parser returns %d, parsed %zu, json: %s",
|
|
Packit |
1422b7 |
r, npb->parsedTo, json_object_to_json_string(parsed_value));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(r != 0) {
|
|
Packit |
1422b7 |
json_object_put(parsed_value);
|
|
Packit |
1422b7 |
if(data->permitMismatchInParser) {
|
|
Packit |
1422b7 |
strtoffs = lastKnownGood; /* go back to final match */
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "mismatch in repeat, "
|
|
Packit |
1422b7 |
"parse ptr back to %zd", strtoffs);
|
|
Packit |
1422b7 |
goto success;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json_arr == NULL) {
|
|
Packit |
1422b7 |
json_arr = json_object_new_array();
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* check for name=".", which means we need to place the
|
|
Packit |
1422b7 |
* value only into to array. As we do not have direct
|
|
Packit |
1422b7 |
* access to the key, we loop over our result as a work-
|
|
Packit |
1422b7 |
* around.
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
struct json_object *toAdd = parsed_value;
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(parsed_value);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(parsed_value);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(key[0] == '.' && key[1] == '\0') {
|
|
Packit |
1422b7 |
json_object_get(val); /* inc refcount! */
|
|
Packit |
1422b7 |
toAdd = val;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
json_object_array_add(json_arr, toAdd);
|
|
Packit |
1422b7 |
if(toAdd != parsed_value)
|
|
Packit |
1422b7 |
json_object_put(parsed_value);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "arr: %s", json_object_to_json_string(json_arr));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* now check if we shall continue */
|
|
Packit |
1422b7 |
npb->parsedTo = 0;
|
|
Packit |
1422b7 |
lastKnownGood = strtoffs; /* record pos in case of fail in while */
|
|
Packit |
1422b7 |
r = ln_normalizeRec(npb, data->while_cond, strtoffs, 1, NULL, &endNode);
|
|
Packit |
1422b7 |
LN_DBGPRINTF(npb->ctx, "repeat while returns %d, parsed %zu",
|
|
Packit |
1422b7 |
r, npb->parsedTo);
|
|
Packit |
1422b7 |
if(r == 0)
|
|
Packit |
1422b7 |
strtoffs = npb->parsedTo;
|
|
Packit |
1422b7 |
} while(r == 0);
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
success:
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = strtoffs - *offs;
|
|
Packit |
1422b7 |
if(value == NULL) {
|
|
Packit |
1422b7 |
json_object_put(json_arr);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*value = json_arr;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
npb->parsedTo = parsedTo_save;
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0 && json_arr != NULL) {
|
|
Packit |
1422b7 |
json_object_put(json_arr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Construct(Repeat)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_Repeat *data = (struct data_Repeat*) calloc(1, sizeof(struct data_Repeat));
|
|
Packit |
1422b7 |
struct ln_pdag *endnode; /* we need this fo ln_pdagAddParser, which updates its param! */
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(json == NULL)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcmp(key, "parser")) {
|
|
Packit |
1422b7 |
if(chkNoDupeDotInParserDefs(ctx, val) != 1) {
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
endnode = data->parser = ln_newPDAG(ctx);
|
|
Packit |
1422b7 |
json_object_get(val); /* prevent free in pdagAddParser */
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParser(ctx, &endnode, val));
|
|
Packit |
1422b7 |
endnode->flags.isTerminal = 1;
|
|
Packit |
1422b7 |
} else if(!strcmp(key, "while")) {
|
|
Packit |
1422b7 |
endnode = data->while_cond = ln_newPDAG(ctx);
|
|
Packit |
1422b7 |
json_object_get(val); /* prevent free in pdagAddParser */
|
|
Packit |
1422b7 |
CHKR(ln_pdagAddParser(ctx, &endnode, val));
|
|
Packit |
1422b7 |
endnode->flags.isTerminal = 1;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "option.permitMismatchInParser")) {
|
|
Packit |
1422b7 |
data->permitMismatchInParser = json_object_get_boolean(val);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for hexnumber: %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(val));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(data->parser == NULL || data->while_cond == NULL) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "repeat parser needs 'parser','while' parameters");
|
|
Packit |
1422b7 |
ln_destructRepeat(ctx, data);
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(Repeat)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
struct data_Repeat *const data = (struct data_Repeat*) pdata;
|
|
Packit |
1422b7 |
if(data->parser != NULL)
|
|
Packit |
1422b7 |
ln_pdagDelete(data->parser);
|
|
Packit |
1422b7 |
if(data->while_cond != NULL)
|
|
Packit |
1422b7 |
ln_pdagDelete(data->while_cond);
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* string escaping modes */
|
|
Packit |
1422b7 |
#define ST_ESC_NONE 0
|
|
Packit |
1422b7 |
#define ST_ESC_BACKSLASH 1
|
|
Packit |
1422b7 |
#define ST_ESC_DOUBLE 2
|
|
Packit |
1422b7 |
#define ST_ESC_BOTH 3
|
|
Packit |
1422b7 |
struct data_String {
|
|
Packit |
1422b7 |
enum { ST_QUOTE_AUTO = 0, ST_QUOTE_NONE = 1, ST_QUOTE_REQD = 2 }
|
|
Packit |
1422b7 |
quoteMode;
|
|
Packit |
1422b7 |
struct {
|
|
Packit |
1422b7 |
unsigned strip_quotes : 1;
|
|
Packit |
1422b7 |
unsigned esc_md : 2;
|
|
Packit |
1422b7 |
} flags;
|
|
Packit |
1422b7 |
char qchar_begin;
|
|
Packit |
1422b7 |
char qchar_end;
|
|
Packit |
1422b7 |
char perm_chars[256]; // TODO: make this bit-wise, so we need only 32 bytes
|
|
Packit |
1422b7 |
};
|
|
Packit |
1422b7 |
static inline void
|
|
Packit |
1422b7 |
stringSetPermittedChar(struct data_String *const data, char c, int val)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
#if 0
|
|
Packit |
1422b7 |
const int i = (unsigned) c / 8;
|
|
Packit |
1422b7 |
const int shft = (unsigned) c % 8;
|
|
Packit |
1422b7 |
const unsigned mask = ~(1 << shft);
|
|
Packit |
1422b7 |
perm_arr[i] = (perm_arr[i] & (0xff
|
|
Packit |
1422b7 |
#endif
|
|
Packit |
1422b7 |
data->perm_chars[(unsigned)c] = val;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static inline int
|
|
Packit |
1422b7 |
stringIsPermittedChar(struct data_String *const data, char c)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
return data->perm_chars[(unsigned)c];
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
stringAddPermittedCharArr(struct data_String *const data,
|
|
Packit |
1422b7 |
const char *const optval)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const size_t nchars = strlen(optval);
|
|
Packit |
1422b7 |
for(size_t i = 0 ; i < nchars ; ++i) {
|
|
Packit |
1422b7 |
stringSetPermittedChar(data, optval[i], 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
stringAddPermittedFromTo(struct data_String *const data,
|
|
Packit |
1422b7 |
const unsigned char from,
|
|
Packit |
1422b7 |
const unsigned char to)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
assert(from <= to);
|
|
Packit |
1422b7 |
for(size_t i = from ; i <= to ; ++i) {
|
|
Packit |
1422b7 |
stringSetPermittedChar(data, (char) i, 1);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static inline void
|
|
Packit |
1422b7 |
stringAddPermittedChars(struct data_String *const data,
|
|
Packit |
1422b7 |
struct json_object *const val)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(optval == NULL)
|
|
Packit |
1422b7 |
return;
|
|
Packit |
1422b7 |
stringAddPermittedCharArr(data, optval);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
static void
|
|
Packit |
1422b7 |
stringAddPermittedCharsViaArray(ln_ctx ctx, struct data_String *const data,
|
|
Packit |
1422b7 |
struct json_object *const arr)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
const int nelem = json_object_array_length(arr);
|
|
Packit |
1422b7 |
for(int i = 0 ; i < nelem ; ++i) {
|
|
Packit |
1422b7 |
struct json_object *const elem
|
|
Packit |
1422b7 |
= json_object_array_get_idx(arr, i);
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(elem);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(elem);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcasecmp(key, "chars")) {
|
|
Packit |
1422b7 |
stringAddPermittedChars(data, val);
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "class")) {
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcasecmp(optval, "digit")) {
|
|
Packit |
1422b7 |
stringAddPermittedCharArr(data, "0123456789");
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "hexdigit")) {
|
|
Packit |
1422b7 |
stringAddPermittedCharArr(data, "0123456789aAbBcCdDeEfF");
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "alpha")) {
|
|
Packit |
1422b7 |
stringAddPermittedFromTo(data, 'a', 'z');
|
|
Packit |
1422b7 |
stringAddPermittedFromTo(data, 'A', 'Z');
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "alnum")) {
|
|
Packit |
1422b7 |
stringAddPermittedCharArr(data, "0123456789");
|
|
Packit |
1422b7 |
stringAddPermittedFromTo(data, 'a', 'z');
|
|
Packit |
1422b7 |
stringAddPermittedFromTo(data, 'A', 'Z');
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid character class '%s'",
|
|
Packit |
1422b7 |
optval);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
/**
|
|
Packit |
1422b7 |
* generic string parser
|
|
Packit |
1422b7 |
*/
|
|
Packit |
1422b7 |
PARSER_Parse(String)
|
|
Packit |
1422b7 |
assert(npb->str != NULL);
|
|
Packit |
1422b7 |
assert(offs != NULL);
|
|
Packit |
1422b7 |
assert(parsed != NULL);
|
|
Packit |
1422b7 |
struct data_String *const data = (struct data_String*) pdata;
|
|
Packit |
1422b7 |
size_t i = *offs;
|
|
Packit |
1422b7 |
int bHaveQuotes = 0;
|
|
Packit |
1422b7 |
int bHadEndQuote = 0;
|
|
Packit |
1422b7 |
int bHadEscape = 0;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == npb->strLen) goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if((data->quoteMode == ST_QUOTE_AUTO) && (npb->str[i] == data->qchar_begin)) {
|
|
Packit |
1422b7 |
bHaveQuotes = 1;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
} else if(data->quoteMode == ST_QUOTE_REQD) {
|
|
Packit |
1422b7 |
if(npb->str[i] == data->qchar_begin) {
|
|
Packit |
1422b7 |
bHaveQuotes = 1;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* scan string */
|
|
Packit |
1422b7 |
while(i < npb->strLen) {
|
|
Packit |
1422b7 |
if(bHaveQuotes) {
|
|
Packit |
1422b7 |
if(npb->str[i] == data->qchar_end) {
|
|
Packit |
1422b7 |
if(data->flags.esc_md == ST_ESC_DOUBLE
|
|
Packit |
1422b7 |
|| data->flags.esc_md == ST_ESC_BOTH) {
|
|
Packit |
1422b7 |
/* may be escaped, need to check! */
|
|
Packit |
1422b7 |
if(i+1 < npb->strLen
|
|
Packit |
1422b7 |
&& npb->str[i+1] == data->qchar_end) {
|
|
Packit |
1422b7 |
bHadEscape = 1;
|
|
Packit |
1422b7 |
++i;
|
|
Packit |
1422b7 |
} else { /* not escaped -> terminal */
|
|
Packit |
1422b7 |
bHadEndQuote = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
bHadEndQuote = 1;
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if( npb->str[i] == '\\'
|
|
Packit |
1422b7 |
&& i+1 < npb->strLen
|
|
Packit |
1422b7 |
&& (data->flags.esc_md == ST_ESC_BACKSLASH
|
|
Packit |
1422b7 |
|| data->flags.esc_md == ST_ESC_BOTH) ) {
|
|
Packit |
1422b7 |
bHadEscape = 1;
|
|
Packit |
1422b7 |
i++; /* skip esc char */
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* terminating conditions */
|
|
Packit |
1422b7 |
if(!bHaveQuotes && npb->str[i] == ' ')
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
if(!stringIsPermittedChar(data, npb->str[i]))
|
|
Packit |
1422b7 |
break;
|
|
Packit |
1422b7 |
i++;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(bHaveQuotes && !bHadEndQuote)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(i == *offs)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
const size_t trmChkIdx = (bHaveQuotes) ? i+1 : i;
|
|
Packit |
1422b7 |
if(npb->str[trmChkIdx] != ' ' && trmChkIdx != npb->strLen)
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
/* success, persist */
|
|
Packit |
1422b7 |
*parsed = i - *offs;
|
|
Packit |
1422b7 |
if(bHadEndQuote)
|
|
Packit |
1422b7 |
++(*parsed); /* skip quote */
|
|
Packit |
1422b7 |
if(value != NULL) {
|
|
Packit |
1422b7 |
size_t strt;
|
|
Packit |
1422b7 |
size_t len;
|
|
Packit |
1422b7 |
if(bHaveQuotes && data->flags.strip_quotes) {
|
|
Packit |
1422b7 |
strt = *offs + 1;
|
|
Packit |
1422b7 |
len = *parsed - 2; /* del begin AND end quote! */
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
strt = *offs;
|
|
Packit |
1422b7 |
len = *parsed;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
char *const cstr = strndup(npb->str+strt, len);
|
|
Packit |
1422b7 |
CHKN(cstr);
|
|
Packit |
1422b7 |
if(bHadEscape) {
|
|
Packit |
1422b7 |
/* need to post-process string... */
|
|
Packit |
1422b7 |
for(size_t j = 0 ; cstr[j] != '\0' ; j++) {
|
|
Packit |
1422b7 |
if( (
|
|
Packit |
1422b7 |
cstr[j] == data->qchar_end
|
|
Packit |
1422b7 |
&& cstr[j+1] == data->qchar_end
|
|
Packit |
1422b7 |
&& (data->flags.esc_md == ST_ESC_DOUBLE
|
|
Packit |
1422b7 |
|| data->flags.esc_md == ST_ESC_BOTH)
|
|
Packit |
1422b7 |
)
|
|
Packit |
1422b7 |
||
|
|
Packit |
1422b7 |
(
|
|
Packit |
1422b7 |
cstr[j] == '\\'
|
|
Packit |
1422b7 |
&& (data->flags.esc_md == ST_ESC_BACKSLASH
|
|
Packit |
1422b7 |
|| data->flags.esc_md == ST_ESC_BOTH)
|
|
Packit |
1422b7 |
) ) {
|
|
Packit |
1422b7 |
/* we need to remove the escape character */
|
|
Packit |
1422b7 |
memmove(cstr+j, cstr+j+1, len-j);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
*value = json_object_new_string(cstr);
|
|
Packit |
1422b7 |
free(cstr);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
r = 0; /* success */
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
PARSER_Construct(String)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
int r = 0;
|
|
Packit |
1422b7 |
struct data_String *const data = (struct data_String*) calloc(1, sizeof(struct data_String));
|
|
Packit |
1422b7 |
data->quoteMode = ST_QUOTE_AUTO;
|
|
Packit |
1422b7 |
data->flags.strip_quotes = 1;
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_BOTH;
|
|
Packit |
1422b7 |
data->qchar_begin = '"';
|
|
Packit |
1422b7 |
data->qchar_end = '"';
|
|
Packit |
1422b7 |
memset(data->perm_chars, 0xff, sizeof(data->perm_chars));
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
struct json_object_iterator it = json_object_iter_begin(json);
|
|
Packit |
1422b7 |
struct json_object_iterator itEnd = json_object_iter_end(json);
|
|
Packit |
1422b7 |
while (!json_object_iter_equal(&it, &itEnd)) {
|
|
Packit |
1422b7 |
const char *key = json_object_iter_peek_name(&it);
|
|
Packit |
1422b7 |
struct json_object *const val = json_object_iter_peek_value(&it);
|
|
Packit |
1422b7 |
if(!strcasecmp(key, "quoting.mode")) {
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcasecmp(optval, "auto")) {
|
|
Packit |
1422b7 |
data->quoteMode = ST_QUOTE_AUTO;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "none")) {
|
|
Packit |
1422b7 |
data->quoteMode = ST_QUOTE_NONE;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "required")) {
|
|
Packit |
1422b7 |
data->quoteMode = ST_QUOTE_REQD;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid quoting.mode for string parser: %s",
|
|
Packit |
1422b7 |
optval);
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "quoting.escape.mode")) {
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(!strcasecmp(optval, "none")) {
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_NONE;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "backslash")) {
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_BACKSLASH;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "double")) {
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_DOUBLE;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(optval, "both")) {
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_BOTH;
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid quoting.escape.mode for string "
|
|
Packit |
1422b7 |
"parser: %s", optval);
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "quoting.char.begin")) {
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(strlen(optval) != 1) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "quoting.char.begin must "
|
|
Packit |
1422b7 |
"be exactly one character but is: '%s'", optval);
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->qchar_begin = *optval;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "quoting.char.end")) {
|
|
Packit |
1422b7 |
const char *const optval = json_object_get_string(val);
|
|
Packit |
1422b7 |
if(strlen(optval) != 1) {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "quoting.char.end must "
|
|
Packit |
1422b7 |
"be exactly one character but is: '%s'", optval);
|
|
Packit |
1422b7 |
r = LN_BADCONFIG;
|
|
Packit |
1422b7 |
goto done;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
data->qchar_end = *optval;
|
|
Packit |
1422b7 |
} else if(!strcasecmp(key, "matching.permitted")) {
|
|
Packit |
1422b7 |
memset(data->perm_chars, 0x00, sizeof(data->perm_chars));
|
|
Packit |
1422b7 |
if(json_object_is_type(val, json_type_string)) {
|
|
Packit |
1422b7 |
stringAddPermittedChars(data, val);
|
|
Packit |
1422b7 |
} else if(json_object_is_type(val, json_type_array)) {
|
|
Packit |
1422b7 |
stringAddPermittedCharsViaArray(ctx, data, val);
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "matching.permitted is invalid "
|
|
Packit |
1422b7 |
"object type, given as '%s",
|
|
Packit |
1422b7 |
json_object_to_json_string(val));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
} else {
|
|
Packit |
1422b7 |
ln_errprintf(ctx, 0, "invalid param for hexnumber: %s",
|
|
Packit |
1422b7 |
json_object_to_json_string(val));
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
json_object_iter_next(&it);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
|
|
Packit |
1422b7 |
if(data->quoteMode == ST_QUOTE_NONE)
|
|
Packit |
1422b7 |
data->flags.esc_md = ST_ESC_NONE;
|
|
Packit |
1422b7 |
*pdata = data;
|
|
Packit |
1422b7 |
done:
|
|
Packit |
1422b7 |
if(r != 0) {
|
|
Packit |
1422b7 |
free(data);
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
return r;
|
|
Packit |
1422b7 |
}
|
|
Packit |
1422b7 |
PARSER_Destruct(String)
|
|
Packit |
1422b7 |
{
|
|
Packit |
1422b7 |
free(pdata);
|
|
Packit |
1422b7 |
}
|