diff options
Diffstat (limited to 'runtime/msg.c')
-rw-r--r-- | runtime/msg.c | 339 |
1 files changed, 322 insertions, 17 deletions
diff --git a/runtime/msg.c b/runtime/msg.c index ded8cfe..66c3b7b 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -82,6 +82,8 @@ DEFobjCurrIf(prop) DEFobjCurrIf(net) DEFobjCurrIf(var) +static char *one_digit[10] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + static char *two_digits[100] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", @@ -94,6 +96,32 @@ static char *two_digits[100] = { "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99"}; +static char *wdayNames[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + +/* The following is a table of supported years. This permits us + * to avoid dynamic memory allocation. Note that the time-based + * algos need to be upgraded after the year 2099 in any case. + * Quite honestly, I don't expect that this is a real problem ;) + */ +static char *years[] = { + "1967", "1968", "1969", "1970", "1971", "1972", "1973", "1974", + "1975", "1976", "1977", "1978", "1979", "1980", "1981", "1982", + "1983", "1984", "1985", "1986", "1987", "1988", "1989", "1990", + "1991", "1992", "1993", "1994", "1995", "1996", "1997", "1998", + "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006", + "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", + "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", + "2023", "2024", "2025", "2026", "2027", "2028", "2029", "2030", + "2031", "2032", "2033", "2034", "2035", "2036", "2037", "2038", + "2039", "2040", "2041", "2042", "2043", "2044", "2045", "2046", + "2047", "2048", "2049", "2050", "2051", "2052", "2053", "2054", + "2055", "2056", "2057", "2058", "2059", "2060", "2061", "2062", + "2063", "2064", "2065", "2066", "2067", "2068", "2069", "2070", + "2071", "2072", "2073", "2074", "2075", "2076", "2077", "2078", + "2079", "2080", "2081", "2082", "2083", "2084", "2085", "2086", + "2087", "2088", "2089", "2090", "2091", "2092", "2093", "2094", + "2095", "2096", "2097", "2098", "2099" }; + static struct { uchar *pszName; short lenName; @@ -505,6 +533,8 @@ propNameToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_PROCID; } else if(!strcmp((char*) pName, "msgid")) { *pPropID = PROP_MSGID; + } else if(!strcmp((char*) pName, "jsonmesg")) { + *pPropID = PROP_JSONMESG; } else if(!strcmp((char*) pName, "parsesuccess")) { *pPropID = PROP_PARSESUCCESS; #ifdef USE_LIBUUID @@ -600,6 +630,8 @@ uchar *propIDToName(propid_t propID) return UCHAR_CONSTANT("procid"); case PROP_MSGID: return UCHAR_CONSTANT("msgid"); + case PROP_JSONMESG: + return UCHAR_CONSTANT("jsonmesg"); case PROP_PARSESUCCESS: return UCHAR_CONSTANT("parsesuccess"); case PROP_SYS_NOW: @@ -1600,6 +1632,31 @@ getTimeReported(msg_t * const pM, enum tplFormatTypes eFmt) MsgUnlock(pM); } return(pM->pszTIMESTAMP_SecFrac); + case tplFmtWDayName: + return wdayNames[getWeekdayNbr(&pM->tTIMESTAMP)]; + case tplFmtWDay: + return one_digit[getWeekdayNbr(&pM->tTIMESTAMP)]; + case tplFmtMonth: + return two_digits[(int)pM->tTIMESTAMP.month]; + case tplFmtYear: + if(pM->tTIMESTAMP.year >= 1967 && pM->tTIMESTAMP.year <= 2099) + return years[pM->tTIMESTAMP.year - 1967]; + else + return "YEAR OUT OF RANGE(1967-2099)"; + case tplFmtDay: + return two_digits[(int)pM->tTIMESTAMP.day]; + case tplFmtHour: + return two_digits[(int)pM->tTIMESTAMP.hour]; + case tplFmtMinute: + return two_digits[(int)pM->tTIMESTAMP.minute]; + case tplFmtSecond: + return two_digits[(int)pM->tTIMESTAMP.second]; + case tplFmtTZOffsHour: + return two_digits[(int)pM->tTIMESTAMP.OffsetHour]; + case tplFmtTZOffsMin: + return two_digits[(int)pM->tTIMESTAMP.OffsetMinute]; + case tplFmtTZOffsDirection: + return (pM->tTIMESTAMP.OffsetMode == '+')? "+" : "-"; } ENDfunc return "INVALID eFmt OPTION!"; @@ -1686,6 +1743,31 @@ static char *getTimeGenerated(msg_t * const pM, enum tplFormatTypes eFmt) MsgUnlock(pM); } return(pM->pszRcvdAt_SecFrac); + case tplFmtWDayName: + return wdayNames[getWeekdayNbr(&pM->tRcvdAt)]; + case tplFmtWDay: + return one_digit[getWeekdayNbr(&pM->tRcvdAt)]; + case tplFmtMonth: + return two_digits[(int)pM->tRcvdAt.month]; + case tplFmtYear: + if(pM->tRcvdAt.year >= 1967 && pM->tRcvdAt.year <= 2099) + return years[pM->tRcvdAt.year - 1967]; + else + return "YEAR OUT OF RANGE(1967-2099)"; + case tplFmtDay: + return two_digits[(int)pM->tRcvdAt.day]; + case tplFmtHour: + return two_digits[(int)pM->tRcvdAt.hour]; + case tplFmtMinute: + return two_digits[(int)pM->tRcvdAt.minute]; + case tplFmtSecond: + return two_digits[(int)pM->tRcvdAt.second]; + case tplFmtTZOffsHour: + return two_digits[(int)pM->tRcvdAt.OffsetHour]; + case tplFmtTZOffsMin: + return two_digits[(int)pM->tRcvdAt.OffsetMinute]; + case tplFmtTZOffsDirection: + return (pM->tRcvdAt.OffsetMode == '+')? "+" : "-"; } ENDfunc return "INVALID eFmt OPTION!"; @@ -1929,6 +2011,95 @@ void MsgSetParseSuccess(msg_t * const pMsg, int bSuccess) pMsg->bParseSuccess = bSuccess; } + +/* return full message as a json string */ +const uchar* +msgGetJSONMESG(msg_t *__restrict__ const pMsg) +{ + struct json_object *json; + struct json_object *jval; + uchar *pRes; /* result pointer */ + rs_size_t bufLen = -1; /* length of string or -1, if not known */ + + json = json_object_new_object(); + + jval = json_object_new_string((char*)getMSG(pMsg)); + json_object_object_add(json, "msg", jval); + + getRawMsg(pMsg, &pRes, &bufLen); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "rawmsg", jval); + + pRes = (uchar*)getTimeReported(pMsg, tplFmtRFC3339Date); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "timereported", jval); + + jval = json_object_new_string(getHOSTNAME(pMsg)); + json_object_object_add(json, "hostname", jval); + + getTAG(pMsg, &pRes, &bufLen); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "syslogtag", jval); + + getInputName(pMsg, &pRes, &bufLen); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "inputname", jval); + + jval = json_object_new_string((char*)getRcvFrom(pMsg)); + json_object_object_add(json, "fromhost", jval); + + jval = json_object_new_string((char*)getRcvFromIP(pMsg)); + json_object_object_add(json, "fromhost-ip", jval); + + jval = json_object_new_string(getPRI(pMsg)); + json_object_object_add(json, "pri", jval); + + jval = json_object_new_string(getFacility(pMsg)); + json_object_object_add(json, "syslogfacility", jval); + + jval = json_object_new_string(getSeverity(pMsg)); + json_object_object_add(json, "syslogseverity", jval); + + pRes = (uchar*)getTimeGenerated(pMsg, tplFmtRFC3339Date); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "timegenerated", jval); + + jval = json_object_new_string((char*)getProgramName(pMsg, LOCK_MUTEX)); + json_object_object_add(json, "programname", jval); + + jval = json_object_new_string(getProtocolVersionString(pMsg)); + json_object_object_add(json, "protocol-version", jval); + + MsgGetStructuredData(pMsg, &pRes, &bufLen); + jval = json_object_new_string((char*)pRes); + json_object_object_add(json, "structured-data", jval); + + jval = json_object_new_string(getAPPNAME(pMsg, LOCK_MUTEX)); + json_object_object_add(json, "app-name", jval); + + jval = json_object_new_string(getPROCID(pMsg, LOCK_MUTEX)); + json_object_object_add(json, "procid", jval); + + jval = json_object_new_string(getMSGID(pMsg)); + json_object_object_add(json, "msgid", jval); + +#ifdef USE_LIBUUID + if(pMsg->pszUUID == NULL) { + jval = NULL; + } else { + getUUID(pMsg, &pRes, &bufLen); + jval = json_object_new_string((char*)pRes); + } + json_object_object_add(json, "uuid", jval); +#endif + + json_object_object_add(json, "$!", pMsg->json); + + pRes = (uchar*) strdup(json_object_get_string(json)); + json_object_put(json); + return pRes; +} + /* rgerhards 2009-06-12: set associated ruleset */ void MsgSetRuleset(msg_t * const pMsg, ruleset_t *pRuleset) @@ -2322,7 +2493,7 @@ finalize_it: * we need it. The rest of the code already knows how to handle an * unset HOSTNAME. */ -void MsgSetHOSTNAME(msg_t *pThis, uchar* pszHOSTNAME, int lenHOSTNAME) +void MsgSetHOSTNAME(msg_t *pThis, const uchar* pszHOSTNAME, const int lenHOSTNAME) { assert(pThis != NULL); @@ -2373,7 +2544,7 @@ void MsgSetMSGoffs(msg_t * const pMsg, short offs) * the caller is responsible for freeing it. * rgerhards, 2009-06-23 */ -rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG) +rsRetVal MsgReplaceMSG(msg_t *pThis, const uchar* pszMSG, int lenMSG) { int lenNew; uchar *bufNew; @@ -2406,12 +2577,14 @@ finalize_it: * terminated by '\0'. * rgerhards, 2009-06-16 */ -void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg) +void MsgSetRawMsg(msg_t *pThis, const char* pszRawMsg, size_t lenMsg) { + int deltaSize; assert(pThis != NULL); if(pThis->pszRawMsg != pThis->szRawMsg) free(pThis->pszRawMsg); + deltaSize = lenMsg - pThis->iLenRawMsg; pThis->iLenRawMsg = lenMsg; if(pThis->iLenRawMsg < CONF_RAWMSG_BUFSIZE) { /* small enough: use fixed buffer (faster!) */ @@ -2424,6 +2597,11 @@ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg) memcpy(pThis->pszRawMsg, pszRawMsg, pThis->iLenRawMsg); pThis->pszRawMsg[pThis->iLenRawMsg] = '\0'; /* this also works with truncation! */ + /* correct other information */ + if(pThis->iLenRawMsg > pThis->offMSG) + pThis->iLenMSG += deltaSize; + else + pThis->iLenMSG = 0; } @@ -2638,7 +2816,8 @@ jsonAddVal(uchar *pSrc, unsigned buflen, es_str_t **dst, int escapeAll) for(i = 0 ; i < buflen ; ++i) { c = pSrc[i]; - if( (c >= 0x23 && c <= 0x5b) + if( (c >= 0x23 && c <= 0x2e) + || (c >= 0x30 && c <= 0x5b) || (c >= 0x5d /* && c <= 0x10FFFF*/) || c == 0x20 || c == 0x21) { /* no need to escape */ @@ -2947,6 +3126,10 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri case PROP_MSGID: pRes = (uchar*)getMSGID(pMsg); break; + case PROP_JSONMESG: + pRes = (uchar*)msgGetJSONMESG(pMsg); + *pbMustBeFreed = 1; + break; #ifdef USE_LIBUUID case PROP_UUID: getUUID(pMsg, &pRes, &bufLen); @@ -3024,8 +3207,6 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri break; case PROP_CEE_ALL_JSON: if(pMsg->json == NULL) { - if(*pbMustBeFreed == 1) - free(pRes); pRes = (uchar*) "{}"; bufLen = 2; *pbMustBeFreed = 0; @@ -3040,8 +3221,6 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri getJSONPropVal(pMsg, pProp, &pRes, &bufLen, pbMustBeFreed); break; case PROP_SYS_BOM: - if(*pbMustBeFreed == 1) - free(pRes); pRes = (uchar*) "\xEF\xBB\xBF"; *pbMustBeFreed = 0; break; @@ -3058,18 +3237,18 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri { struct timespec tp; - if(*pbMustBeFreed == 1) - free(pRes); if((pRes = (uchar*) MALLOC(sizeof(uchar) * 32)) == NULL) { RET_OUT_OF_MEMORY; } - *pbMustBeFreed = 1; if(clock_gettime(CLOCK_UPTIME, &tp) == -1) { + free(pRes); *pPropLen = sizeof("**SYSCALL FAILED**") - 1; return(UCHAR_CONSTANT("**SYSCALL FAILED**")); } + *pbMustBeFreed = 1; + snprintf((char*) pRes, sizeof(uchar) * 32, "%ld", tp.tv_sec); } @@ -3078,18 +3257,18 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri { struct sysinfo s_info; - if(*pbMustBeFreed == 1) - free(pRes); if((pRes = (uchar*) MALLOC(sizeof(uchar) * 32)) == NULL) { RET_OUT_OF_MEMORY; } - *pbMustBeFreed = 1; if(sysinfo(&s_info) < 0) { + free(pRes); *pPropLen = sizeof("**SYSCALL FAILED**") - 1; return(UCHAR_CONSTANT("**SYSCALL FAILED**")); } + *pbMustBeFreed = 1; + snprintf((char*) pRes, sizeof(uchar) * 32, "%ld", s_info.uptime); } # endif @@ -3157,7 +3336,7 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri /* we got our end pointer, now do the copy */ /* TODO: code copied from below, this is a candidate for a separate function */ iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */ - pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(char)); + pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(uchar)); if(pBuf == NULL) { if(*pbMustBeFreed == 1) free(pRes); @@ -3335,7 +3514,7 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri if(iTo > bufLen) /* iTo is very large, if no to-position is set in the template! */ iTo = bufLen; iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */ - pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(char)); + pBufStart = pBuf = MALLOC((iLen + 1) * sizeof(uchar)); if(pBuf == NULL) { if(*pbMustBeFreed == 1) free(pRes); @@ -3389,7 +3568,7 @@ uchar *MsgGetProp(msg_t *__restrict__ const pMsg, struct templateEntry *__restri uchar *pBStart; uchar *pB; uchar *pSrc; - pBStart = pB = MALLOC((bufLen + 1) * sizeof(char)); + pBStart = pB = MALLOC((bufLen + 1) * sizeof(uchar)); if(pB == NULL) { if(*pbMustBeFreed == 1) free(pRes); @@ -3795,6 +3974,132 @@ finalize_it: #undef isProp +/* Set a single property based on the JSON object provided. The + * property name is extracted from the JSON object. + */ +static rsRetVal +msgSetPropViaJSON(msg_t *__restrict__ const pMsg, const char *name, struct json_object *json) +{ + const char *psz; + int val; + prop_t *propFromHost = NULL; + prop_t *propRcvFromIP = NULL; + DEFiRet; + + // TODO: think if we need to lock the message mutex. For some updates + // we probably need to! + + /* note: json_object_get_string() manages the memory of the returned + * string. So we MUST NOT free it! + */ + dbgprintf("DDDD: msgSetPropViaJSON key: '%s'\n", name); + if(!strcmp(name, "rawmsg")) { + psz = json_object_get_string(json); + MsgSetRawMsg(pMsg, psz, strlen(psz)); + } else if(!strcmp(name, "msg")) { + psz = json_object_get_string(json); + MsgReplaceMSG(pMsg, (const uchar*)psz, strlen(psz)); + } else if(!strcmp(name, "syslogtag")) { + psz = json_object_get_string(json); + MsgSetTAG(pMsg, (const uchar*)psz, strlen(psz)); + } else if(!strcmp(name, "syslogfacility")) { + val = json_object_get_int(json); + if(val >= 0 && val <= 24) + pMsg->iFacility = val; + else + DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val); + } else if(!strcmp(name, "syslogseverity")) { + val = json_object_get_int(json); + if(val >= 0 && val <= 7) + pMsg->iSeverity = val; + else + DBGPRINTF("mmexternal: invalid fac %d requested -- ignored\n", val); + } else if(!strcmp(name, "procid")) { + psz = json_object_get_string(json); + MsgSetPROCID(pMsg, psz); + } else if(!strcmp(name, "msgid")) { + psz = json_object_get_string(json); + MsgSetMSGID(pMsg, psz); + } else if(!strcmp(name, "structured-data")) { + psz = json_object_get_string(json); + MsgSetStructuredData(pMsg, psz); + } else if(!strcmp(name, "hostname") || !strcmp(name, "source")) { + psz = json_object_get_string(json); + MsgSetHOSTNAME(pMsg, (const uchar*)psz, strlen(psz)); + } else if(!strcmp(name, "fromhost")) { + psz = json_object_get_string(json); + MsgSetRcvFromStr(pMsg, (const uchar*) psz, 0, &propFromHost); + } else if(!strcmp(name, "fromhost-ip")) { + psz = json_object_get_string(json); + MsgSetRcvFromIPStr(pMsg, (const uchar*)psz, strlen(psz), &propRcvFromIP); + } else if(!strcmp(name, "$!")) { + msgAddJSON(pMsg, (uchar*)"!", json); + } else { + /* we ignore unknown properties */ + DBGPRINTF("msgSetPropViaJSON: unkonwn property ignored: %s\n", + name); + } + RETiRet; +} + + +/* set message properties based on JSON string. This function does it all, + * including parsing the JSON string. If an error is detected, the operation + * is aborted at the time of error. Any modifications made before the + * error ocurs are still PERSISTED. + * This function is meant to support the external message modifiction module + * interface. As such, replacing properties is expressively permited. Note that + * properties which were derived from the message during parsing are NOT + * updated if the underlying (raw)msg property is changed. + */ +rsRetVal +MsgSetPropsViaJSON(msg_t *__restrict__ const pMsg, const uchar *__restrict__ const jsonstr) +{ + struct json_tokener *tokener = NULL; + struct json_object *json; + const char *errMsg; + DEFiRet; + + DBGPRINTF("DDDDDD: JSON string for message mod: '%s'\n", jsonstr); + if(!strcmp((char*)jsonstr, "{}")) /* shortcut for a common case */ + FINALIZE; + + tokener = json_tokener_new(); + + json = json_tokener_parse_ex(tokener, (char*)jsonstr, ustrlen(jsonstr)); + if(Debug) { + errMsg = NULL; + if(json == NULL) { + enum json_tokener_error err; + + err = tokener->err; + if(err != json_tokener_continue) + errMsg = json_tokener_errors[err]; + else + errMsg = "Unterminated input"; + } else if(!json_object_is_type(json, json_type_object)) + errMsg = "JSON value is not an object"; + if(errMsg != NULL) { + DBGPRINTF("MsgSetPropsViaJSON: Error parsing JSON '%s': %s\n", + jsonstr, errMsg); + } + } + if(json == NULL || !json_object_is_type(json, json_type_object)) { + ABORT_FINALIZE(RS_RET_JSON_PARSE_ERR); + } + + json_object_object_foreach(json, name, val) { + msgSetPropViaJSON(pMsg, name, val); + } + json_object_put(json); + +finalize_it: + if(tokener != NULL) + json_tokener_free(tokener); + RETiRet; +} + + /* get the severity - this is an entry point that * satisfies the base object class getSeverity semantics. * rgerhards, 2008-01-14 |