unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

slog.c (5846B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/monitor.c
      3  *   (C) 2021 Bram Matthys and The UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 ModuleHeader MOD_HEADER
     26   = {
     27 	"slog",
     28 	"5.0",
     29 	"S2S logging", 
     30 	"UnrealIRCd Team",
     31 	"unrealircd-6",
     32     };
     33 
     34 /* Forward declarations */
     35 CMD_FUNC(cmd_slog);
     36 void _do_unreal_log_remote_deliver(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized);
     37 
     38 MOD_TEST()
     39 {
     40 	MARK_AS_OFFICIAL_MODULE(modinfo);
     41 	EfunctionAddVoid(modinfo->handle, EFUNC_DO_UNREAL_LOG_REMOTE_DELIVER, _do_unreal_log_remote_deliver);
     42 	return MOD_SUCCESS;
     43 }
     44 
     45 MOD_INIT()
     46 {	
     47 	MARK_AS_OFFICIAL_MODULE(modinfo);
     48 
     49 	CommandAdd(modinfo->handle, "SLOG", cmd_slog, MAXPARA, CMD_SERVER);
     50 
     51 	return MOD_SUCCESS;
     52 }
     53 
     54 MOD_LOAD()
     55 {
     56 	return MOD_SUCCESS;
     57 }
     58 
     59 MOD_UNLOAD()
     60 {
     61 	return MOD_SUCCESS;
     62 }
     63 
     64 /** Server to server logging command.
     65  * This way remote servers can send a log message to all servers.
     66  * The message is broadcasted on to the rest of the network.
     67  * Syntax:
     68  * parv[1]: loglevel (eg "info")
     69  * parv[2]: subsystem (eg: "link")
     70  * parv[3]: event ID (eg: "LINK_DENIED_AUTH_FAILED")
     71  * parv[4]: log message (only the first line!)
     72  * We also require the "unrealircd.org/json-log" message tag to be present
     73  * and to contain a valid UnrealIRCd JSON log.
     74  * In fact, for sending the log message to disk and everything, we ignore
     75  * the message in parv[4] and use the "msg" in the JSON itself.
     76  * This because the "msg" in the JSON can be multi-line (can contain \n's)
     77  * while the message in parv[4] will only be the first line.
     78  *
     79  * Why not skip parv[4] altogether and not send it all?
     80  * I think it is still useful to send these, both for easy watching
     81  * at server to server traffic, and also so (services) servers don't have
     82  * to implement a full JSON parser.
     83  */
     84 CMD_FUNC(cmd_slog)
     85 {
     86 	LogLevel loglevel;
     87 	const char *subsystem;
     88 	const char *event_id;
     89 	const char *msg;
     90 	const char *msg_in_json;
     91 	char *json_incoming = NULL;
     92 	char *json_serialized = NULL;
     93 	MessageTag *m;
     94 	MultiLine *mmsg = NULL;
     95 	json_t *j, *jt;
     96 	json_error_t jerr;
     97 	const char *original_timestamp;
     98 
     99 	if ((parc < 4) || BadPtr(parv[4]))
    100 	{
    101 		sendnumeric(client, ERR_NEEDMOREPARAMS, "SLOG");
    102 		return;
    103 	}
    104 
    105 	loglevel = log_level_stringtoval(parv[1]);
    106 	if (loglevel == ULOG_INVALID)
    107 		return;
    108 	subsystem = parv[2];
    109 	if (!valid_subsystem(subsystem))
    110 		return;
    111 	event_id = parv[3];
    112 	if (!valid_event_id(event_id))
    113 		return;
    114 	msg = parv[4];
    115 
    116 	m = find_mtag(recv_mtags, "unrealircd.org/json-log");
    117 	if (m)
    118 		json_incoming = m->value;
    119 
    120 	if (!json_incoming)
    121 		return;
    122 	// Was previously: unreal_log_raw(loglevel, subsystem, event_id, NULL, msg); // WRONG: this may re-broadcast too, so twice, including back to direction!!!
    123 
    124 	/* Validate the JSON */
    125 	j = json_loads(json_incoming, JSON_REJECT_DUPLICATES, &jerr);
    126 	if (!j)
    127 	{
    128 		unreal_log(ULOG_INFO, "log", "REMOTE_LOG_INVALID", client,
    129 		           "Received malformed JSON in server-to-server log message (SLOG) from $client",
    130 		           log_data_string("bad_json_serialized", json_incoming));
    131 		return;
    132 	}
    133 
    134 	jt = json_object_get(j, "msg");
    135 	if (!jt || !(msg_in_json = json_string_value(jt)))
    136 	{
    137 		unreal_log(ULOG_INFO, "log", "REMOTE_LOG_INVALID", client,
    138 		           "Missing 'msg' in JSON in server-to-server log message (SLOG) from $client",
    139 		           log_data_string("bad_json_serialized", json_incoming));
    140 		json_decref(j);
    141 		return;
    142 	}
    143 	mmsg = line2multiline(msg_in_json);
    144 
    145 	/* Set "timestamp", and save the original one in "original_timestamp" (if it existed) */
    146 	jt = json_object_get(j, "timestamp");
    147 	if (jt)
    148 	{
    149 		original_timestamp = json_string_value(jt);
    150 		if (original_timestamp)
    151 			json_object_set_new(j, "original_timestamp", json_string(original_timestamp));
    152 	}
    153 	json_object_set_new(j, "timestamp", json_string(timestamp_iso8601_now()));
    154 	json_object_set_new(j, "log_source", json_string(client->name));
    155 
    156 	/* Re-serialize the result */
    157 	json_serialized = json_dumps(j, JSON_COMPACT);
    158 
    159 	if (json_serialized)
    160 		do_unreal_log_internal_from_remote(loglevel, subsystem, event_id, mmsg, j, json_serialized, client);
    161 
    162 	/* Broadcast to the other servers */
    163 	sendto_server(client, 0, 0, recv_mtags, ":%s SLOG %s %s %s :%s",
    164 	              client->id,
    165 	              parv[1], parv[2], parv[3], parv[4]);
    166 
    167 	/* Free everything */
    168 	safe_free(json_serialized);
    169 	json_decref(j);
    170 	safe_free_multiline(mmsg);
    171 }
    172 
    173 void _do_unreal_log_remote_deliver(LogLevel loglevel, const char *subsystem, const char *event_id, MultiLine *msg, const char *json_serialized)
    174 {
    175 	MessageTag *mtags = safe_alloc(sizeof(MessageTag));
    176 
    177 	safe_strdup(mtags->name, "unrealircd.org/json-log");
    178 	safe_strdup(mtags->value, json_serialized);
    179 
    180 	/* Note that we only send the first line (msg->line),
    181 	 * even for a multi-line event.
    182 	 * If the recipient really wants to see everything then
    183 	 * they can use the JSON data.
    184 	 */
    185 	sendto_server(NULL, 0, 0, mtags, ":%s SLOG %s %s %s :%s",
    186 	              me.id,
    187 	              log_level_valtostring(loglevel), subsystem, event_id, msg->line);
    188 
    189 	free_message_tags(mtags);
    190 }