ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
Revision: 9318
Committed: Sun Mar 8 11:40:39 2020 UTC (4 years ago) by michael
Content type: text/x-csrc
File size: 45762 byte(s)
Log Message:
- m_stats.c:stats_dns_servers(): remove extraneous parantheses on irc_nsaddr_list

File Contents

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

Properties

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