1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-12 16:54:46 +02:00

JSON-RPC: WHOWAS fetching is now whowas.get, also expose not only

logon_time/logoff_time but also connected_since.

This also fixes the Makefile for the Windows build (i hope)
This commit is contained in:
Bram Matthys
2023-04-15 09:22:44 +02:00
parent 2184f38e7e
commit 7ad160f57a
9 changed files with 181 additions and 120 deletions
+8
View File
@@ -339,6 +339,7 @@ DLL_FILES=\
src/modules/restrict-commands.dll \
src/modules/rmtkl.dll \
src/modules/rpc/channel.dll \
src/modules/rpc/log.dll \
src/modules/rpc/name_ban.dll \
src/modules/rpc/rpc.dll \
src/modules/rpc/stats.dll \
@@ -346,6 +347,7 @@ DLL_FILES=\
src/modules/rpc/server_ban.dll \
src/modules/rpc/server_ban_exception.dll \
src/modules/rpc/spamfilter.dll \
src/modules/rpc/whowas.dll \
src/modules/rpc/user.dll \
src/modules/rules.dll \
src/modules/sajoin.dll \
@@ -1119,6 +1121,9 @@ src/modules/rmtkl.dll: src/modules/rmtkl.c $(INCLUDES)
src/modules/rpc/channel.dll: src/modules/rpc/channel.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rpc/channel.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/channel.pdb $(MODLFLAGS)
src/modules/rpc/log.dll: src/modules/rpc/log.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rpc/log.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/log.pdb $(MODLFLAGS)
src/modules/rpc/name_ban.dll: src/modules/rpc/name_ban.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rpc/name_ban.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/name_ban.pdb $(MODLFLAGS)
@@ -1143,6 +1148,9 @@ src/modules/rpc/spamfilter.dll: src/modules/rpc/spamfilter.c $(INCLUDES)
src/modules/rpc/user.dll: src/modules/rpc/user.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rpc/user.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/user.pdb $(MODLFLAGS)
src/modules/rpc/whowas.dll: src/modules/rpc/whowas.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rpc/whowas.c /Fesrc/modules/rpc/ /Fosrc/modules/rpc/ /Fdsrc/modules/rpc/whowas.pdb $(MODLFLAGS)
src/modules/rules.dll: src/modules/rules.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/rules.c /Fesrc/modules/ /Fosrc/modules/ /Fdsrc/modules/rules.pdb $(MODLFLAGS)
+1 -1
View File
@@ -72,7 +72,7 @@ You can help us by testing this release and reporting any issues at https://bugs
[`rpc.del_timer`](https://www.unrealircd.org/docs/JSON-RPC:Rpc#rpc.del_timer)
so you can schedule JSON-RPC calls, like stats.get, to be executed every xyz msec.
* New JSON-RPC method
[`user.get_whowas`](https://www.unrealircd.org/docs/JSON-RPC:User#user.get_whowas)
[`whowas.get`](https://www.unrealircd.org/docs/JSON-RPC:Whowas#whowas.get)
to fetch WHOWAS history.
* A new message tag `unrealircd.org/issued-by` which is IRCOp-only (and
used intra-server) to communicate who actually issued a command.
+1
View File
@@ -250,6 +250,7 @@ loadmodule "rpc/server_ban_exception";
loadmodule "rpc/name_ban";
loadmodule "rpc/spamfilter";
loadmodule "rpc/log";
loadmodule "rpc/whowas";
/*** Other ***/
// These are modules that don't fit in any of the previous sections
+1
View File
@@ -861,6 +861,7 @@ typedef struct Whowas {
long umodes;
time_t logon;
time_t logoff;
time_t connected_since;
WhoWasEvent event;
struct Client *online; /* Pointer to new nickname for chasing or NULL */
struct Whowas *next; /* for hash table... */
+1 -1
View File
@@ -34,7 +34,7 @@ INCLUDES = ../../include/channel.h \
R_MODULES= \
rpc.so stats.so user.so server.so channel.so server_ban.so \
server_ban_exception.so name_ban.so spamfilter.so \
log.so
log.so whowas.so
MODULES=$(R_MODULES)
MODULEFLAGS=@MODULEFLAGS@
+1 -109
View File
@@ -8,7 +8,7 @@
ModuleHeader MOD_HEADER
= {
"rpc/user",
"1.0.6",
"1.0.7",
"user.* RPC calls",
"UnrealIRCd Team",
"unrealircd-6",
@@ -28,7 +28,6 @@ RPC_CALL_FUNC(rpc_user_kill);
RPC_CALL_FUNC(rpc_user_quit);
RPC_CALL_FUNC(rpc_user_join);
RPC_CALL_FUNC(rpc_user_part);
RPC_CALL_FUNC(rpc_user_get_whowas);
MOD_INIT()
{
@@ -142,15 +141,6 @@ MOD_INIT()
config_error("[rpc/user] Could not register RPC handler");
return MOD_FAILED;
}
memset(&r, 0, sizeof(r));
r.method = "user.get_whowas";
r.loglevel = ULOG_DEBUG;
r.call = rpc_user_get_whowas;
if (!RPCHandlerAdd(modinfo->handle, &r))
{
config_error("[rpc/user] Could not register RPC handler");
return MOD_FAILED;
}
return MOD_SUCCESS;
}
@@ -705,101 +695,3 @@ RPC_CALL_FUNC(rpc_user_part)
rpc_response(client, request, result);
json_decref(result);
}
extern WhoWas MODVAR WHOWAS[NICKNAMEHISTORYLENGTH];
const char *whowas_event_to_string(WhoWasEvent event)
{
if (event == WHOWAS_EVENT_QUIT)
return "quit";
if (event == WHOWAS_EVENT_NICK_CHANGE)
return "nick-change";
if (event == WHOWAS_EVENT_SERVER_TERMINATING)
return "server-terminating";
return "unknown";
}
void json_expand_whowas(json_t *j, const char *key, WhoWas *e, int detail)
{
json_t *child;
json_t *user = NULL;
char buf[BUFSIZE+1];
if (key)
{
child = json_object();
json_object_set_new(j, key, child);
} else {
child = j;
}
json_object_set_new(child, "name", json_string_unreal(e->name));
if (detail == 0)
return;
json_object_set_new(child, "hostname", json_string_unreal(e->hostname));
json_object_set_new(child, "ip", json_string_unreal(e->ip));
snprintf(buf, sizeof(buf), "%s!%s@%s", e->name, e->username, e->hostname);
json_object_set_new(child, "details", json_string_unreal(buf));
if (detail < 2)
return;
json_object_set_new(child, "event", json_string_unreal(whowas_event_to_string(e->event)));
json_object_set_new(child, "logon_time", json_timestamp(e->logon));
json_object_set_new(child, "logoff_time", json_timestamp(e->logoff));
/* client.user */
user = json_object();
json_object_set_new(child, "user", user);
json_object_set_new(user, "username", json_string_unreal(e->username));
if (!BadPtr(e->realname))
json_object_set_new(user, "realname", json_string_unreal(e->realname));
if (!BadPtr(e->virthost))
json_object_set_new(user, "vhost", json_string_unreal(e->virthost));
json_object_set_new(user, "servername", json_string_unreal(e->servername));
if (!BadPtr(e->account))
json_object_set_new(user, "account", json_string_unreal(e->account));
}
RPC_CALL_FUNC(rpc_user_get_whowas)
{
json_t *result, *list, *item;
int details;
int i;
const char *name;
const char *ip;
OPTIONAL_PARAM_STRING("name", name);
OPTIONAL_PARAM_STRING("ip", ip);
OPTIONAL_PARAM_INTEGER("object_detail_level", details, 2);
if (details == 3)
{
rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4.");
return;
}
result = json_object();
list = json_array();
json_object_set_new(result, "list", list);
for (i=0; i < NICKNAMEHISTORYLENGTH; i++)
{
WhoWas *e = &WHOWAS[i];
if (!e->name)
continue;
if (name && !match_simple(name, e->name))
continue;
if (ip && !match_simple(ip, e->ip))
continue;
item = json_object();
json_expand_whowas(item, NULL, e, details);
json_array_append_new(list, item);
}
rpc_response(client, request, result);
json_decref(result);
}
+148
View File
@@ -0,0 +1,148 @@
/* whowas.* RPC calls
* (C) Copyright 2023-.. Bram Matthys (Syzop) and the UnrealIRCd team
* License: GPLv2 or later
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER
= {
"rpc/whowas",
"1.0.0",
"whowas.* RPC calls",
"UnrealIRCd Team",
"unrealircd-6",
};
/* Externals */
extern WhoWas MODVAR WHOWAS[NICKNAMEHISTORYLENGTH];
/* Forward declarations */
RPC_CALL_FUNC(rpc_whowas_get);
MOD_INIT()
{
RPCHandlerInfo r;
MARK_AS_OFFICIAL_MODULE(modinfo);
memset(&r, 0, sizeof(r));
r.method = "whowas.get";
r.loglevel = ULOG_DEBUG;
r.call = rpc_whowas_get;
if (!RPCHandlerAdd(modinfo->handle, &r))
{
config_error("[rpc/whowas] Could not register RPC handler");
return MOD_FAILED;
}
return MOD_SUCCESS;
}
MOD_LOAD()
{
return MOD_SUCCESS;
}
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
const char *whowas_event_to_string(WhoWasEvent event)
{
if (event == WHOWAS_EVENT_QUIT)
return "quit";
if (event == WHOWAS_EVENT_NICK_CHANGE)
return "nick-change";
if (event == WHOWAS_EVENT_SERVER_TERMINATING)
return "server-terminating";
return "unknown";
}
void json_expand_whowas(json_t *j, const char *key, WhoWas *e, int detail)
{
json_t *child;
json_t *user = NULL;
char buf[BUFSIZE+1];
if (key)
{
child = json_object();
json_object_set_new(j, key, child);
} else {
child = j;
}
json_object_set_new(child, "name", json_string_unreal(e->name));
json_object_set_new(child, "event", json_string_unreal(whowas_event_to_string(e->event)));
json_object_set_new(child, "logon_time", json_timestamp(e->logon));
json_object_set_new(child, "logoff_time", json_timestamp(e->logoff));
if (detail == 0)
return;
json_object_set_new(child, "hostname", json_string_unreal(e->hostname));
json_object_set_new(child, "ip", json_string_unreal(e->ip));
snprintf(buf, sizeof(buf), "%s!%s@%s", e->name, e->username, e->hostname);
json_object_set_new(child, "details", json_string_unreal(buf));
if (detail < 2)
return;
if (e->connected_since)
json_object_set_new(child, "connected_since", json_timestamp(e->connected_since));
/* client.user */
user = json_object();
json_object_set_new(child, "user", user);
json_object_set_new(user, "username", json_string_unreal(e->username));
if (!BadPtr(e->realname))
json_object_set_new(user, "realname", json_string_unreal(e->realname));
if (!BadPtr(e->virthost))
json_object_set_new(user, "vhost", json_string_unreal(e->virthost));
json_object_set_new(user, "servername", json_string_unreal(e->servername));
if (!BadPtr(e->account))
json_object_set_new(user, "account", json_string_unreal(e->account));
}
RPC_CALL_FUNC(rpc_whowas_get)
{
json_t *result, *list, *item;
int details;
int i;
const char *name;
const char *ip;
OPTIONAL_PARAM_STRING("name", name);
OPTIONAL_PARAM_STRING("ip", ip);
OPTIONAL_PARAM_INTEGER("object_detail_level", details, 2);
if (details == 3)
{
rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4.");
return;
}
result = json_object();
list = json_array();
json_object_set_new(result, "list", list);
for (i=0; i < NICKNAMEHISTORYLENGTH; i++)
{
WhoWas *e = &WHOWAS[i];
if (!e->name)
continue;
if (name && !match_simple(name, e->name))
continue;
if (ip && !match_simple(ip, e->ip))
continue;
item = json_object();
json_expand_whowas(item, NULL, e, details);
json_array_append_new(list, item);
}
rpc_response(client, request, result);
json_decref(result);
}
+17 -7
View File
@@ -364,19 +364,22 @@ int write_whowasdb(void)
int write_whowas_entry(UnrealDB *db, const char *tmpfname, WhoWas *e)
{
char connected_since[64];
char logontime[64];
char logofftime[64];
char event[16];
snprintf(connected_since, sizeof(connected_since), "%lld", (long long)e->connected_since);
snprintf(logontime, sizeof(logontime), "%lld", (long long)e->logon);
snprintf(logofftime, sizeof(logofftime), "%lld", (long long)e->logoff);
snprintf(event, sizeof(event), "%d", e->event);
W_SAFE(unrealdb_write_int32(db, MAGIC_WHOWASDB_START));
W_SAFE_PROPERTY(db, "nick", e->name);
W_SAFE_PROPERTY(db, "event", event);
W_SAFE_PROPERTY(db, "connected_since", connected_since);
W_SAFE_PROPERTY(db, "logontime", logontime);
W_SAFE_PROPERTY(db, "logofftime", logofftime);
W_SAFE_PROPERTY(db, "event", event);
W_SAFE_PROPERTY(db, "username", e->username);
W_SAFE_PROPERTY(db, "hostname", e->hostname);
W_SAFE_PROPERTY(db, "ip", e->ip);
@@ -399,7 +402,7 @@ int write_whowas_entry(UnrealDB *db, const char *tmpfname, WhoWas *e)
safe_free(hostname); \
safe_free(ip); \
safe_free(realname); \
logontime = logofftime = 0; \
connected_since = logontime = logofftime = 0; \
event = 0; \
safe_free(server); \
safe_free(virthost); \
@@ -431,6 +434,7 @@ int read_whowasdb(void)
char *hostname = NULL;
char *ip = NULL;
char *realname = NULL;
long long connected_since = 0;
long long logontime = 0;
long long logofftime = 0;
int event = 0;
@@ -491,7 +495,7 @@ int read_whowasdb(void)
// Variables
key = value = NULL;
nick = username = hostname = ip = realname = virthost = account = server = NULL;
logontime = logofftime = 0;
connected_since = logontime = logofftime = 0;
event = 0;
R_SAFE(unrealdb_read_int32(db, &magic));
@@ -524,6 +528,11 @@ int read_whowasdb(void)
{
realname = value;
} else
if (!strcmp(key, "connected_since"))
{
connected_since = atoll(value);
safe_free(value);
} else
if (!strcmp(key, "logontime"))
{
logontime = atoll(value);
@@ -581,13 +590,14 @@ int read_whowasdb(void)
if (e->hashv != -1)
free_whowas_fields(e);
/* Set values */
unreal_log(ULOG_DEBUG, "whowasdb", "WHOWASDB_READ_RECORD", NULL,
"[whowasdb] Adding '$nick'...",
log_data_string("nick", nick));
//unreal_log(ULOG_DEBUG, "whowasdb", "WHOWASDB_READ_RECORD", NULL,
// "[whowasdb] Adding '$nick'...",
// log_data_string("nick", nick));
e->hashv = hash_whowas_name(nick);
e->event = event;
e->connected_since = connected_since;
e->logon = logontime;
e->logoff = logofftime;
e->event = event;
safe_strdup(e->name, nick);
safe_strdup(e->username, username);
safe_strdup(e->hostname, hostname);
+3 -2
View File
@@ -46,6 +46,7 @@ void free_whowas_fields(WhoWas *e)
e->event = 0;
e->logon = 0;
e->logoff = 0;
e->connected_since = 0;
/* Remove from lists and reset hashv */
if (e->online)
@@ -57,6 +58,8 @@ void free_whowas_fields(WhoWas *e)
void create_whowas_entry(Client *client, WhoWas *e, WhoWasEvent event)
{
e->hashv = hash_whowas_name(client->name);
e->event = event;
e->connected_since = get_creationtime(client);
e->logon = client->lastnick;
e->logoff = TStime();
e->umodes = client->umodes;
@@ -78,8 +81,6 @@ void create_whowas_entry(Client *client, WhoWas *e, WhoWasEvent event)
*/
/* strlcpy(e->servername, client->user->server,HOSTLEN); */
e->servername = client->user->server;
e->event = event;
}
void add_history(Client *client, int online, WhoWasEvent event)