diff options
Diffstat (limited to 'src/fluent-bit/plugins/out_syslog')
-rw-r--r-- | src/fluent-bit/plugins/out_syslog/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/fluent-bit/plugins/out_syslog/syslog.c | 1170 | ||||
-rw-r--r-- | src/fluent-bit/plugins/out_syslog/syslog_conf.c | 162 | ||||
-rw-r--r-- | src/fluent-bit/plugins/out_syslog/syslog_conf.h | 70 |
4 files changed, 1407 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/out_syslog/CMakeLists.txt b/src/fluent-bit/plugins/out_syslog/CMakeLists.txt new file mode 100644 index 000000000..556d8e1a4 --- /dev/null +++ b/src/fluent-bit/plugins/out_syslog/CMakeLists.txt @@ -0,0 +1,5 @@ +set(src + syslog.c + syslog_conf.c) + +FLB_PLUGIN(out_syslog "${src}" "") diff --git a/src/fluent-bit/plugins/out_syslog/syslog.c b/src/fluent-bit/plugins/out_syslog/syslog.c new file mode 100644 index 000000000..a33351354 --- /dev/null +++ b/src/fluent-bit/plugins/out_syslog/syslog.c @@ -0,0 +1,1170 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fluent-bit/flb_output_plugin.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_network.h> +#include <fluent-bit/flb_utils.h> +#include <fluent-bit/flb_kv.h> +#include <fluent-bit/flb_pack.h> +#include <fluent-bit/flb_sds.h> +#include <fluent-bit/flb_log_event_decoder.h> + +#include "syslog_conf.h" + +#ifndef MSG_DONTWAIT + #define MSG_DONTWAIT 0 +#endif + +#ifndef MSG_NOSIGNAL + #define MSG_NOSIGNAL 0 +#endif + +#define RFC5424_MAXSIZE 2048 +#define RFC3164_MAXSIZE 1024 + +struct syslog_msg { + int severity; + int facility; + flb_sds_t hostname; + flb_sds_t appname; + flb_sds_t procid; + flb_sds_t msgid; + flb_sds_t sd; + flb_sds_t message; +}; + +static const char *rfc3164_mon[] = {"Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"}; + +static struct { + char *name; + int len; + int value; +} syslog_severity[] = { + { "emerg", 5, 0 }, + { "alert", 5, 1 }, + { "crit", 4, 2 }, + { "err", 3, 3 }, + { "warning", 7, 4 }, + { "notice", 6, 5 }, + { "info", 4, 6 }, + { "debug", 5, 7 }, + { NULL, 0,-1 } +}; + +static struct { + char *name; + int len; + int value; +} syslog_facility[] = { + { "kern", 4, 0 }, + { "user", 4, 1 }, + { "mail", 4, 2 }, + { "daemon", 6, 3 }, + { "auth", 4, 4 }, + { "syslog", 6, 5 }, + { "lpr", 3, 6 }, + { "news", 4, 7 }, + { "uucp", 4, 8 }, + { "cron", 4, 9 }, + { "authpriv", 8, 10 }, + { "ftp", 3, 11 }, + { "ntp", 3, 12 }, + { "security", 8, 13 }, + { "console", 7, 14 }, + { "local0", 6, 16 }, + { "local1", 6, 17 }, + { "local2", 6, 18 }, + { "local3", 6, 19 }, + { "local4", 6, 20 }, + { "local5", 6, 21 }, + { "local6", 6, 22 }, + { "local7", 6, 23 }, + { NULL, 0,-1 }, +}; + +/* '"', '\' ']' */ +static char rfc5424_sp_value[256] = { + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0,'"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\',']', 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0, + 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0 , 0, 0 +}; + +/* '=', ' ', ']', '"' */ +static char rfc5424_sp_name[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static flb_sds_t syslog_rfc5424(flb_sds_t *s, struct flb_time *tms, + struct syslog_msg *msg) +{ + struct tm tm; + flb_sds_t tmp; + uint8_t prival; + + prival = (msg->facility << 3) + msg->severity; + + if (gmtime_r(&(tms->tm.tv_sec), &tm) == NULL) { + return NULL; + } + + tmp = flb_sds_printf(s, "<%i>%i %d-%02d-%02dT%02d:%02d:%02d.%06"PRIu64"Z ", + prival, 1, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + (uint64_t) tms->tm.tv_nsec/1000); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->hostname) { + int len = flb_sds_len(msg->hostname); + tmp = flb_sds_cat(*s, msg->hostname, len > 255 ? 255 : len); + if (!tmp) { + return NULL; + } + *s = tmp; + } + else { + tmp = flb_sds_cat(*s, "-" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + tmp = flb_sds_cat(*s, " ", 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->appname) { + int len = flb_sds_len(msg->appname); + tmp = flb_sds_cat(*s, msg->appname, len > 48 ? 48 : len); + if (!tmp) { + return NULL; + } + *s = tmp; + } + else { + tmp = flb_sds_cat(*s, "-" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + tmp = flb_sds_cat(*s, " ", 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->procid) { + int len = flb_sds_len(msg->procid); + tmp = flb_sds_cat(*s, msg->procid, len > 128 ? 128 : len); + if (!tmp) { + return NULL; + } + *s = tmp; + } + else { + tmp = flb_sds_cat(*s, "-" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + tmp = flb_sds_cat(*s, " ", 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->msgid) { + int len = flb_sds_len(msg->msgid); + tmp = flb_sds_cat(*s, msg->msgid, len > 32 ? 32 : len); + if (!tmp) { + return NULL; + } + *s = tmp; + } + else { + tmp = flb_sds_cat(*s, "-" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + tmp = flb_sds_cat(*s, " ", 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->sd) { + tmp = flb_sds_cat(*s, msg->sd, flb_sds_len(msg->sd)); + if (!tmp) { + return NULL; + } + *s = tmp; + } + else { + tmp = flb_sds_cat(*s, "-" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + if (msg->message) { + int len = flb_sds_len(msg->message); + tmp = flb_sds_cat(*s, " \xef\xbb\xbf", 4); + if (!tmp) { + return NULL; + } + *s = tmp; + tmp = flb_sds_cat(*s, msg->message, len); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + return *s; +} + +static flb_sds_t syslog_rfc3164 (flb_sds_t *s, struct flb_time *tms, + struct syslog_msg *msg) +{ + struct tm tm; + flb_sds_t tmp; + uint8_t prival; + + prival = (msg->facility << 3) + msg->severity; + + if (gmtime_r(&(tms->tm.tv_sec), &tm) == NULL) { + return NULL; + } + + tmp = flb_sds_printf(s, "<%i>%s %2d %02d:%02d:%02d ", prival, + rfc3164_mon[tm.tm_mon], tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + if (!tmp) { + return NULL; + } + *s = tmp; + + if (msg->hostname) { + tmp = flb_sds_cat(*s, msg->hostname, flb_sds_len(msg->hostname)); + if (!tmp) { + return NULL; + } + *s = tmp; + tmp = flb_sds_cat(*s, " ", 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + if (msg->appname) { + tmp = flb_sds_cat(*s, msg->appname, flb_sds_len(msg->appname)); + if (!tmp) { + return NULL; + } + *s = tmp; + if (msg->procid) { + tmp = flb_sds_cat(*s, "[" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + tmp = flb_sds_cat(*s, msg->procid, flb_sds_len(msg->procid)); + if (!tmp) { + return NULL; + } + *s = tmp; + tmp = flb_sds_cat(*s, "]" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + tmp = flb_sds_cat(*s, ": " , 2); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + if (msg->message) { + tmp = flb_sds_cat(*s, msg->message, flb_sds_len(msg->message)); + if (!tmp) { + return NULL; + } + *s = tmp; + } + + return *s; +} + +static flb_sds_t msgpack_to_sd(struct flb_syslog *ctx, + flb_sds_t *s, const char *sd, int sd_len, + msgpack_object *o) +{ + flb_sds_t tmp; + int i; + int loop; + int n, start_len, end_len; + + if (*s == NULL) { + *s = flb_sds_create_size(512); + if (*s == NULL) { + return NULL; + } + } + + tmp = flb_sds_cat(*s, "[" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + start_len = flb_sds_len(*s); + if (ctx->allow_longer_sd_id != FLB_TRUE && sd_len > 32) { + /* + * RFC5424 defines + * SD-NAME = 1*32PRINTUSASCII + * ; except '=', SP, ']', %d34 (") + * + * https://www.rfc-editor.org/rfc/rfc5424#section-6 + */ + sd_len = 32; + } + tmp = flb_sds_cat(*s, sd, sd_len); + if (!tmp) { + return NULL; + } + *s = tmp; + + end_len = flb_sds_len(*s); + for(n=start_len; n < end_len; n++) { + if (!rfc5424_sp_name[(unsigned char)(*s)[n]]) { + (*s)[n] = '_'; + } + } + + loop = o->via.map.size; + if (loop != 0) { + msgpack_object_kv *p = o->via.map.ptr; + for (i = 0; i < loop; i++) { + char temp[48] = {0}; + const char *key = NULL; + int key_len = 0; + const char *val = NULL; + int val_len = 0; + + msgpack_object *k = &p[i].key; + msgpack_object *v = &p[i].val; + + if (k->type != MSGPACK_OBJECT_BIN && k->type != MSGPACK_OBJECT_STR) { + continue; + } + + if (k->type == MSGPACK_OBJECT_STR) { + key = k->via.str.ptr; + key_len = k->via.str.size; + } + else { + key = k->via.bin.ptr; + key_len = k->via.bin.size; + } + + if (v->type == MSGPACK_OBJECT_BOOLEAN) { + val = v->via.boolean ? "true" : "false"; + val_len = v->via.boolean ? 4 : 5; + } + else if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%" PRIu64, v->via.u64); + } + else if (v->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%" PRId64, v->via.i64); + } + else if (v->type == MSGPACK_OBJECT_FLOAT) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%f", v->via.f64); + } + else if (v->type == MSGPACK_OBJECT_STR) { + /* String value */ + val = v->via.str.ptr; + val_len = v->via.str.size; + } + else if (v->type == MSGPACK_OBJECT_BIN) { + /* Bin value */ + val = v->via.bin.ptr; + val_len = v->via.bin.size; + } + + if (!val || !key) { + continue; + } + + tmp = flb_sds_cat(*s, " " , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + + start_len = flb_sds_len(*s); + if (ctx->allow_longer_sd_id != FLB_TRUE && key_len > 32 ) { + /* + * RFC5424 defines + * PARAM-NAME = SD-NAME + * SD-NAME = 1*32PRINTUSASCII + * ; except '=', SP, ']', %d34 (") + * + * https://www.rfc-editor.org/rfc/rfc5424#section-6 + */ + key_len = 32; + } + tmp = flb_sds_cat(*s, key, key_len); + if (!tmp) { + return NULL; + } + *s = tmp; + + end_len = flb_sds_len(*s); + for(n=start_len; n < end_len; n++) { + if (!rfc5424_sp_name[(unsigned char)(*s)[n]]) { + (*s)[n] = '_'; + } + } + + tmp = flb_sds_cat(*s, "=\"" , 2); + if (!tmp) { + return NULL; + } + *s = tmp; + + tmp = flb_sds_cat_esc(*s, val , val_len, + rfc5424_sp_value, sizeof(rfc5424_sp_value)); + if (!tmp) { + return NULL; + } + *s = tmp; + + tmp = flb_sds_cat(*s, "\"" , 1); + if (!tmp) { + return NULL; + } + *s = tmp; + } + } + + tmp = flb_sds_cat(*s, "]" , 1); + if (!tmp) return NULL; + *s = tmp; + + return *s; +} + +static int msgpack_to_syslog(struct flb_syslog *ctx, msgpack_object *o, + struct syslog_msg *msg) +{ + int i; + int loop; + struct mk_list *head; + struct flb_config_map_val *mv; + + if (o == NULL) { + return -1; + } + + loop = o->via.map.size; + if (loop != 0) { + msgpack_object_kv *p = o->via.map.ptr; + + for (i = 0; i < loop; i++) { + char temp[48] = {0}; + const char *key = NULL; + int key_len = 0; + const char *val = NULL; + int val_len = 0; + + msgpack_object *k = &p[i].key; + msgpack_object *v = &p[i].val; + + if (k->type != MSGPACK_OBJECT_BIN && k->type != MSGPACK_OBJECT_STR){ + continue; + } + + if (k->type == MSGPACK_OBJECT_STR) { + key = k->via.str.ptr; + key_len = k->via.str.size; + } + else { + key = k->via.bin.ptr; + key_len = k->via.bin.size; + } + + if (v->type == MSGPACK_OBJECT_MAP) { + if (ctx->sd_keys) { + flb_config_map_foreach(head, mv, ctx->sd_keys) { + if ((key_len == flb_sds_len(mv->val.str)) && + strncmp(key, mv->val.str, flb_sds_len(mv->val.str)) == 0) { + msgpack_to_sd(ctx, &(msg->sd), key, key_len, v); + break; + } + } + } + continue; + } + + if (v->type == MSGPACK_OBJECT_BOOLEAN) { + val = v->via.boolean ? "true" : "false"; + val_len = v->via.boolean ? 4 : 5; + } + else if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%" PRIu64, v->via.u64); + } + else if (v->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%" PRId64, v->via.i64); + } + else if (v->type == MSGPACK_OBJECT_FLOAT) { + val = temp; + val_len = snprintf(temp, sizeof(temp) - 1, + "%f", v->via.f64); + } + else if (v->type == MSGPACK_OBJECT_STR) { + /* String value */ + val = v->via.str.ptr; + val_len = v->via.str.size; + } + else if (v->type == MSGPACK_OBJECT_BIN) { + /* Bin value */ + val = v->via.bin.ptr; + val_len = v->via.bin.size; + } + + if (!val || !key) { + continue; + } + + if ((ctx->severity_key != NULL) && + flb_sds_cmp(ctx->severity_key, key, key_len) == 0) { + if (msg->severity == -1) { + if ((val_len == 1) && (val[0] >= '0' && val[0] <= '7')) { + msg->severity = val[0]-'0'; + } + else { + int i; + for (i=0; syslog_severity[i].name != NULL; i++) { + if ((syslog_severity[i].len == val_len) && + (!strncasecmp(syslog_severity[i].name, val, val_len))) { + msg->severity = syslog_severity[i].value; + } + } + if (!syslog_severity[i].name) { + flb_plg_warn(ctx->ins, "invalid severity: '%.*s'", + val_len, val); + } + } + } + } + else if ((ctx->facility_key != NULL) && + flb_sds_cmp(ctx->facility_key, key, key_len) == 0) { + if (msg->facility == -1) { + if ((val_len == 1) && (val[0] >= '0' && val[0] <= '9')) { + msg->facility = val[0]-'0'; + } + else if ((val_len == 2) && + (val[0] >= '0' && val[0] <= '2') && + (val[1] >= '0' && val[1] <= '9')) { + msg->facility = (val[0]-'0')*10; + msg->facility += (val[1]-'0'); + if (!((msg->facility >= 0) && (msg->facility <=23))) { + flb_plg_warn(ctx->ins, "invalid facility: '%.*s'", + val_len, val); + msg->facility= -1; + } + } + else { + int i; + for (i=0; syslog_facility[i].name != NULL; i++) { + if ((syslog_facility[i].len == val_len) && + (!strncasecmp(syslog_facility[i].name, val, val_len))) { + msg->facility = syslog_facility[i].value; + } + } + if (!syslog_facility[i].name) { + flb_plg_warn(ctx->ins, "invalid facility: '%.*s'", + val_len, val); + } + } + } + } + else if ((ctx->hostname_key != NULL) && + flb_sds_cmp(ctx->hostname_key, key, key_len) == 0) { + if (!msg->hostname) { + msg->hostname = flb_sds_create_len(val, val_len); + } + } + else if ((ctx->appname_key != NULL) && + flb_sds_cmp(ctx->appname_key, key, key_len) == 0) { + if (!msg->appname) { + msg->appname = flb_sds_create_len(val, val_len); + } + } + else if ((ctx->procid_key != NULL) && + flb_sds_cmp(ctx->procid_key, key, key_len) == 0) { + if (!msg->procid) { + msg->procid = flb_sds_create_len(val, val_len); + } + } + else if ((ctx->msgid_key != NULL) && + flb_sds_cmp(ctx->msgid_key, key, key_len) == 0) { + if (!msg->msgid) { + msg->msgid = flb_sds_create_len(val, val_len); + } + } + else if ((ctx->message_key != NULL) && + flb_sds_cmp(ctx->message_key, key, key_len) == 0) { + if (!msg->message) { + msg->message = flb_sds_create_len(val, val_len); + } + } + } + } + + return 0; +} + +static flb_sds_t syslog_format(struct flb_syslog *ctx, msgpack_object *o, + flb_sds_t *s, struct flb_time *tm) +{ + struct syslog_msg msg; + flb_sds_t tmp; + flb_sds_t ret_sds; + int ret; + + msg.severity = -1; + msg.facility = -1; + msg.hostname = NULL; + msg.appname = NULL; + msg.procid = NULL; + msg.msgid = NULL; + msg.sd = NULL; + msg.message = NULL; + + ret = msgpack_to_syslog(ctx, o, &msg); + if (!ret) { + if (msg.severity < 0) { + msg.severity = ctx->severity_preset; + } + if (msg.facility < 0) { + msg.facility = ctx->facility_preset; + } + if (msg.hostname == NULL && ctx->hostname_preset) { + msg.hostname = flb_sds_create(ctx->hostname_preset); + } + if (msg.appname == NULL && ctx->appname_preset) { + msg.appname = flb_sds_create(ctx->appname_preset); + } + if (msg.procid == NULL && ctx->procid_preset) { + msg.procid = flb_sds_create(ctx->procid_preset); + } + if (msg.msgid == NULL && ctx->msgid_preset) { + msg.msgid = flb_sds_create(ctx->msgid_preset); + } + + if (ctx->parsed_format == FLB_SYSLOG_RFC3164) { + tmp = syslog_rfc3164(s, tm, &msg); + } + else { + tmp = syslog_rfc5424(s, tm, &msg); + } + + if (!tmp) { + ret_sds = NULL; + goto clean; + } + *s = tmp; + + if (flb_sds_len(*s) > ctx->maxsize) { + flb_sds_len_set(*s, ctx->maxsize); + } + + if (ctx->parsed_mode != FLB_SYSLOG_UDP) { + tmp = flb_sds_cat(*s, "\n", 1); + if (!tmp) { + ret_sds = NULL; + goto clean; + } + *s = tmp; + } + } + else { + ret_sds = NULL; + goto clean; + } + + ret_sds = *s; +clean: + flb_sds_destroy(msg.hostname); + flb_sds_destroy(msg.appname); + flb_sds_destroy(msg.procid); + flb_sds_destroy(msg.msgid); + flb_sds_destroy(msg.sd); + flb_sds_destroy(msg.message); + + return ret_sds; +} + +static void cb_syslog_flush(struct flb_event_chunk *event_chunk, + struct flb_output_flush *out_flush, + struct flb_input_instance *i_ins, + void *out_context, + struct flb_config *config) +{ + struct flb_syslog *ctx = out_context; + flb_sds_t s; + flb_sds_t tmp; + size_t bytes_sent; + msgpack_object map; + struct flb_connection *u_conn = NULL; + int ret; + struct flb_log_event_decoder log_decoder; + struct flb_log_event log_event; + + if (ctx->parsed_mode != FLB_SYSLOG_UDP) { + u_conn = flb_upstream_conn_get(ctx->u); + if (!u_conn) { + flb_plg_error(ctx->ins, "no upstream connections available"); + FLB_OUTPUT_RETURN(FLB_RETRY); + } + } + + s = flb_sds_create_size(ctx->maxsize); + if (s == NULL) { + FLB_OUTPUT_RETURN(FLB_ERROR); + } + + ret = flb_log_event_decoder_init(&log_decoder, + (char *) event_chunk->data, + event_chunk->size); + + if (ret != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, + "Log event decoder initialization error : %d", ret); + + flb_sds_destroy(s); + + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + while ((ret = flb_log_event_decoder_next( + &log_decoder, + &log_event)) == FLB_EVENT_DECODER_SUCCESS) { + map = *log_event.body; + + flb_sds_len_set(s, 0); + + tmp = syslog_format(ctx, &map, &s, &log_event.timestamp); + if (tmp != NULL) { + s = tmp; + if (ctx->parsed_mode == FLB_SYSLOG_UDP) { + ret = send(ctx->fd, s, flb_sds_len(s), MSG_DONTWAIT | MSG_NOSIGNAL); + if (ret == -1) { + flb_log_event_decoder_destroy(&log_decoder); + flb_sds_destroy(s); + + FLB_OUTPUT_RETURN(FLB_RETRY); + } + } + else { + ret = flb_io_net_write(u_conn, + s, flb_sds_len(s), &bytes_sent); + if (ret == -1) { + flb_errno(); + flb_log_event_decoder_destroy(&log_decoder); + flb_upstream_conn_release(u_conn); + flb_sds_destroy(s); + + FLB_OUTPUT_RETURN(FLB_RETRY); + } + } + } + else { + flb_plg_error(ctx->ins, "error formating message"); + } + } + + flb_sds_destroy(s); + flb_log_event_decoder_destroy(&log_decoder); + + if (ctx->parsed_mode != FLB_SYSLOG_UDP) { + flb_upstream_conn_release(u_conn); + } + + FLB_OUTPUT_RETURN(FLB_OK); +} + +static int cb_syslog_init(struct flb_output_instance *ins, struct flb_config *config, + void *data) +{ + int io_flags; + struct flb_syslog *ctx = NULL; + + /* Set default network configuration */ + flb_output_net_default("127.0.0.1", 514, ins); + + /* Create config context */ + ctx = flb_syslog_config_create(ins, config); + if (ctx == NULL) { + flb_plg_error(ins, "error configuring plugin"); + return -1; + } + + if (ctx->maxsize < 0) { + if (ctx->parsed_format == FLB_SYSLOG_RFC3164) { + ctx->maxsize = RFC3164_MAXSIZE; + } + else { + ctx->maxsize = RFC5424_MAXSIZE; + } + } + + ctx->fd = -1; + if (ctx->parsed_mode == FLB_SYSLOG_UDP) { + ctx->fd = flb_net_udp_connect(ins->host.name, ins->host.port, + ins->net_setup.source_address); + if (ctx->fd < 0) { + flb_syslog_config_destroy(ctx); + return -1; + } + } + else { + + /* use TLS ? */ + if (ins->use_tls == FLB_TRUE) { + io_flags = FLB_IO_TLS; + } + else { + io_flags = FLB_IO_TCP; + } + + if (ins->host.ipv6 == FLB_TRUE) { + io_flags |= FLB_IO_IPV6; + } + + ctx->u = flb_upstream_create(config, ins->host.name, ins->host.port, + io_flags, ins->tls); + if (!(ctx->u)) { + flb_syslog_config_destroy(ctx); + return -1; + } + flb_output_upstream_set(ctx->u, ins); + } + + /* Set the plugin context */ + flb_output_set_context(ins, ctx); + + flb_plg_info(ctx->ins, "setup done for %s:%i (TLS=%s)", + ins->host.name, ins->host.port, + ins->use_tls ? "on" : "off"); + return 0; +} + +static int cb_syslog_exit(void *data, struct flb_config *config) +{ + struct flb_syslog *ctx = data; + + if (ctx == NULL) { + return 0; + } + + if (ctx->u) { + flb_upstream_destroy(ctx->u); + } + + if (ctx->fd > 0) { + close(ctx->fd); + } + + flb_syslog_config_destroy(ctx); + + return 0; +} + + +/* for testing */ +static int cb_syslog_format_test(struct flb_config *config, + struct flb_input_instance *ins, + void *plugin_context, + void *flush_ctx, + int event_type, + const char *tag, int tag_len, + const void *data, size_t bytes, + void **out_data, size_t *out_size) +{ + struct flb_syslog *ctx = plugin_context; + flb_sds_t tmp; + flb_sds_t s; + msgpack_object map; + struct flb_log_event_decoder log_decoder; + struct flb_log_event log_event; + int ret; + + s = flb_sds_create_size(ctx->maxsize); + if (s == NULL) { + flb_error("flb_sds_create_size failed"); + return -1; + } + + ret = flb_log_event_decoder_init(&log_decoder, (char *) data, bytes); + + if (ret != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, + "Log event decoder initialization error : %d", ret); + + flb_sds_destroy(s); + + return -1; + } + + flb_log_event_decoder_next(&log_decoder, &log_event); + ret = flb_log_event_decoder_get_last_result(&log_decoder); + if (ret != FLB_EVENT_DECODER_SUCCESS) { + flb_error("msgpack_unpack_next failed"); + + flb_log_event_decoder_destroy(&log_decoder); + + return -1; + } + + map = *log_event.body; + flb_sds_len_set(s, 0); + tmp = syslog_format(ctx, &map, &s, &log_event.timestamp); + + flb_log_event_decoder_destroy(&log_decoder); + + if (tmp == NULL) { + flb_error("syslog_fromat returns NULL"); + return -1; + } + + *out_data = tmp; + *out_size = flb_sds_len(tmp); + + return 0; +} + +/* Configuration properties map */ +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_STR, "mode", "udp", + 0, FLB_TRUE, offsetof(struct flb_syslog, mode), + "Set the desired transport type, the available options are tcp and udp. If you need to " + "use a TLS secure channel, choose 'tcp' mode here and enable the 'tls' option separately." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_format", "rfc5424", + 0, FLB_TRUE, offsetof(struct flb_syslog, format), + "Specify the Syslog protocol format to use, the available options are rfc3164 " + "and rfc5424." + }, + + { + FLB_CONFIG_MAP_SIZE, "syslog_maxsize", "0", + 0, FLB_TRUE, offsetof(struct flb_syslog, maxsize), + "Set the maximum size allowed per message. The value must be only integers " + "representing the number of bytes allowed. If no value is provided, the " + "default size is set depending of the protocol version specified by " + "syslog_format , rfc3164 sets max size to 1024 bytes, while rfc5424 sets " + "the size to 2048 bytes." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_severity_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, severity_key), + "Specify the name of the key from the original record that contains the Syslog " + "severity number. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_INT, "syslog_severity_preset", "6", + 0, FLB_TRUE, offsetof(struct flb_syslog, severity_preset), + "Specify the preset severity number. It must be 0-7. " + " This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_facility_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, facility_key), + "Specify the name of the key from the original record that contains the Syslog " + "facility number. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_INT, "syslog_facility_preset", "1", + 0, FLB_TRUE, offsetof(struct flb_syslog, facility_preset), + "Specify the preset facility number. It must be 0-23. " + " This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_hostname_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, hostname_key), + "Specify the key name from the original record that contains the hostname that " + "generated the message. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_hostname_preset", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, hostname_preset), + "Specify the preset hostname. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_appname_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, appname_key), + "Specify the key name from the original record that contains the application " + "name that generated the message. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_appname_preset", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, appname_preset), + "Specify the preset appname. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_procid_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, procid_key), + "Specify the key name from the original record that contains the Process ID " + "that generated the message. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_procid_preset", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, procid_preset), + "Specify the preset procid. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_msgid_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, msgid_key), + "Specify the key name from the original record that contains the Message ID " + "associated to the message. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_msgid_preset", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, msgid_preset), + "Specify the preset msgid. This configuration is optional." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_sd_key", NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct flb_syslog, sd_keys), + "Specify the key name from the original record that contains the " + "Structured Data (SD) content. If set, the value of the key must be a map." + "This option can be set multiple times." + }, + + { + FLB_CONFIG_MAP_STR, "syslog_message_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, message_key), + "Specify the key name that contains the message to deliver. Note that if " + "this property is mandatory, otherwise the message will be empty." + }, + + { + FLB_CONFIG_MAP_BOOL, "allow_longer_sd_id", "false", + 0, FLB_TRUE, offsetof(struct flb_syslog, allow_longer_sd_id), + "If true, Fluent-bit allows SD-ID that is longer than 32 characters. " + "Such long SD-ID violates RFC 5424." + }, + + /* EOF */ + {0} +}; + +/* Plugin reference */ +struct flb_output_plugin out_syslog_plugin = { + .name = "syslog", + .description = "Syslog", + .cb_init = cb_syslog_init, + .cb_pre_run = NULL, + .cb_flush = cb_syslog_flush, + .cb_exit = cb_syslog_exit, + + /* Configuration */ + .config_map = config_map, + + /* for testing */ + .test_formatter.callback = cb_syslog_format_test, + + /* Plugin flags */ + .flags = FLB_OUTPUT_NET | FLB_IO_OPT_TLS, +}; diff --git a/src/fluent-bit/plugins/out_syslog/syslog_conf.c b/src/fluent-bit/plugins/out_syslog/syslog_conf.c new file mode 100644 index 000000000..ea16fce26 --- /dev/null +++ b/src/fluent-bit/plugins/out_syslog/syslog_conf.c @@ -0,0 +1,162 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fluent-bit/flb_output_plugin.h> +#include <fluent-bit/flb_kv.h> + +#include "syslog_conf.h" + +static int is_valid_severity(struct flb_output_instance *ins, int val, int format) +{ + if (format != FLB_SYSLOG_RFC5424 && format != FLB_SYSLOG_RFC3164) { + flb_plg_error(ins, "[%s] unknown syslog format.", __FUNCTION__); + return -1; + } + + if (ins == NULL) { + flb_plg_error(ins, "[%s] arg is null. ins=%p", __FUNCTION__, ins); + return -1; + } + if (val < 0 || val > 7) { + flb_plg_error(ins, "[%s] invalid severity level %d. It should be 0-7.", __FUNCTION__, val); + return -1; + } + + return 0; +} + +static int is_valid_facility(struct flb_output_instance *ins, int val, int format) +{ + if (format != FLB_SYSLOG_RFC5424 && format != FLB_SYSLOG_RFC3164) { + flb_plg_error(ins, "[%s] unknown syslog format.", __FUNCTION__); + return -1; + } + + if (ins == NULL) { + flb_plg_error(ins, "[%s] arg is null. ins=%p", __FUNCTION__, ins); + return -1; + } + + if (val < 0 || val > 23) { + flb_plg_error(ins, "[%s] invalid facility level %d. It should be 0-23.", __FUNCTION__, val); + return -1; + } + return 0; +} + + +struct flb_syslog *flb_syslog_config_create(struct flb_output_instance *ins, + struct flb_config *config) +{ + int ret; + const char *tmp; + struct flb_syslog *ctx = NULL; + + /* Allocate plugin context */ + ctx = flb_calloc(1, sizeof(struct flb_syslog)); + if (!ctx) { + flb_errno(); + return NULL; + } + ctx->ins = ins; + ctx->parsed_mode = FLB_SYSLOG_UDP; + ctx->parsed_format = FLB_SYSLOG_RFC5424; + ctx->maxsize = -1; + + /* Populate context with config map defaults and incoming properties */ + ret = flb_output_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_plg_error(ctx->ins, "configuration error"); + flb_syslog_config_destroy(ctx); + return NULL; + } + + /* Set context */ + flb_output_set_context(ins, ctx); + + /* Config Mode */ + tmp = flb_output_get_property("mode", ins); + if (tmp) { + if (!strcasecmp(tmp, "tcp")) { + ctx->parsed_mode = FLB_SYSLOG_TCP; + } + else if (!strcasecmp(tmp, "tls")) { + ctx->parsed_mode = FLB_SYSLOG_TLS; + } + else if (!strcasecmp(tmp, "udp")) { + ctx->parsed_mode = FLB_SYSLOG_UDP; + } + else { + flb_plg_error(ctx->ins, "unknown syslog mode %s", tmp); + flb_syslog_config_destroy(ctx); + return NULL; + } + } + + /* syslog_format */ + tmp = flb_output_get_property("syslog_format", ins); + if (tmp) { + if (strcasecmp(tmp, "rfc3164") == 0) { + ctx->parsed_format = FLB_SYSLOG_RFC3164; + } + else if (strcasecmp(tmp, "rfc5424") == 0) { + ctx->parsed_format = FLB_SYSLOG_RFC5424; + } + else { + flb_plg_error(ctx->ins, "unknown syslog format %s", tmp); + flb_syslog_config_destroy(ctx); + return NULL; + } + } + + if (ctx->parsed_format == FLB_SYSLOG_RFC5424 && ctx->allow_longer_sd_id == FLB_TRUE) { + flb_plg_warn(ctx->ins, "Allow longer SD-ID. It may violate RFC5424."); + } + + /* validate preset values */ + ret = is_valid_severity(ctx->ins, ctx->severity_preset, ctx->parsed_format); + if (ret != 0) { + flb_syslog_config_destroy(ctx); + return NULL; + } + + ret = is_valid_facility(ctx->ins, ctx->facility_preset, ctx->parsed_format); + if (ret != 0) { + flb_syslog_config_destroy(ctx); + return NULL; + } + + + /* syslog maxsize */ + if (ctx->maxsize <= 0) { + if (ctx->parsed_format == FLB_SYSLOG_RFC3164) { + ctx->maxsize = 1024; + } + else if (ctx->parsed_format == FLB_SYSLOG_RFC5424) { + ctx->maxsize = 2048; + } + } + + return ctx; +} + +void flb_syslog_config_destroy(struct flb_syslog *ctx) +{ + flb_free(ctx); +} diff --git a/src/fluent-bit/plugins/out_syslog/syslog_conf.h b/src/fluent-bit/plugins/out_syslog/syslog_conf.h new file mode 100644 index 000000000..8bdb027a5 --- /dev/null +++ b/src/fluent-bit/plugins/out_syslog/syslog_conf.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_OUT_SYSLOG_CONF_H +#define FLB_OUT_SYSLOG_CONF_H + +#include <fluent-bit/flb_config.h> +#include <fluent-bit/flb_output.h> +#include <fluent-bit/flb_pipe.h> + + +#define FLB_SYSLOG_UDP 0 +#define FLB_SYSLOG_TCP 1 +#define FLB_SYSLOG_TLS 2 + +#define FLB_SYSLOG_RFC3164 0 +#define FLB_SYSLOG_RFC5424 1 + +struct flb_syslog { + flb_sockfd_t fd; + struct flb_upstream *u; + flb_sds_t mode; + flb_sds_t format; + size_t maxsize; + flb_sds_t severity_key; + flb_sds_t facility_key; + flb_sds_t timestamp_key; + flb_sds_t hostname_key; + flb_sds_t appname_key; + flb_sds_t procid_key; + flb_sds_t msgid_key; + struct mk_list *sd_keys; + int allow_longer_sd_id; + flb_sds_t message_key; + + /* Preset */ + int severity_preset; + int facility_preset; + flb_sds_t hostname_preset; + flb_sds_t appname_preset; + flb_sds_t procid_preset; + flb_sds_t msgid_preset; + + /* Internal */ + int parsed_mode; + int parsed_format; + struct flb_output_instance *ins; +}; + +struct flb_syslog *flb_syslog_config_create(struct flb_output_instance *ins, + struct flb_config *config); +void flb_syslog_config_destroy(struct flb_syslog *ctx); + +#endif |