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 }