2 * IRC - Internet Relay Chat, ircd/s_stats.c
3 * Copyright (C) 2000 Joseph Bongaarts
5 * See file AUTHORS in IRC package for additional names of
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)
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.
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.
30 #include "ircd_chattr.h"
31 #include "ircd_events.h"
32 #include "ircd_features.h"
33 #include "ircd_crypt.h"
35 #include "ircd_reply.h"
36 #include "ircd_string.h"
66 * Report configuration lines and other statistics from this
69 * Note: The info is reported in the order the server uses
70 * it--not reversed as in ircd.conf!
73 static unsigned int report_array[17][3] = {
74 {CONF_SERVER, RPL_STATSCLINE, 'C'},
75 {CONF_CLIENT, RPL_STATSILINE, 'I'},
76 {CONF_LEAF, RPL_STATSLLINE, 'L'},
77 {CONF_OPERATOR, RPL_STATSOLINE, 'O'},
78 {CONF_HUB, RPL_STATSHLINE, 'H'},
79 {CONF_UWORLD, RPL_STATSULINE, 'U'},
84 stats_configured_links(struct Client *sptr, struct StatDesc* sd, int stat,
87 static char null[] = "<NULL>";
91 unsigned short int port;
92 char c, *host, *pass, *name;
94 mask = sd->sd_funcdata;
96 for (tmp = GlobalConfList; tmp; tmp = tmp->next)
98 if ((tmp->status & mask))
100 for (p = &report_array[0][0]; *p; p += 3)
101 if (*p == tmp->status)
106 host = BadPtr(tmp->host) ? null : tmp->host;
107 pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
108 name = BadPtr(tmp->name) ? null : tmp->name;
111 * On K line the passwd contents can be
112 * displayed on STATS reply. -Vesa
114 /* Special-case 'k' or 'K' lines as appropriate... -Kev */
115 if ((tmp->status & CONF_UWORLD))
116 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
117 else if ((tmp->status & (CONF_SERVER | CONF_HUB)))
118 send_reply(sptr, p[1], c, "*", name, port, get_conf_class(tmp));
119 else if ((tmp->status & CONF_CLIENT))
121 if(tmp->passwd && IsDigit(*tmp->passwd) && (!tmp->passwd[1] ||
122 (IsDigit(tmp->passwd[1]) && !tmp->passwd[2])))
123 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
125 send_reply(sptr, p[1], c, host, "*", name, port, get_conf_class(tmp));
128 send_reply(sptr, p[1], c, host, name, port, get_conf_class(tmp));
134 * {CONF_CRULEALL, RPL_STATSDLINE, 'D'},
135 * {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
138 stats_crule_list(struct Client* to, struct StatDesc *sd, int stat,
142 const struct CRuleConf* p = conf_get_crule_list();
144 mask = (stat == 'D') ? CRULE_ALL : CRULE_MASK;
146 for ( ; p; p = p->next)
149 send_reply(to, RPL_STATSDLINE, stat, p->hostmask, p->rule);
154 stats_engine(struct Client *to, struct StatDesc *sd, int stat, char *param)
156 send_reply(to, RPL_STATSENGINE, engine_name());
160 stats_access(struct Client *to, struct StatDesc *sd, int stat, char *param)
162 struct ConfItem *aconf;
168 stats_configured_links(to, sd, stat, param);
172 wilds = string_has_wildcards(param);
174 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
176 if (aconf->status != CONF_CLIENT)
178 if ((!wilds && (!match(aconf->host, param) ||
179 !match(aconf->name, param))) ||
180 (wilds && (!mmatch(param, aconf->host) ||
181 !mmatch(param, aconf->name))))
183 send_reply(to, RPL_STATSILINE, 'I', aconf->host, aconf->name,
184 aconf->port, get_conf_class(aconf));
194 * {CONF_KILL, RPL_STATSKLINE, 'K'},
195 * {CONF_IPKILL, RPL_STATSKLINE, 'k'},
198 report_deny_list(struct Client* to)
200 const struct DenyConf* p = conf_get_deny_list();
201 for ( ; p; p = p->next)
202 send_reply(to, RPL_STATSKLINE, (p->flags & DENY_FLAGS_IP) ? 'k' : 'K',
203 p->hostmask, p->message, p->usermask);
207 stats_klines(struct Client *sptr, struct StatDesc *sd, int stat, char *mask)
214 const struct DenyConf* conf;
222 need_more_params(sptr, "STATS K");
224 report_deny_list(sptr);
230 wilds = string_has_wildcards(mask);
233 if ((host = strchr(mask, '@')))
241 for (conf = conf_get_deny_list(); conf; conf = conf->next)
243 if ((!wilds && ((user || conf->hostmask) &&
244 !match(conf->hostmask, host) &&
245 (!user || !match(conf->usermask, user)))) ||
246 (wilds && !mmatch(host, conf->hostmask) &&
247 (!user || !mmatch(user, conf->usermask))))
249 send_reply(sptr, RPL_STATSKLINE,
250 (conf->flags & DENY_FLAGS_IP) ? 'k' : 'K',
251 conf->hostmask, conf->message, conf->usermask);
259 stats_links(struct Client* sptr, struct StatDesc* sd, int stat, char* name)
261 struct Client *acptr;
266 wilds = string_has_wildcards(name);
269 * Send info about connections which match, or all if the
270 * mask matches me.name. Only restrictions are on those who
271 * are invisible not being visible to 'foreigners' who use
272 * a wild card based search to list it.
274 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
275 "SendM SendKBytes RcveM RcveKBytes :Open since");
276 for (i = 0; i <= HighestFd; i++)
278 if (!(acptr = LocalClientArray[i]))
280 /* Don't return clients when this is a request for `all' */
281 if (!name && IsUser(acptr))
283 /* Don't show invisible people to non opers unless they know the nick */
284 if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) &&
287 /* Only show the ones that match the given mask - if any */
288 if (name && wilds && match(name, cli_name(acptr)))
290 /* Skip all that do not match the specific query */
291 if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr)))
293 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
294 "%s %u %u %u %u %u :%Tu",
295 (*(cli_name(acptr))) ? cli_name(acptr) : "<unregistered>",
296 (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr),
297 (int)cli_sendK(acptr), (int)cli_receiveM(acptr),
298 (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr));
302 /* hopefuly this will be where we'll spit out info about loaded modules */
304 stats_modules(struct Client* to, struct StatDesc* sd, int stat, char* param)
306 crypt_mechs_t* mechs;
308 send_reply(to, SND_EXPLICIT | RPL_STATSLLINE,
309 "Module Description Entry Point");
311 /* atm the only "modules" we have are the crypto mechanisms,
312 eventualy they'll be part of a global dl module list, for now
313 i'll just output data about them -- hikari */
315 if(crypt_mechs_root == NULL)
318 mechs = crypt_mechs_root->next;
325 send_reply(to, SND_EXPLICIT | RPL_STATSLLINE,
327 mechs->mech->shortname, mechs->mech->description,
328 mechs->mech->crypt_function);
336 stats_commands(struct Client* to, struct StatDesc* sd, int stat, char* param)
338 struct Message *mptr;
340 for (mptr = msgtab; mptr->cmd; mptr++)
342 send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes);
346 stats_quarantine(struct Client* to, struct StatDesc* sd, int stat, char* param)
350 for (qline = GlobalQuarantineList; qline; qline = qline->next)
352 if (param && match(param, qline->chname)) /* narrow search */
354 send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason);
359 stats_mapping(struct Client *to, struct StatDesc* sd, int stat, char* param)
363 send_reply(to, RPL_STATSRLINE, "Command", "Name", "Prepend", "Target");
364 for (map = GlobalServiceMapList; map; map = map->next) {
365 struct nick_host *nh;
366 for (nh = map->services; nh; nh = nh->next) {
367 send_reply(to, RPL_STATSRLINE, map->command, map->name,
368 (map->prepend ? map->prepend : "*"), nh->nick);
374 stats_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param)
378 nowr = CurrentTime - cli_since(&me);
379 send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
380 (nowr / 60) % 60, nowr % 60);
381 send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count);
385 stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat,
388 struct Client *acptr;
391 * lowercase 'v' is for human-readable,
392 * uppercase 'V' is for machine-readable
395 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE,
396 "%-20s %-20s Flags Hops Numeric Lag RTT Up Down "
397 "Clients/Max Proto %-10s :Info", "Servername", "Uplink",
400 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
402 if (!IsServer(acptr) && !IsMe(acptr))
405 if (param && match(param, cli_name(acptr)))
407 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ?
408 "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i "
410 "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s",
412 cli_name(cli_serv(acptr)->up),
413 IsBurst(acptr) ? 'B' : '-',
414 IsBurstAck(acptr) ? 'A' : '-',
415 IsHub(acptr) ? 'H' : '-',
416 IsService(acptr) ? 'S' : '-',
419 base64toint(cli_yxx(acptr)),
420 cli_serv(acptr)->lag,
421 cli_serv(acptr)->asll_rtt,
422 cli_serv(acptr)->asll_to,
423 cli_serv(acptr)->asll_from,
424 cli_serv(acptr)->clients,
425 cli_serv(acptr)->nn_mask,
426 cli_serv(acptr)->prot,
427 cli_serv(acptr)->timestamp,
434 stats_meminfo(struct Client* to, struct StatDesc* sd, int stat, char* param)
436 class_send_meminfo(to);
437 send_listinfo(to, 0);
442 stats_help(struct Client* to, struct StatDesc* sd, int stat, char* param)
444 struct StatDesc *asd;
446 /* only if it's my user */
448 for (asd = statsinfo; asd->sd_c; asd++)
449 if (asd->sd_c != sd->sd_c) /* don't send the help for us */
450 sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c - %s", to, asd->sd_c,
454 /* This array of structures contains information about all single-character
455 * stats. Struct StatDesc is defined in s_stats.h.
457 struct StatDesc statsinfo[] = {
458 { 'a', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_a,
459 report_dns_servers, 0,
461 { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
462 stats_configured_links, CONF_SERVER,
463 "Remote server connection lines." },
464 { 'd', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_d,
466 "Dynamic routing configuration." },
467 { 'e', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e,
469 "Report server event loop engine." },
470 { 'f', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f,
472 "Feature settings." },
473 { 'g', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g,
475 "Global bans (G-lines)." },
476 { 'h', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_h,
477 stats_configured_links, (CONF_HUB | CONF_LEAF),
478 "Hubs information." },
479 { 'i', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i,
480 stats_access, CONF_CLIENT,
481 "Connection authorization lines." },
482 { 'j', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_j,
484 "Message length histogram." },
485 { 'k', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k,
487 "Local bans (K-Lines)." },
488 { 'l', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS),
491 "Current connections information." },
492 { 'L', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS),
495 "Dynamicly loaded modules." },
497 { 'M', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_M,
499 "Memory allocation & leak monitoring." },
501 { 'm', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m,
503 "Message usage information." },
504 { 'o', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o,
505 stats_configured_links, CONF_OPERATOR,
506 "Operator information." },
507 { 'p', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p,
509 "Listening ports." },
510 { 'q', (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q,
512 "Quarantined channels list." },
513 { 'R', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_R,
515 "Service mappings." },
517 { 'r', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_r,
519 "System resource usage (Debug only)." },
521 { 'T', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
523 "Configured Message Of The Day files." },
524 { 't', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t,
526 "Local connection statistics (Total SND/RCV, etc)." },
527 { 'U', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U,
528 stats_configured_links, CONF_UWORLD,
529 "Service server & nick jupes information." },
530 { 'u', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u,
532 "Current uptime & highest connection count." },
533 { 'v', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_v,
534 stats_servers_verbose, 0,
535 "Verbose server information." },
536 { 'w', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
538 "Userload statistics." },
540 { 'x', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
542 "List usage information (Debug only)." },
544 { 'y', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
546 "Connection classes." },
547 { 'z', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z,
549 "Memory/Structure allocation information." },
550 { '*', (STAT_FLAG_CASESENS | STAT_FLAG_VARPARAM), FEAT_LAST_F,
552 "Send help for stats." },
553 { '\0', 0, FEAT_LAST_F, 0, 0, 0 }
556 /* This array is for mapping from characters to statistics descriptors */
557 struct StatDesc *statsmap[256];
559 /* Function to build the statsmap from the statsinfo array */
566 /* Make darn sure the statsmap array is initialized to all zeros */
567 for (i = 0; i < 256; i++)
570 /* Build the mapping */
571 for (sd = statsinfo; sd->sd_c; sd++)
573 if (sd->sd_flags & STAT_FLAG_CASESENS)
574 /* case sensitive character... */
575 statsmap[(int)sd->sd_c] = sd;
578 /* case insensitive--make sure to put in two entries */
579 statsmap[(int)ToLower((int)sd->sd_c)] = sd;
580 statsmap[(int)ToUpper((int)sd->sd_c)] = sd;