ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/m_stats.c
Revision: 8499
Committed: Thu Apr 5 12:59:25 2018 UTC (6 years ago) by michael
Content type: text/x-csrc
File size: 43378 byte(s)
Log Message:
- Killed Connection::aftype. Use Client::ip.ss.ss_family instead.

File Contents

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

Properties

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