#############################################################################
# Copyright (c) 2017 Balabit
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# As an additional exemption you are allowed to compile & link against the
# OpenSSL libraries as published by the OpenSSL project. See the file
# COPYING for details.
#
#############################################################################

# This is the experimental transport for transferring messages in whole
# between syslog-ng instances.
#
# EWMM stands for "enterprise wide message model", which is also kind of an
# experimental name, but so far it stuck.
#
# Format:
#   - program name should be "@syslog-ng" which is used to recognize this message
#   - name-values are encoded as JSON in the MSG field
#   - name-value pairs that start with "._" should be hop-by-hop fields only
#     to transmit syslog-ng <> syslog-ng information and is not considered
#     part of the original message.
#   - regexp numeric matches ($0 .. $255) are not transmitted
#

@requires json-plugin

block parser ewmm-parser() {
	channel {
                filter { program("@syslog-ng" type(string)); };

                # NOTE: this will probably overwrite all builtin
                # name value pairs, including $MSG
                rewrite {
                        unset(value("PROGRAM"));
                        unset(value("RAWMSG"));
                };
                parser { json-parser(); };
		parser { tags-parser(template("${._TAGS}")); };
                rewrite {
			# remove hop-by-hop fields
                        unset(value("._TAGS"));
                };
	};
};

template-function "format-ewmm" "<$PRI>1 $ISODATE $LOGHOST @syslog-ng - - ${SDATA:--} $(format-json --leave-initial-dot --scope all-nv-pairs --exclude 0* --exclude 1* --exclude 2* --exclude 3* --exclude 4* --exclude 5* --exclude 6* --exclude 7* --exclude 8* --exclude 9* --exclude SOURCE --exclude .SDATA.* ._TAGS=${TAGS})\n";

#
# syslog-ng is just an alias for the ewmm destination there's no syslog-ng()
# source and shouldn't be one, even if it sounds asymmetrical.
#
# Rationale:
#   - on the source side we want ewmm to be processed on the same channel as
#     everything else is coming in.
#   - we already created default-network-drivers() for exactly this use-case
#   - the ewmm() source below is a pretty limited use-case that is probably
#     only good enough for testing.
#   - with this, we have symmetry: ewmm() source and destination. And we
#     also reserved the name "syslog-ng()" to send messages to an actual
#     syslog-ng instance.
#
# if someone needs a different use-case, the recommended way is to construct
# the source plus parsing bits at the configuration file level, as that
# use-case is not generic enough.
#

block destination syslog-ng(server('127.0.0.1') ...) {
	ewmm(ip(`server`) `__VARARGS__`);
};

block destination ewmm(ip('127.0.0.1') transport(tcp) port(514) ...) {
        network("`ip`" transport(`transport`) port(`port`)
                template("$(format-ewmm)")
                frac-digits(3)
		`__VARARGS__`
        );
};

block source ewmm(
        ip('0.0.0.0')
        port(514)
        transport(tcp)
        flags("")
        ...) {

        channel {
                source {
                        network(ip("`ip`")
                                transport(`transport`)
                                port(`port`)
                                flags(syslog-protocol, `flags`)
                                `__VARARGS__`);
                };

                parser { ewmm-parser(); };
        };
};
