ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
Revision: 9070
Committed: Sat Oct 5 17:25:40 2019 UTC (4 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 45825 byte(s)
Log Message:
- m_stats.c:stats_tab[]: use designated initializers

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2019 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_stats.c
23 * \brief Includes required functions for processing the STATS command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "irc_string.h"
31 #include "ircd.h"
32 #include "listener.h"
33 #include "parse.h"
34 #include "conf.h"
35 #include "conf_class.h"
36 #include "conf_cluster.h"
37 #include "conf_gecos.h"
38 #include "conf_pseudo.h"
39 #include "conf_resv.h"
40 #include "conf_service.h"
41 #include "conf_shared.h"
42 #include "hostmask.h"
43 #include "numeric.h"
44 #include "send.h"
45 #include "fdlist.h"
46 #include "misc.h"
47 #include "server.h"
48 #include "server_capab.h"
49 #include "event.h"
50 #include "modules.h"
51 #include "whowas.h"
52 #include "watch.h"
53 #include "reslib.h"
54 #include "motd.h"
55 #include "ipcache.h"
56
57
58 static const char *
59 oper_privs_as_string(const unsigned int flags)
60 {
61 static const struct oper_flags
62 {
63 unsigned int flag;
64 unsigned char letter;
65 } flag_table[] = {
66 { OPER_FLAG_ADMIN, 'A' },
67 { OPER_FLAG_CLOSE, 'B' },
68 { OPER_FLAG_CONNECT, 'C' },
69 { OPER_FLAG_CONNECT_REMOTE, 'D' },
70 { OPER_FLAG_DIE, 'E' },
71 { OPER_FLAG_DLINE, 'F' },
72 { OPER_FLAG_GLOBOPS, 'G' },
73 { OPER_FLAG_JOIN_RESV, 'H' },
74 { OPER_FLAG_KILL, 'I' },
75 { OPER_FLAG_KILL_REMOTE, 'J' },
76 { OPER_FLAG_KLINE, 'K' },
77 { OPER_FLAG_LOCOPS, 'L' },
78 { OPER_FLAG_MODULE, 'M' },
79 { OPER_FLAG_NICK_RESV, 'N' },
80 { OPER_FLAG_OPME, 'O' },
81 { OPER_FLAG_REHASH, 'P' },
82 { OPER_FLAG_REMOTEBAN, 'Q' },
83 { OPER_FLAG_RESTART, 'R' },
84 { OPER_FLAG_RESV, 'S' },
85 { OPER_FLAG_SET, 'T' },
86 { OPER_FLAG_SQUIT, 'U' },
87 { OPER_FLAG_SQUIT_REMOTE, 'V' },
88 { OPER_FLAG_UNDLINE, 'W' },
89 { OPER_FLAG_UNKLINE, 'X' },
90 { OPER_FLAG_UNRESV, 'Y' },
91 { OPER_FLAG_UNXLINE, 'Z' },
92 { OPER_FLAG_WALLOPS, 'a' },
93 { OPER_FLAG_XLINE, 'b' },
94 { 0, '\0' }
95 };
96
97 static char buf[sizeof(flag_table) / sizeof(flag_table[0])];
98 char *p = buf;
99
100 for (const struct oper_flags *tab = flag_table; tab->flag; ++tab)
101 if (flags & tab->flag)
102 *p++ = tab->letter;
103
104 if (p == buf)
105 *p++ = '0';
106
107 *p = '\0';
108
109 return buf;
110 }
111
112 static void
113 report_shared(struct Client *source_p)
114 {
115 static const struct shared_types
116 {
117 unsigned int type;
118 unsigned char letter;
119 } flag_table[] = {
120 { SHARED_KLINE, 'K' },
121 { SHARED_UNKLINE, 'U' },
122 { SHARED_XLINE, 'X' },
123 { SHARED_UNXLINE, 'Y' },
124 { SHARED_RESV, 'Q' },
125 { SHARED_UNRESV, 'R' },
126 { SHARED_LOCOPS, 'L' },
127 { SHARED_DLINE, 'D' },
128 { SHARED_UNDLINE, 'E' },
129 { 0, '\0' }
130 };
131
132 dlink_node *node;
133 char buf[sizeof(flag_table) / sizeof(flag_table[0]) + 1]; /* +1 for 'c' */
134
135 DLINK_FOREACH(node, shared_get_list()->head)
136 {
137 const struct SharedItem *shared = node->data;
138 char *p = buf;
139
140 *p++ = 'c';
141
142 for (const struct shared_types *tab = flag_table; tab->type; ++tab)
143 if (tab->type & shared->type)
144 *p++ = tab->letter;
145 else
146 *p++ = ToLower(tab->letter);
147
148 *p = '\0';
149
150 sendto_one_numeric(source_p, &me, RPL_STATSULINE, shared->server,
151 shared->user, shared->host, buf);
152 }
153 }
154
155 static void
156 report_cluster(struct Client *source_p)
157 {
158 static const struct cluster_types
159 {
160 unsigned int type;
161 unsigned char letter;
162 } flag_table[] = {
163 { CLUSTER_KLINE, 'K' },
164 { CLUSTER_UNKLINE, 'U' },
165 { CLUSTER_XLINE, 'X' },
166 { CLUSTER_UNXLINE, 'Y' },
167 { CLUSTER_RESV, 'Q' },
168 { CLUSTER_UNRESV, 'R' },
169 { CLUSTER_LOCOPS, 'L' },
170 { CLUSTER_DLINE, 'D' },
171 { CLUSTER_UNDLINE, 'E' },
172 { 0, '\0' }
173 };
174
175 dlink_node *node;
176 char buf[sizeof(flag_table) / sizeof(flag_table[0]) + 1]; /* +1 for 'C' */
177
178 DLINK_FOREACH(node, cluster_get_list()->head)
179 {
180 const struct ClusterItem *cluster = node->data;
181 char *p = buf;
182
183 *p++ = 'C';
184
185 for (const struct cluster_types *tab = flag_table; tab->type; ++tab)
186 if (tab->type & cluster->type)
187 *p++ = tab->letter;
188 else
189 *p++ = ToLower(tab->letter);
190
191 *p = '\0';
192
193 sendto_one_numeric(source_p, &me, RPL_STATSULINE, cluster->server,
194 "*", "*", buf);
195 }
196 }
197
198 static void
199 stats_service(struct Client *source_p, int parc, char *parv[])
200 {
201 dlink_node *node;
202
203 DLINK_FOREACH(node, service_get_list()->head)
204 {
205 const struct ServiceItem *service = node->data;
206 sendto_one_numeric(source_p, &me, RPL_STATSSERVICE, "*", service->name, 0, 0);
207 }
208 }
209
210 static void
211 stats_gecos(struct Client *source_p, int parc, char *parv[])
212 {
213 dlink_node *node;
214
215 DLINK_FOREACH(node, gecos_get_list()->head)
216 {
217 const struct GecosItem *gecos = node->data;
218 sendto_one_numeric(source_p, &me, RPL_STATSXLINE,
219 gecos->expire ? 'x' : 'X',
220 gecos->mask, gecos->reason);
221 }
222 }
223
224 /*
225 * inputs - pointer to client requesting confitem report
226 * - ConfType to report
227 * output - none
228 * side effects -
229 */
230 static void
231 stats_operator(struct Client *source_p, int parc, char *parv[])
232 {
233 dlink_node *node;
234
235 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_o_oper_only)
236 {
237 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
238 return;
239 }
240
241 DLINK_FOREACH(node, operator_items.head)
242 {
243 const struct MaskItem *conf = node->data;
244
245 /* Don't allow non opers to see oper privs */
246 if (HasUMode(source_p, UMODE_OPER))
247 sendto_one_numeric(source_p, &me, RPL_STATSOLINE, 'O', conf->user, conf->host,
248 conf->name, oper_privs_as_string(conf->port),
249 conf->class->name);
250 else
251 sendto_one_numeric(source_p, &me, RPL_STATSOLINE, 'O', conf->user, conf->host,
252 conf->name, "0", conf->class->name);
253 }
254 }
255
256 static void
257 stats_connect(struct Client *source_p, int parc, char *parv[])
258 {
259 dlink_node *node;
260
261 DLINK_FOREACH(node, connect_items.head)
262 {
263 char buf[8];
264 char *p = buf;
265 const struct MaskItem *conf = node->data;
266
267 if (IsConfAllowAutoConn(conf))
268 *p++ = 'A';
269 if (IsConfSSL(conf))
270 *p++ = 'S';
271 if (p == buf)
272 *p++ = '*';
273
274 *p = '\0';
275
276 /*
277 * Allow admins to see actual ips unless 'hide_server_ips' is enabled
278 */
279 if (ConfigServerHide.hide_server_ips == 0 && HasUMode(source_p, UMODE_ADMIN))
280 sendto_one_numeric(source_p, &me, RPL_STATSCLINE, 'C', conf->host,
281 buf, conf->name, conf->port, conf->class->name);
282 else
283 sendto_one_numeric(source_p, &me, RPL_STATSCLINE, 'C', "*@127.0.0.1",
284 buf, conf->name, conf->port, conf->class->name);
285 }
286 }
287
288 /* report_resv()
289 *
290 * inputs - pointer to client pointer to report to.
291 * output - NONE
292 * side effects - report all resvs to client.
293 */
294 static void
295 stats_resv(struct Client *source_p, int parc, char *parv[])
296 {
297 dlink_node *node;
298
299 DLINK_FOREACH(node, resv_chan_get_list()->head)
300 {
301 const struct ResvItem *resv = node->data;
302
303 sendto_one_numeric(source_p, &me, RPL_STATSQLINE,
304 resv->expire ? 'q' : 'Q',
305 resv->mask, resv->reason);
306 }
307
308 DLINK_FOREACH(node, resv_nick_get_list()->head)
309 {
310 const struct ResvItem *resv = node->data;
311
312 sendto_one_numeric(source_p, &me, RPL_STATSQLINE,
313 resv->expire ? 'q' : 'Q',
314 resv->mask, resv->reason);
315 }
316 }
317
318 static void
319 stats_memory(struct Client *source_p, int parc, char *parv[])
320 {
321 dlink_node *node, *node2;
322
323 unsigned int local_client_conf_count = 0; /* local client conf links */
324
325 unsigned int channel_members = 0;
326 unsigned int channel_invites = 0;
327 unsigned int channel_bans = 0;
328 unsigned int channel_except = 0;
329 unsigned int channel_invex = 0;
330
331 unsigned int wwu = 0; /* whowas users */
332 unsigned int number_ips_stored = 0; /* number of ip addresses hashed */
333
334 size_t channel_ban_memory = 0;
335 size_t channel_except_memory = 0;
336 size_t channel_invex_memory = 0;
337
338 unsigned int safelist_count = 0;
339 size_t safelist_memory = 0;
340
341 size_t wwm = 0; /* whowas array memory used */
342 size_t mem_ips_stored = 0; /* memory used by ip address hash */
343
344 unsigned int local_client_count = 0;
345 unsigned int remote_client_count = 0;
346
347 size_t local_client_memory_used = 0;
348 size_t remote_client_memory_used = 0;
349
350 unsigned int watch_list_headers = 0; /* watchlist headers */
351 unsigned int watch_list_entries = 0; /* watchlist entries */
352 size_t watch_list_memory = 0; /* watchlist memory used */
353
354 unsigned int listener_count = 0;
355 size_t listener_memory = 0;
356
357
358 DLINK_FOREACH(node, local_server_list.head)
359 {
360 const struct Client *target_p = node->data;
361
362 local_client_conf_count += dlink_list_length(&target_p->connection->confs);
363 }
364
365 DLINK_FOREACH(node, local_client_list.head)
366 {
367 const struct Client *target_p = node->data;
368
369 local_client_conf_count += dlink_list_length(&target_p->connection->confs);
370 watch_list_entries += dlink_list_length(&target_p->connection->watches);
371 }
372
373 local_client_count = dlink_list_length(&local_server_list) + dlink_list_length(&local_client_list);
374 remote_client_count = dlink_list_length(&global_server_list) + dlink_list_length(&global_client_list) - local_client_count;
375
376 /* Count up all members, invites, ban lists, except lists, Invex lists */
377 DLINK_FOREACH(node, channel_get_list()->head)
378 {
379 const struct Channel *chptr = node->data;
380
381 channel_members += dlink_list_length(&chptr->members);
382 channel_invites += dlink_list_length(&chptr->invites);
383
384 channel_bans += dlink_list_length(&chptr->banlist);
385 channel_ban_memory += dlink_list_length(&chptr->banlist) * sizeof(struct Ban);
386
387 channel_except += dlink_list_length(&chptr->exceptlist);
388 channel_except_memory += dlink_list_length(&chptr->exceptlist) * sizeof(struct Ban);
389
390 channel_invex += dlink_list_length(&chptr->invexlist);
391 channel_invex_memory += dlink_list_length(&chptr->invexlist) * sizeof(struct Ban);
392 }
393
394 safelist_count = dlink_list_length(&listing_client_list);
395 if (safelist_count)
396 {
397 safelist_memory = safelist_count * sizeof(struct ListTask);
398
399 DLINK_FOREACH(node, listing_client_list.head)
400 {
401 const struct Client *acptr = node->data;
402
403 DLINK_FOREACH(node2, acptr->connection->list_task->show_mask.head)
404 safelist_memory += strlen(node2->data);
405
406 DLINK_FOREACH(node2, acptr->connection->list_task->hide_mask.head)
407 safelist_memory += strlen(node2->data);
408 }
409 }
410
411 watch_count_memory(&watch_list_headers, &watch_list_memory);
412 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
413 "z :WATCH headers %u(%zu) entries %u(%zu)",
414 watch_list_headers,
415 watch_list_memory,
416 watch_list_entries,
417 watch_list_entries * sizeof(dlink_node) * 2);
418
419 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
420 "z :Clients %u(%zu)",
421 dlink_list_length(&global_client_list),
422 dlink_list_length(&global_client_list) * sizeof(struct Client));
423
424 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
425 "z :Servers %u(%zu, %zu)",
426 dlink_list_length(&global_server_list),
427 dlink_list_length(&global_server_list) * sizeof(struct Client),
428 dlink_list_length(&global_server_list) * sizeof(struct Server));
429
430 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
431 "z :Attached confs %u(%zu)",
432 local_client_conf_count,
433 local_client_conf_count * sizeof(dlink_node));
434
435 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
436 "z :Resv channels %u(%zu) nicks %u(%zu)",
437 dlink_list_length(resv_chan_get_list()),
438 dlink_list_length(resv_chan_get_list()) * sizeof(struct ResvItem),
439 dlink_list_length(resv_nick_get_list()),
440 dlink_list_length(resv_nick_get_list()) * sizeof(struct ResvItem));
441
442 listener_count_memory(&listener_count, &listener_memory);
443 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
444 "z :Listeners %u(%zu)",
445 listener_count, listener_memory);
446
447 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
448 "z :Classes %u(%zu)",
449 dlink_list_length(class_get_list()),
450 dlink_list_length(class_get_list()) * sizeof(struct ClassItem));
451
452 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
453 "z :Channels %u(%zu)",
454 dlink_list_length(channel_get_list()),
455 dlink_list_length(channel_get_list()) * sizeof(struct Channel));
456
457 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
458 "z :Bans %u(%zu)",
459 channel_bans, channel_ban_memory);
460
461 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
462 "z :Exceptions %u(%zu)",
463 channel_except, channel_except_memory);
464
465 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
466 "z :Invex %u(%zu)",
467 channel_invex, channel_invex_memory);
468
469 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
470 "z :Channel members %u(%zu) invites %u(%zu)",
471 channel_members,
472 channel_members * sizeof(struct Membership),
473 channel_invites,
474 channel_invites * sizeof(struct Invite));
475
476 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
477 "z :Safelist %u(%zu)",
478 safelist_count, safelist_memory);
479
480 whowas_count_memory(&wwu, &wwm);
481 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
482 "z :Whowas users %u(%zu)", wwu, wwm);
483
484 motd_memory_count(source_p);
485
486 ipcache_get_stats(&number_ips_stored, &mem_ips_stored);
487 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
488 "z :iphash %u(%zu)",
489 number_ips_stored, mem_ips_stored);
490
491 local_client_memory_used = local_client_count * (sizeof(struct Client) + sizeof(struct Connection));
492 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
493 "z :Local client Memory in use: %u(%zu)",
494 local_client_count, local_client_memory_used);
495
496 remote_client_memory_used = remote_client_count * sizeof(struct Client);
497 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
498 "z :Remote client Memory in use: %u(%zu)",
499 remote_client_count, remote_client_memory_used);
500 }
501
502 static void
503 stats_dns_servers(struct Client *source_p, int parc, char *parv[])
504 {
505 char ipaddr[HOSTIPLEN + 1] = "";
506
507 for (unsigned int i = 0; i < irc_nscount; ++i)
508 {
509 getnameinfo((const struct sockaddr *)&(irc_nsaddr_list[i]),
510 irc_nsaddr_list[i].ss_len, ipaddr,
511 sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
512 sendto_one_numeric(source_p, &me, RPL_STATSALINE, ipaddr);
513 }
514 }
515
516 /* stats_deny()
517 *
518 * input - client to report to
519 * output - none
520 * side effects - client is given dline list.
521 */
522 static void
523 stats_deny(struct Client *source_p, int parc, char *parv[])
524 {
525 dlink_node *node;
526
527 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
528 {
529 DLINK_FOREACH(node, atable[i].head)
530 {
531 const struct AddressRec *arec = node->data;
532
533 if (arec->type != CONF_DLINE)
534 continue;
535
536 const struct MaskItem *conf = arec->conf;
537 /* Don't report a temporary dline as permanent dline */
538 if (conf->until)
539 continue;
540
541 sendto_one_numeric(source_p, &me, RPL_STATSDLINE, 'D', conf->host, conf->reason);
542 }
543 }
544 }
545
546 /* stats_tdeny()
547 *
548 * input - client to report to
549 * output - none
550 * side effects - client is given dline list.
551 */
552 static void
553 stats_tdeny(struct Client *source_p, int parc, char *parv[])
554 {
555 dlink_node *node;
556
557 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
558 {
559 DLINK_FOREACH(node, atable[i].head)
560 {
561 const struct AddressRec *arec = node->data;
562
563 if (arec->type != CONF_DLINE)
564 continue;
565
566 const struct MaskItem *conf = arec->conf;
567 /* Don't report a permanent dline as temporary dline */
568 if (conf->until == 0)
569 continue;
570
571 sendto_one_numeric(source_p, &me, RPL_STATSDLINE, 'd', conf->host, conf->reason);
572 }
573 }
574 }
575
576 /* stats_exempt()
577 *
578 * input - client to report to
579 * output - none
580 * side effects - client is given list of exempt blocks
581 */
582 static void
583 stats_exempt(struct Client *source_p, int parc, char *parv[])
584 {
585 dlink_node *node;
586
587 if (ConfigGeneral.stats_e_disabled)
588 {
589 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
590 return;
591 }
592
593 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
594 {
595 DLINK_FOREACH(node, atable[i].head)
596 {
597 const struct AddressRec *arec = node->data;
598
599 if (arec->type != CONF_EXEMPT)
600 continue;
601
602 const struct MaskItem *conf = arec->conf;
603 sendto_one_numeric(source_p, &me, RPL_STATSDLINE, 'e', conf->host, "");
604 }
605 }
606 }
607
608 static void
609 stats_events(struct Client *source_p, int parc, char *parv[])
610 {
611 dlink_node *node;
612
613 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
614 "E :Operation Next Execution");
615 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
616 "E :---------------------------------------------");
617
618 DLINK_FOREACH(node, event_get_list()->head)
619 {
620 const struct event *ev = node->data;
621
622 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
623 "E :%-30s %-4ju seconds",
624 ev->name, ev->next - event_base->time.sec_monotonic);
625 }
626 }
627
628 static void
629 stats_fdlist(struct Client *source_p, int parc, char *parv[])
630 {
631 for (int fd = 0; fd <= highest_fd; ++fd)
632 {
633 const fde_t *F = &fd_table[fd];
634
635 if (F->flags.open == true)
636 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
637 "F :fd %-5d desc '%s'", F->fd, F->desc);
638 }
639 }
640
641 static void
642 stats_hubleaf(struct Client *source_p, int parc, char *parv[])
643 {
644 dlink_node *node, *node2;
645
646 DLINK_FOREACH(node, connect_items.head)
647 {
648 const struct MaskItem *conf = node->data;
649
650 DLINK_FOREACH(node2, conf->hub_list.head)
651 sendto_one_numeric(source_p, &me, RPL_STATSHLINE, 'H', node2->data, conf->name, 0, "*");
652 }
653
654 DLINK_FOREACH(node, connect_items.head)
655 {
656 const struct MaskItem *conf = node->data;
657
658 DLINK_FOREACH(node2, conf->leaf_list.head)
659 sendto_one_numeric(source_p, &me, RPL_STATSLLINE, 'L', node2->data, conf->name, 0, "*");
660 }
661 }
662
663 /*
664 * show_iline_prefix()
665 *
666 * inputs - pointer to struct Client requesting output
667 * - pointer to struct MaskItem
668 * - name to which iline prefix will be prefixed to
669 * output - pointer to static string with prefixes listed in ascii form
670 * side effects - NONE
671 */
672 static const char *
673 show_iline_prefix(const struct Client *source_p, const struct MaskItem *conf)
674 {
675 static char buf[USERLEN + 16];
676 char *p = buf;
677
678 if (IsConfWebIRC(conf))
679 *p++ = '<';
680 if (IsNoTilde(conf))
681 *p++ = '-';
682 if (IsNeedIdentd(conf))
683 *p++ = '+';
684 if (!IsNeedPassword(conf))
685 *p++ = '&';
686 if (IsConfExemptResv(conf))
687 *p++ = '$';
688 if (IsConfDoSpoofIp(conf))
689 *p++ = '=';
690 if (IsConfCanFlood(conf))
691 *p++ = '|';
692 if (HasUMode(source_p, UMODE_OPER))
693 {
694 if (IsConfExemptKline(conf))
695 *p++ = '^';
696 if (IsConfExemptXline(conf))
697 *p++ = '!';
698 if (IsConfExemptLimits(conf))
699 *p++ = '>';
700 }
701
702 strlcpy(p, conf->user, USERLEN + 1);
703 return buf;
704 }
705
706 static void
707 report_auth(struct Client *source_p, int parc, char *parv[])
708 {
709 dlink_node *node;
710
711 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
712 {
713 DLINK_FOREACH(node, atable[i].head)
714 {
715 const struct AddressRec *arec = node->data;
716
717 if (arec->type != CONF_CLIENT)
718 continue;
719
720 const struct MaskItem *conf = arec->conf;
721 if (!HasUMode(source_p, UMODE_OPER) && IsConfDoSpoofIp(conf))
722 continue;
723
724 sendto_one_numeric(source_p, &me, RPL_STATSILINE, 'I',
725 conf->name == NULL ? "*" : conf->name,
726 show_iline_prefix(source_p, conf),
727 conf->host, conf->port,
728 conf->class->name);
729 }
730 }
731 }
732
733 static void
734 stats_auth(struct Client *source_p, int parc, char *parv[])
735 {
736 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
737 if (ConfigGeneral.stats_i_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
738 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
739
740 /* If unopered, only return matching auth blocks */
741 else if (ConfigGeneral.stats_i_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
742 {
743 const struct MaskItem *conf = NULL;
744
745 if (MyConnect(source_p))
746 conf = find_conf_by_address(source_p->host,
747 &source_p->ip, CONF_CLIENT,
748 source_p->username,
749 source_p->connection->password, 1);
750 else
751 conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
752 source_p->username, NULL, 1);
753
754 if (conf == NULL)
755 return;
756
757 sendto_one_numeric(source_p, &me, RPL_STATSILINE,
758 'I', "*", show_iline_prefix(source_p, conf),
759 conf->host, conf->port,
760 conf->class->name);
761 }
762 else /* They are opered, or allowed to see all auth blocks */
763 report_auth(source_p, 0, NULL);
764 }
765
766 /* report_Klines()
767 * Inputs: Client to report to,
768 * type(==0 for perm, !=0 for temporary)
769 * mask
770 * Output: None
771 * Side effects: Reports configured K(or k)-lines to source_p.
772 */
773 static void
774 report_Klines(struct Client *source_p, int tkline)
775 {
776 dlink_node *node;
777 char c = '\0';
778
779 if (tkline)
780 c = 'k';
781 else
782 c = 'K';
783
784 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
785 {
786 DLINK_FOREACH(node, atable[i].head)
787 {
788 const struct AddressRec *arec = node->data;
789
790 if (arec->type != CONF_KLINE)
791 continue;
792
793 const struct MaskItem *conf = arec->conf;
794 if ((!tkline && conf->until) ||
795 (tkline && !conf->until))
796 continue;
797
798 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, c, conf->host, conf->user,
799 conf->reason);
800 }
801 }
802 }
803
804 static void
805 stats_tklines(struct Client *source_p, int parc, char *parv[])
806 {
807 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
808 if (ConfigGeneral.stats_k_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
809 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
810
811 /* If unopered, only return matching klines */
812 else if (ConfigGeneral.stats_k_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
813 {
814 const struct MaskItem *conf = NULL;
815
816 if (MyConnect(source_p))
817 conf = find_conf_by_address(source_p->host,
818 &source_p->ip, CONF_KLINE,
819 source_p->username, NULL, 1);
820 else
821 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
822 source_p->username, NULL, 1);
823
824 if (conf == NULL)
825 return;
826
827 /* Don't report a permanent kline as temporary kline */
828 if (conf->until == 0)
829 return;
830
831 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, 'k',
832 conf->host, conf->user, conf->reason);
833 }
834 else /* They are opered, or allowed to see all klines */
835 report_Klines(source_p, 1);
836 }
837
838 static void
839 stats_klines(struct Client *source_p, int parc, char *parv[])
840 {
841 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
842 if (ConfigGeneral.stats_k_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
843 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
844
845 /* If unopered, only return matching klines */
846 else if (ConfigGeneral.stats_k_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
847 {
848 const struct MaskItem *conf = NULL;
849
850 /* Search for a kline */
851 if (MyConnect(source_p))
852 conf = find_conf_by_address(source_p->host,
853 &source_p->ip, CONF_KLINE,
854 source_p->username, NULL, 0);
855 else
856 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
857 source_p->username, NULL, 0);
858
859 if (conf == NULL)
860 return;
861
862 /* Don't report a temporary kline as permanent kline */
863 if (conf->until)
864 return;
865
866 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, 'K',
867 conf->host, conf->user, conf->reason);
868 }
869 else /* They are opered, or allowed to see all klines */
870 report_Klines(source_p, 0);
871 }
872
873 static void
874 stats_messages(struct Client *source_p, int parc, char *parv[])
875 {
876 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_m_oper_only)
877 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
878 else
879 report_messages(source_p);
880 }
881
882 static void
883 stats_pseudo(struct Client *source_p, int parc, char *parv[])
884 {
885 dlink_node *node;
886
887 DLINK_FOREACH(node, pseudo_get_list()->head)
888 {
889 const struct PseudoItem *pseudo = node->data;
890 sendto_one_numeric(source_p, &me, RPL_STATSPSEUDO, pseudo->command,
891 pseudo->name, pseudo->nick, pseudo->serv,
892 pseudo->prepend ? pseudo->prepend : "*");
893 }
894 }
895
896 /* stats_operedup()
897 *
898 * input - client pointer
899 * output - none
900 * side effects - client is shown a list of active opers
901 */
902 static void
903 stats_operedup(struct Client *source_p, int parc, char *parv[])
904 {
905 dlink_node *node;
906 unsigned int opercount = 0;
907 char buf[IRCD_BUFSIZE] = "";
908
909 DLINK_FOREACH(node, oper_list.head)
910 {
911 const struct Client *target_p = node->data;
912
913 if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
914 continue;
915
916 if (HasUMode(source_p, UMODE_OPER) || !HasUMode(target_p, UMODE_HIDEIDLE))
917 snprintf(buf, sizeof(buf), "%s", time_dissect(client_get_idle_time(source_p, target_p)));
918 else
919 strlcpy(buf, "n/a", sizeof(buf));
920
921 if (MyConnect(source_p) && HasUMode(source_p, UMODE_OPER))
922 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
923 "p :[%c][%s] %s (%s@%s) Idle: %s",
924 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
925 oper_privs_as_string(target_p->connection->operflags),
926 target_p->name, target_p->username, target_p->host, buf);
927 else
928 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
929 "p :[%c] %s (%s@%s) Idle: %s",
930 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
931 target_p->name, target_p->username, target_p->host, buf);
932 ++opercount;
933 }
934
935 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
936 "p :%u OPER(s)", opercount);
937 }
938
939 /* show_ports()
940 *
941 * inputs - pointer to client to show ports to
942 * output - none
943 * side effects - send port listing to a client
944 */
945 static void
946 show_ports(struct Client *source_p)
947 {
948 dlink_node *node;
949
950 DLINK_FOREACH(node, listener_get_list()->head)
951 {
952 char buf[8];
953 char *p = buf;
954 const struct Listener *listener = node->data;
955
956 if (listener->flags & LISTENER_HIDDEN)
957 {
958 if (!HasUMode(source_p, UMODE_ADMIN))
959 continue;
960 *p++ = 'H';
961 }
962
963 if (listener->flags & LISTENER_SERVER)
964 *p++ = 'S';
965 if (listener->flags & LISTENER_SSL)
966 *p++ = 's';
967 *p = '\0';
968
969 if (HasUMode(source_p, UMODE_ADMIN) && ConfigServerHide.hide_server_ips == 0)
970 sendto_one_numeric(source_p, &me, RPL_STATSPLINE, 'P', listener->port,
971 listener->name,
972 listener->ref_count, buf,
973 listener->active ? "active" : "disabled");
974 else
975 sendto_one_numeric(source_p, &me, RPL_STATSPLINE, 'P', listener->port,
976 me.name, listener->ref_count, buf,
977 listener->active ? "active" : "disabled");
978 }
979 }
980
981 static void
982 stats_ports(struct Client *source_p, int parc, char *parv[])
983 {
984 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_P_oper_only)
985 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
986 else
987 show_ports(source_p);
988 }
989
990 static void
991 stats_tstats(struct Client *source_p, int parc, char *parv[])
992 {
993 dlink_node *node;
994 struct ServerStatistics sp = ServerStats;
995
996 DLINK_FOREACH(node, local_server_list.head)
997 {
998 const struct Client *target_p = node->data;
999
1000 sp.is_sbs += target_p->connection->send.bytes;
1001 sp.is_sbr += target_p->connection->recv.bytes;
1002 sp.is_sti += event_base->time.sec_monotonic - target_p->connection->created_monotonic;
1003 sp.is_sv++;
1004 }
1005
1006 DLINK_FOREACH(node, local_client_list.head)
1007 {
1008 const struct Client *target_p = node->data;
1009
1010 sp.is_cbs += target_p->connection->send.bytes;
1011 sp.is_cbr += target_p->connection->recv.bytes;
1012 sp.is_cti += event_base->time.sec_monotonic - target_p->connection->created_monotonic;
1013 sp.is_cl++;
1014 }
1015
1016 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1017 "t :accepts %u refused %u",
1018 sp.is_ac, sp.is_ref);
1019 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1020 "t :unknown commands %u prefixes %u",
1021 sp.is_unco, sp.is_unpf);
1022 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1023 "t :nick collisions %u unknown closes %u",
1024 sp.is_kill, sp.is_ni);
1025 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1026 "t :wrong direction %u empty %u",
1027 sp.is_wrdi, sp.is_empt);
1028 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1029 "t :numerics seen %u",
1030 sp.is_num);
1031 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1032 "t :auth successes %u fails %u",
1033 sp.is_asuc, sp.is_abad);
1034 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1035 "t :Client Server");
1036 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1037 "t :connected %u %u",
1038 sp.is_cl, sp.is_sv);
1039 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1040 "t :bytes sent %ju %ju",
1041 sp.is_cbs, sp.is_sbs);
1042 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1043 "t :bytes received %ju %ju",
1044 sp.is_cbr, sp.is_sbr);
1045 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1046 "t :time connected %ju %ju",
1047 sp.is_cti, sp.is_sti);
1048 }
1049
1050 static void
1051 stats_uptime(struct Client *source_p, int parc, char *parv[])
1052 {
1053 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_u_oper_only)
1054 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
1055 else
1056 {
1057 sendto_one_numeric(source_p, &me, RPL_STATSUPTIME,
1058 time_dissect(event_base->time.sec_monotonic - me.connection->created_monotonic));
1059 if (ConfigServerHide.disable_remote_commands == 0 || HasUMode(source_p, UMODE_OPER))
1060 sendto_one_numeric(source_p, &me, RPL_STATSCONN, Count.max_loc_con,
1061 Count.max_loc, Count.totalrestartcount);
1062 }
1063 }
1064
1065 static void
1066 stats_shared(struct Client *source_p, int parc, char *parv[])
1067 {
1068 report_shared(source_p);
1069 report_cluster(source_p);
1070 }
1071
1072 /* stats_servers()
1073 *
1074 * input - client pointer
1075 * output - none
1076 * side effects - client is shown lists of who connected servers
1077 */
1078 static void
1079 stats_servers(struct Client *source_p, int parc, char *parv[])
1080 {
1081 dlink_node *node;
1082
1083 DLINK_FOREACH(node, local_server_list.head)
1084 {
1085 const struct Client *target_p = node->data;
1086
1087 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1088 "v :%s (%s!%s@%s) Idle: %s",
1089 target_p->name,
1090 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1091 "*", "*", time_dissect(event_base->time.sec_monotonic - target_p->connection->last_data));
1092 }
1093
1094 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1095 "v :%u Server(s)",
1096 dlink_list_length(&local_server_list));
1097 }
1098
1099 static void
1100 stats_class(struct Client *source_p, int parc, char *parv[])
1101 {
1102 dlink_node *node;
1103
1104 DLINK_FOREACH(node, class_get_list()->head)
1105 {
1106 const struct ClassItem *class = node->data;
1107
1108 sendto_one_numeric(source_p, &me, RPL_STATSYLINE, 'Y',
1109 class->name, class->ping_freq,
1110 class->con_freq,
1111 class->max_total, class->max_sendq,
1112 class->max_recvq,
1113 class->ref_count,
1114 class->number_per_cidr, class->cidr_bitlen_ipv4,
1115 class->number_per_cidr, class->cidr_bitlen_ipv6,
1116 class->active ? "active" : "disabled");
1117 }
1118 }
1119
1120 static void
1121 stats_servlinks(struct Client *source_p, int parc, char *parv[])
1122 {
1123 dlink_node *node;
1124 uintmax_t sendB = 0, recvB = 0;
1125 uintmax_t uptime = 0;
1126
1127 if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1128 {
1129 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
1130 return;
1131 }
1132
1133 DLINK_FOREACH(node, local_server_list.head)
1134 {
1135 const struct Client *target_p = node->data;
1136
1137 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1138 if (!HasUMode(source_p, UMODE_OPER))
1139 continue;
1140
1141 sendB += target_p->connection->send.bytes;
1142 recvB += target_p->connection->recv.bytes;
1143
1144 /* ":%s 211 %s %s %u %u %ju %u %ju :%ju %ju %s" */
1145 sendto_one_numeric(source_p, &me, RPL_STATSLINKINFO,
1146 client_get_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1147 dbuf_length(&target_p->connection->buf_sendq),
1148 target_p->connection->send.messages,
1149 target_p->connection->send.bytes >> 10,
1150 target_p->connection->recv.messages,
1151 target_p->connection->recv.bytes >> 10,
1152 (event_base->time.sec_monotonic - target_p->connection->created_monotonic),
1153 (event_base->time.sec_monotonic - target_p->connection->last_data),
1154 HasUMode(source_p, UMODE_OPER) ? capab_get(target_p) : "TS");
1155 }
1156
1157 sendB >>= 10;
1158 recvB >>= 10;
1159
1160 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :%u total server(s)",
1161 dlink_list_length(&local_server_list));
1162 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :Sent total: %7.2f %s",
1163 _GMKv(sendB), _GMKs(sendB));
1164 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :Recv total: %7.2f %s",
1165 _GMKv(recvB), _GMKs(recvB));
1166
1167 uptime = (event_base->time.sec_monotonic - me.connection->created_monotonic);
1168
1169 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1170 "? :Server send: %7.2f %s (%4.1f KiB/s)",
1171 _GMKv((me.connection->send.bytes >> 10)),
1172 _GMKs((me.connection->send.bytes >> 10)),
1173 (float)((float)((me.connection->send.bytes) >> 10) /
1174 (float)uptime));
1175 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1176 "? :Server recv: %7.2f %s (%4.1f KiB/s)",
1177 _GMKv((me.connection->recv.bytes >> 10)),
1178 _GMKs((me.connection->recv.bytes >> 10)),
1179 (float)((float)((me.connection->recv.bytes) >> 10) /
1180 (float)uptime));
1181 }
1182
1183 /* parse_stats_args()
1184 *
1185 * inputs - arg count
1186 * - args
1187 * - doall flag
1188 * - wild card or not
1189 * output - pointer to name to use
1190 * side effects -
1191 * common parse routine for m_stats args
1192 *
1193 */
1194 static const char *
1195 parse_stats_args(struct Client *source_p, int parc, char *parv[], bool *doall, bool *wilds)
1196 {
1197 if (parc > 2)
1198 {
1199 const char *name = parv[2];
1200
1201 if (irccmp(name, ID_or_name(&me, source_p)) == 0)
1202 *doall = true;
1203 else if (match(name, ID_or_name(&me, source_p)) == 0)
1204 *doall = true;
1205
1206 *wilds = has_wildcards(name);
1207
1208 return name;
1209 }
1210
1211 return NULL;
1212 }
1213
1214 static void
1215 stats_L_list(struct Client *source_p, const char *name, bool doall, bool wilds,
1216 dlink_list *list, const char statchar)
1217 {
1218 dlink_node *node;
1219
1220 /*
1221 * Send info about connections which match, or all if the
1222 * mask matches from.
1223 */
1224 DLINK_FOREACH(node, list->head)
1225 {
1226 const struct Client *target_p = node->data;
1227 enum addr_mask_type type = 0;
1228
1229 if (!doall && wilds && match(name, target_p->name))
1230 continue;
1231
1232 if (!(doall || wilds) && irccmp(name, target_p->name))
1233 continue;
1234
1235 if (IsUpper(statchar))
1236 type = SHOW_IP;
1237 else
1238 type = HIDE_IP;
1239
1240 if (IsServer(target_p) || IsConnecting(target_p) || IsHandshake(target_p))
1241 if (!HasUMode(source_p, UMODE_ADMIN))
1242 type = MASK_IP;
1243
1244 sendto_one_numeric(source_p, &me, RPL_STATSLINKINFO,
1245 client_get_name(target_p, type),
1246 dbuf_length(&target_p->connection->buf_sendq),
1247 target_p->connection->send.messages,
1248 target_p->connection->send.bytes >> 10,
1249 target_p->connection->recv.messages,
1250 target_p->connection->recv.bytes >> 10,
1251 (event_base->time.sec_monotonic - target_p->connection->created_monotonic),
1252 (event_base->time.sec_monotonic - target_p->connection->last_data),
1253 IsServer(target_p) ? capab_get(target_p) : "-");
1254 }
1255 }
1256
1257 /*
1258 * stats_L
1259 *
1260 * inputs - pointer to client to report to
1261 * - doall flag
1262 * - wild card or not
1263 * output - NONE
1264 * side effects -
1265 */
1266 static void
1267 stats_L(struct Client *source_p, const char *name, bool doall,
1268 bool wilds, const char statchar)
1269 {
1270 stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1271 stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1272 stats_L_list(source_p, name, doall, wilds, &local_server_list, statchar);
1273 }
1274
1275 static void
1276 stats_ltrace(struct Client *source_p, int parc, char *parv[])
1277 {
1278 bool doall = false;
1279 bool wilds = false;
1280 const char *name = NULL;
1281
1282 if ((name = parse_stats_args(source_p, parc, parv, &doall, &wilds)))
1283 {
1284 const char statchar = *parv[1];
1285 stats_L(source_p, name, doall, wilds, statchar);
1286 }
1287 else
1288 sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "STATS");
1289 }
1290
1291 struct StatsStruct
1292 {
1293 const unsigned char letter;
1294 void (*handler)(struct Client *, int, char *[]);
1295 const unsigned int required_modes;
1296 };
1297
1298 static const struct StatsStruct *stats_map[256];
1299 static const struct StatsStruct stats_tab[] =
1300 {
1301 { .letter = 'a', .handler = stats_dns_servers, .required_modes = UMODE_ADMIN },
1302 { .letter = 'A', .handler = stats_dns_servers, .required_modes = UMODE_ADMIN },
1303 { .letter = 'c', .handler = stats_connect, .required_modes = UMODE_OPER },
1304 { .letter = 'C', .handler = stats_connect, .required_modes = UMODE_OPER },
1305 { .letter = 'd', .handler = stats_tdeny, .required_modes = UMODE_OPER },
1306 { .letter = 'D', .handler = stats_deny, .required_modes = UMODE_OPER },
1307 { .letter = 'e', .handler = stats_exempt, .required_modes = UMODE_OPER },
1308 { .letter = 'E', .handler = stats_events, .required_modes = UMODE_ADMIN },
1309 { .letter = 'f', .handler = stats_fdlist, .required_modes = UMODE_ADMIN },
1310 { .letter = 'F', .handler = stats_fdlist, .required_modes = UMODE_ADMIN },
1311 { .letter = 'h', .handler = stats_hubleaf, .required_modes = UMODE_OPER },
1312 { .letter = 'H', .handler = stats_hubleaf, .required_modes = UMODE_OPER },
1313 { .letter = 'i', .handler = stats_auth },
1314 { .letter = 'I', .handler = stats_auth },
1315 { .letter = 'k', .handler = stats_tklines },
1316 { .letter = 'K', .handler = stats_klines },
1317 { .letter = 'l', .handler = stats_ltrace, .required_modes = UMODE_OPER },
1318 { .letter = 'L', .handler = stats_ltrace, .required_modes = UMODE_OPER },
1319 { .letter = 'm', .handler = stats_messages },
1320 { .letter = 'M', .handler = stats_messages },
1321 { .letter = 'o', .handler = stats_operator },
1322 { .letter = 'O', .handler = stats_operator },
1323 { .letter = 'p', .handler = stats_operedup },
1324 { .letter = 'P', .handler = stats_ports },
1325 { .letter = 'q', .handler = stats_resv, .required_modes = UMODE_OPER },
1326 { .letter = 'Q', .handler = stats_resv, .required_modes = UMODE_OPER },
1327 { .letter = 's', .handler = stats_pseudo, .required_modes = UMODE_OPER },
1328 { .letter = 'S', .handler = stats_service, .required_modes = UMODE_OPER },
1329 { .letter = 't', .handler = stats_tstats, .required_modes = UMODE_OPER },
1330 { .letter = 'T', .handler = motd_report, .required_modes = UMODE_OPER },
1331 { .letter = 'u', .handler = stats_uptime },
1332 { .letter = 'U', .handler = stats_shared, .required_modes = UMODE_OPER },
1333 { .letter = 'v', .handler = stats_servers, .required_modes = UMODE_OPER },
1334 { .letter = 'x', .handler = stats_gecos, .required_modes = UMODE_OPER },
1335 { .letter = 'X', .handler = stats_gecos, .required_modes = UMODE_OPER },
1336 { .letter = 'y', .handler = stats_class, .required_modes = UMODE_OPER },
1337 { .letter = 'Y', .handler = stats_class, .required_modes = UMODE_OPER },
1338 { .letter = 'z', .handler = stats_memory, .required_modes = UMODE_OPER },
1339 { .letter = '?', .handler = stats_servlinks },
1340 { .letter = '\0' }
1341 };
1342
1343 static void
1344 do_stats(struct Client *source_p, int parc, char *parv[])
1345 {
1346 const unsigned char statchar = *parv[1];
1347 const struct StatsStruct *tab;
1348
1349 if (statchar == '\0')
1350 {
1351 sendto_one_numeric(source_p, &me, RPL_ENDOFSTATS, '*');
1352 return;
1353 }
1354
1355 if ((tab = stats_map[statchar]))
1356 {
1357 if (tab->required_modes == 0 || HasUMode(source_p, tab->required_modes))
1358 tab->handler(source_p, parc, parv);
1359 else
1360 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
1361
1362 sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1363 "STATS %c requested by %s (%s@%s) [%s]",
1364 statchar, source_p->name, source_p->username,
1365 source_p->host, source_p->servptr->name);
1366 }
1367
1368 sendto_one_numeric(source_p, &me, RPL_ENDOFSTATS, statchar);
1369 }
1370
1371 /*
1372 * m_stats()
1373 * parv[0] = command
1374 * parv[1] = stat letter/command
1375 * parv[2] = (if present) server/mask in stats L
1376 */
1377 static int
1378 m_stats(struct Client *source_p, int parc, char *parv[])
1379 {
1380 static uintmax_t last_used = 0;
1381
1382 /* Check the user is actually allowed to do /stats, and isn't flooding */
1383 if ((last_used + ConfigGeneral.pace_wait) > event_base->time.sec_monotonic)
1384 {
1385 sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "STATS");
1386 return 0;
1387 }
1388
1389 last_used = event_base->time.sec_monotonic;
1390
1391 /* Is the stats meant for us? */
1392 if (ConfigServerHide.disable_remote_commands == 0)
1393 if (server_hunt(source_p, ":%s STATS %s :%s", 2, parc, parv)->ret != HUNTED_ISME)
1394 return 0;
1395
1396 do_stats(source_p, parc, parv);
1397 return 0;
1398 }
1399
1400 /*
1401 * ms_stats()
1402 * parv[0] = command
1403 * parv[1] = stat letter/command
1404 * parv[2] = (if present) server/mask in stats L, or target
1405 */
1406 static int
1407 ms_stats(struct Client *source_p, int parc, char *parv[])
1408 {
1409 if (server_hunt(source_p, ":%s STATS %s :%s", 2, parc, parv)->ret != HUNTED_ISME)
1410 return 0;
1411
1412 do_stats(source_p, parc, parv);
1413 return 0;
1414 }
1415
1416 static void
1417 stats_init(void)
1418 {
1419 for (const struct StatsStruct *tab = stats_tab; tab->letter; ++tab)
1420 stats_map[tab->letter] = tab;
1421 }
1422
1423 static struct Message stats_msgtab =
1424 {
1425 .cmd = "STATS",
1426 .args_min = 2,
1427 .args_max = MAXPARA,
1428 .handlers[UNREGISTERED_HANDLER] = m_unregistered,
1429 .handlers[CLIENT_HANDLER] = m_stats,
1430 .handlers[SERVER_HANDLER] = ms_stats,
1431 .handlers[ENCAP_HANDLER] = m_ignore,
1432 .handlers[OPER_HANDLER] = ms_stats
1433 };
1434
1435 static void
1436 module_init(void)
1437 {
1438 stats_init();
1439 mod_add_cmd(&stats_msgtab);
1440 }
1441
1442 static void
1443 module_exit(void)
1444 {
1445 mod_del_cmd(&stats_msgtab);
1446 }
1447
1448 struct module module_entry =
1449 {
1450 .version = "$Revision$",
1451 .modinit = module_init,
1452 .modexit = module_exit,
1453 };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision