ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
Revision: 7997
Committed: Tue Mar 14 13:17:52 2017 UTC (7 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 43081 byte(s)
Log Message:
- Rename get_client_name() to client_get_name()

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2017 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 "conf.h"
34 #include "conf_class.h"
35 #include "conf_cluster.h"
36 #include "conf_gecos.h"
37 #include "conf_resv.h"
38 #include "conf_service.h"
39 #include "conf_shared.h"
40 #include "hostmask.h"
41 #include "numeric.h"
42 #include "send.h"
43 #include "fdlist.h"
44 #include "misc.h"
45 #include "server.h"
46 #include "event.h"
47 #include "parse.h"
48 #include "modules.h"
49 #include "whowas.h"
50 #include "watch.h"
51 #include "reslib.h"
52 #include "motd.h"
53 #include "ipcache.h"
54
55
56 static void
57 report_shared(struct Client *source_p)
58 {
59 static const struct shared_types
60 {
61 unsigned int type;
62 unsigned char letter;
63 } flag_table[] = {
64 { SHARED_KLINE, 'K' },
65 { SHARED_UNKLINE, 'U' },
66 { SHARED_XLINE, 'X' },
67 { SHARED_UNXLINE, 'Y' },
68 { SHARED_RESV, 'Q' },
69 { SHARED_UNRESV, 'R' },
70 { SHARED_LOCOPS, 'L' },
71 { SHARED_DLINE, 'D' },
72 { SHARED_UNDLINE, 'E' },
73 { 0, '\0' }
74 };
75
76 dlink_node *node;
77 char buf[sizeof(flag_table) / sizeof(struct shared_types) + 1]; /* +1 for 'c' */
78
79 DLINK_FOREACH(node, shared_get_list()->head)
80 {
81 const struct SharedItem *shared = node->data;
82 char *p = buf;
83
84 *p++ = 'c';
85
86 for (const struct shared_types *tab = flag_table; tab->type; ++tab)
87 if (tab->type & shared->type)
88 *p++ = tab->letter;
89 else
90 *p++ = ToLower(tab->letter);
91
92 *p = '\0';
93
94 sendto_one_numeric(source_p, &me, RPL_STATSULINE, shared->server,
95 shared->user, shared->host, buf);
96 }
97 }
98
99 static void
100 report_cluster(struct Client *source_p)
101 {
102 static const struct cluster_types
103 {
104 unsigned int type;
105 unsigned char letter;
106 } flag_table[] = {
107 { CLUSTER_KLINE, 'K' },
108 { CLUSTER_UNKLINE, 'U' },
109 { CLUSTER_XLINE, 'X' },
110 { CLUSTER_UNXLINE, 'Y' },
111 { CLUSTER_RESV, 'Q' },
112 { CLUSTER_UNRESV, 'R' },
113 { CLUSTER_LOCOPS, 'L' },
114 { CLUSTER_DLINE, 'D' },
115 { CLUSTER_UNDLINE, 'E' },
116 { 0, '\0' }
117 };
118
119 dlink_node *node;
120 char buf[sizeof(flag_table) / sizeof(struct cluster_types) + 1]; /* +1 for 'C' */
121
122 DLINK_FOREACH(node, cluster_get_list()->head)
123 {
124 const struct ClusterItem *cluster = node->data;
125 char *p = buf;
126
127 *p++ = 'C';
128
129 for (const struct cluster_types *tab = flag_table; tab->type; ++tab)
130 if (tab->type & cluster->type)
131 *p++ = tab->letter;
132 else
133 *p++ = ToLower(tab->letter);
134
135 *p = '\0';
136
137 sendto_one_numeric(source_p, &me, RPL_STATSULINE, cluster->server,
138 "*", "*", buf);
139 }
140 }
141
142 static void
143 stats_service(struct Client *source_p, int parc, char *parv[])
144 {
145 dlink_node *node;
146
147 DLINK_FOREACH(node, service_get_list()->head)
148 {
149 const struct ServiceItem *service = node->data;
150 sendto_one_numeric(source_p, &me, RPL_STATSSERVICE, 'S', "*", service->name, 0, 0);
151 }
152 }
153
154 static void
155 stats_gecos(struct Client *source_p, int parc, char *parv[])
156 {
157 dlink_node *node;
158
159 DLINK_FOREACH(node, gecos_get_list()->head)
160 {
161 const struct GecosItem *gecos = node->data;
162 sendto_one_numeric(source_p, &me, RPL_STATSXLINE,
163 gecos->expire ? 'x' : 'X',
164 gecos->mask, gecos->reason);
165 }
166 }
167
168 /*
169 * inputs - pointer to client requesting confitem report
170 * - ConfType to report
171 * output - none
172 * side effects -
173 */
174 static void
175 stats_operator(struct Client *source_p, int parc, char *parv[])
176 {
177 dlink_node *node;
178
179 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_o_oper_only)
180 {
181 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
182 return;
183 }
184
185 DLINK_FOREACH(node, operator_items.head)
186 {
187 const struct MaskItem *conf = node->data;
188
189 /* Don't allow non opers to see oper privs */
190 if (HasUMode(source_p, UMODE_OPER))
191 sendto_one_numeric(source_p, &me, RPL_STATSOLINE, 'O', conf->user, conf->host,
192 conf->name, oper_privs_as_string(conf->port),
193 conf->class->name);
194 else
195 sendto_one_numeric(source_p, &me, RPL_STATSOLINE, 'O', conf->user, conf->host,
196 conf->name, "0", conf->class->name);
197 }
198 }
199
200 static void
201 stats_connect(struct Client *source_p, int parc, char *parv[])
202 {
203 dlink_node *node;
204
205 DLINK_FOREACH(node, connect_items.head)
206 {
207 char buf[8];
208 char *p = buf;
209 const struct MaskItem *conf = node->data;
210
211 if (IsConfAllowAutoConn(conf))
212 *p++ = 'A';
213 if (IsConfSSL(conf))
214 *p++ = 'S';
215 if (p == buf)
216 *p++ = '*';
217
218 *p = '\0';
219
220 /*
221 * Allow admins to see actual ips unless hide_server_ips is enabled
222 */
223 if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
224 sendto_one_numeric(source_p, &me, RPL_STATSCLINE, 'C', conf->host,
225 buf, conf->name, conf->port,
226 conf->class->name);
227 else
228 sendto_one_numeric(source_p, &me, RPL_STATSCLINE, 'C',
229 "*@127.0.0.1", buf, conf->name, conf->port,
230 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_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_list),
401 dlink_list_length(&channel_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_hubleaf(struct Client *source_p, int parc, char *parv[])
576 {
577 dlink_node *node, *node2;
578
579 DLINK_FOREACH(node, connect_items.head)
580 {
581 const struct MaskItem *conf = node->data;
582
583 DLINK_FOREACH(node2, conf->hub_list.head)
584 sendto_one_numeric(source_p, &me, RPL_STATSHLINE, 'H', node2->data, conf->name, 0, "*");
585 }
586
587 DLINK_FOREACH(node, connect_items.head)
588 {
589 const struct MaskItem *conf = node->data;
590
591 DLINK_FOREACH(node2, conf->leaf_list.head)
592 sendto_one_numeric(source_p, &me, RPL_STATSLLINE, 'L', node2->data, conf->name, 0, "*");
593 }
594 }
595
596 /*
597 * show_iline_prefix()
598 *
599 * inputs - pointer to struct Client requesting output
600 * - pointer to struct MaskItem
601 * - name to which iline prefix will be prefixed to
602 * output - pointer to static string with prefixes listed in ascii form
603 * side effects - NONE
604 */
605 static const char *
606 show_iline_prefix(const struct Client *source_p, const struct MaskItem *conf)
607 {
608 static char buf[USERLEN + 16];
609 char *p = buf;
610
611 if (IsConfWebIRC(conf))
612 *p++ = '<';
613 if (IsNoTilde(conf))
614 *p++ = '-';
615 if (IsNeedIdentd(conf))
616 *p++ = '+';
617 if (!IsNeedPassword(conf))
618 *p++ = '&';
619 if (IsConfExemptResv(conf))
620 *p++ = '$';
621 if (IsConfDoSpoofIp(conf))
622 *p++ = '=';
623 if (IsConfCanFlood(conf))
624 *p++ = '|';
625 if (HasUMode(source_p, UMODE_OPER))
626 {
627 if (IsConfExemptKline(conf))
628 *p++ = '^';
629 if (IsConfExemptXline(conf))
630 *p++ = '!';
631 if (IsConfExemptLimits(conf))
632 *p++ = '>';
633 }
634
635 strlcpy(p, conf->user, USERLEN + 1);
636 return buf;
637 }
638
639 static void
640 report_auth(struct Client *source_p, int parc, char *parv[])
641 {
642 dlink_node *node;
643
644 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
645 {
646 DLINK_FOREACH(node, atable[i].head)
647 {
648 const struct AddressRec *arec = node->data;
649
650 if (arec->type != CONF_CLIENT)
651 continue;
652
653 const struct MaskItem *conf = arec->conf;
654 if (!HasUMode(source_p, UMODE_OPER) && IsConfDoSpoofIp(conf))
655 continue;
656
657 sendto_one_numeric(source_p, &me, RPL_STATSILINE, 'I',
658 conf->name == NULL ? "*" : conf->name,
659 show_iline_prefix(source_p, conf),
660 conf->host, conf->port,
661 conf->class->name);
662 }
663 }
664 }
665
666 static void
667 stats_auth(struct Client *source_p, int parc, char *parv[])
668 {
669 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
670 if (ConfigGeneral.stats_i_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
671 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
672
673 /* If unopered, only return matching auth blocks */
674 else if (ConfigGeneral.stats_i_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
675 {
676 const struct MaskItem *conf = NULL;
677
678 if (MyConnect(source_p))
679 conf = find_conf_by_address(source_p->host,
680 &source_p->connection->ip, CONF_CLIENT,
681 source_p->connection->aftype,
682 source_p->username,
683 source_p->connection->password, 1);
684 else
685 conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT, 0,
686 source_p->username, NULL, 1);
687
688 if (!conf)
689 return;
690
691 sendto_one_numeric(source_p, &me, RPL_STATSILINE,
692 'I', "*", show_iline_prefix(source_p, conf),
693 conf->host, conf->port,
694 conf->class->name);
695 }
696 else /* They are opered, or allowed to see all auth blocks */
697 report_auth(source_p, 0, NULL);
698 }
699
700 /* report_Klines()
701 * Inputs: Client to report to,
702 * type(==0 for perm, !=0 for temporary)
703 * mask
704 * Output: None
705 * Side effects: Reports configured K(or k)-lines to source_p.
706 */
707 static void
708 report_Klines(struct Client *source_p, int tkline)
709 {
710 dlink_node *node;
711 char c = '\0';
712
713 if (tkline)
714 c = 'k';
715 else
716 c = 'K';
717
718 for (unsigned int i = 0; i < ATABLE_SIZE; ++i)
719 {
720 DLINK_FOREACH(node, atable[i].head)
721 {
722 const struct AddressRec *arec = node->data;
723
724 if (arec->type != CONF_KLINE)
725 continue;
726
727 const struct MaskItem *conf = arec->conf;
728 if ((!tkline && conf->until) ||
729 (tkline && !conf->until))
730 continue;
731
732 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, c, conf->host, conf->user,
733 conf->reason);
734 }
735 }
736 }
737
738 static void
739 stats_tklines(struct Client *source_p, int parc, char *parv[])
740 {
741 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
742 if (ConfigGeneral.stats_k_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
743 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
744
745 /* If unopered, only return matching klines */
746 else if (ConfigGeneral.stats_k_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
747 {
748 const struct MaskItem *conf = NULL;
749
750 if (MyConnect(source_p))
751 conf = find_conf_by_address(source_p->host,
752 &source_p->connection->ip, CONF_KLINE,
753 source_p->connection->aftype,
754 source_p->username, NULL, 1);
755 else
756 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE, 0,
757 source_p->username, NULL, 1);
758
759 if (!conf)
760 return;
761
762 /* Don't report a permanent kline as temporary kline */
763 if (!conf->until)
764 return;
765
766 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, 'k',
767 conf->host, conf->user, conf->reason);
768 }
769 else /* They are opered, or allowed to see all klines */
770 report_Klines(source_p, 1);
771 }
772
773 static void
774 stats_klines(struct Client *source_p, int parc, char *parv[])
775 {
776 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
777 if (ConfigGeneral.stats_k_oper_only == 2 && !HasUMode(source_p, UMODE_OPER))
778 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
779
780 /* If unopered, only return matching klines */
781 else if (ConfigGeneral.stats_k_oper_only == 1 && !HasUMode(source_p, UMODE_OPER))
782 {
783 const struct MaskItem *conf = NULL;
784
785 /* Search for a kline */
786 if (MyConnect(source_p))
787 conf = find_conf_by_address(source_p->host,
788 &source_p->connection->ip, CONF_KLINE,
789 source_p->connection->aftype,
790 source_p->username, NULL, 0);
791 else
792 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE, 0,
793 source_p->username, NULL, 0);
794
795 if (!conf)
796 return;
797
798 /* Don't report a temporary kline as permanent kline */
799 if (conf->until)
800 return;
801
802 sendto_one_numeric(source_p, &me, RPL_STATSKLINE, 'K',
803 conf->host, conf->user, conf->reason);
804 }
805 else /* They are opered, or allowed to see all klines */
806 report_Klines(source_p, 0);
807 }
808
809 static void
810 stats_messages(struct Client *source_p, int parc, char *parv[])
811 {
812 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_m_oper_only)
813 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
814 else
815 report_messages(source_p);
816 }
817
818 /* stats_operedup()
819 *
820 * input - client pointer
821 * output - none
822 * side effects - client is shown a list of active opers
823 */
824 static void
825 stats_operedup(struct Client *source_p, int parc, char *parv[])
826 {
827 dlink_node *node;
828 unsigned int opercount = 0;
829 char buf[IRCD_BUFSIZE] = "";
830
831 DLINK_FOREACH(node, oper_list.head)
832 {
833 const struct Client *target_p = node->data;
834
835 if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
836 continue;
837
838 if (HasUMode(source_p, UMODE_OPER) || !HasUMode(target_p, UMODE_HIDEIDLE))
839 snprintf(buf, sizeof(buf), "%s", time_dissect(client_get_idle_time(source_p, target_p)));
840 else
841 strlcpy(buf, "n/a", sizeof(buf));
842
843 if (MyConnect(source_p) && HasUMode(source_p, UMODE_OPER))
844 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
845 "p :[%c][%s] %s (%s@%s) Idle: %s",
846 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
847 oper_privs_as_string(target_p->connection->operflags),
848 target_p->name, target_p->username, target_p->host, buf);
849 else
850 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
851 "p :[%c] %s (%s@%s) Idle: %s",
852 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
853 target_p->name, target_p->username, target_p->host, buf);
854 ++opercount;
855 }
856
857 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
858 "p :%u OPER(s)", opercount);
859 }
860
861 /* show_ports()
862 *
863 * inputs - pointer to client to show ports to
864 * output - none
865 * side effects - send port listing to a client
866 */
867 static void
868 show_ports(struct Client *source_p)
869 {
870 dlink_node *node;
871
872 DLINK_FOREACH(node, listener_get_list()->head)
873 {
874 char buf[8];
875 char *p = buf;
876 const struct Listener *listener = node->data;
877
878 if (listener->flags & LISTENER_HIDDEN)
879 {
880 if (!HasUMode(source_p, UMODE_ADMIN))
881 continue;
882 *p++ = 'H';
883 }
884
885 if (listener->flags & LISTENER_SERVER)
886 *p++ = 'S';
887 if (listener->flags & LISTENER_SSL)
888 *p++ = 's';
889 *p = '\0';
890
891 if (HasUMode(source_p, UMODE_ADMIN) && !ConfigServerHide.hide_server_ips)
892 sendto_one_numeric(source_p, &me, RPL_STATSPLINE, 'P', listener->port,
893 listener->name,
894 listener->ref_count, buf,
895 listener->active ? "active" : "disabled");
896 else
897 sendto_one_numeric(source_p, &me, RPL_STATSPLINE, 'P', listener->port,
898 me.name, listener->ref_count, buf,
899 listener->active ? "active" : "disabled");
900 }
901 }
902
903 static void
904 stats_ports(struct Client *source_p, int parc, char *parv[])
905 {
906 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_P_oper_only)
907 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
908 else
909 show_ports(source_p);
910 }
911
912 static void
913 stats_tstats(struct Client *source_p, int parc, char *parv[])
914 {
915 dlink_node *node;
916 struct ServerStatistics tmp;
917 struct ServerStatistics *sp = &tmp;
918
919 memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
920
921 /*
922 * must use the += operator. is_sv is not the number of currently
923 * active server connections. Note the incrementation in
924 * s_bsd.c:close_connection.
925 */
926 sp->is_sv += dlink_list_length(&local_server_list);
927
928 DLINK_FOREACH(node, local_server_list.head)
929 {
930 const struct Client *target_p = node->data;
931
932 sp->is_sbs += target_p->connection->send.bytes;
933 sp->is_sbr += target_p->connection->recv.bytes;
934 sp->is_sti += CurrentTime - target_p->connection->firsttime;
935 }
936
937 sp->is_cl += dlink_list_length(&local_client_list);
938
939 DLINK_FOREACH(node, local_client_list.head)
940 {
941 const struct Client *target_p = node->data;
942
943 sp->is_cbs += target_p->connection->send.bytes;
944 sp->is_cbr += target_p->connection->recv.bytes;
945 sp->is_cti += CurrentTime - target_p->connection->firsttime;
946 }
947
948 sp->is_ni += dlink_list_length(&unknown_list);
949
950 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
951 "t :accepts %u refused %u",
952 sp->is_ac, sp->is_ref);
953 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
954 "t :unknown commands %u prefixes %u",
955 sp->is_unco, sp->is_unpf);
956 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
957 "t :nick collisions %u unknown closes %u",
958 sp->is_kill, sp->is_ni);
959 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
960 "t :wrong direction %u empty %u",
961 sp->is_wrdi, sp->is_empt);
962 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
963 "t :numerics seen %u",
964 sp->is_num);
965 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
966 "t :auth successes %u fails %u",
967 sp->is_asuc, sp->is_abad);
968 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
969 "t :Client Server");
970 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
971 "t :connected %u %u",
972 sp->is_cl, sp->is_sv);
973 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
974 "t :bytes sent %ju %ju",
975 sp->is_cbs, sp->is_sbs);
976 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
977 "t :bytes received %ju %ju",
978 sp->is_cbr, sp->is_sbr);
979 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
980 "t :time connected %ju %ju",
981 sp->is_cti, sp->is_sti);
982 }
983
984 static void
985 stats_uptime(struct Client *source_p, int parc, char *parv[])
986 {
987 if (!HasUMode(source_p, UMODE_OPER) && ConfigGeneral.stats_u_oper_only)
988 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
989 else
990 {
991 sendto_one_numeric(source_p, &me, RPL_STATSUPTIME,
992 time_dissect(CurrentTime - me.connection->since));
993 if (!ConfigServerHide.disable_remote_commands || HasUMode(source_p, UMODE_OPER))
994 sendto_one_numeric(source_p, &me, RPL_STATSCONN, Count.max_loc_con,
995 Count.max_loc_cli, Count.totalrestartcount);
996 }
997 }
998
999 static void
1000 stats_shared(struct Client *source_p, int parc, char *parv[])
1001 {
1002 report_shared(source_p);
1003 report_cluster(source_p);
1004 }
1005
1006 /* stats_servers()
1007 *
1008 * input - client pointer
1009 * output - none
1010 * side effects - client is shown lists of who connected servers
1011 */
1012 static void
1013 stats_servers(struct Client *source_p, int parc, char *parv[])
1014 {
1015 dlink_node *node;
1016
1017 DLINK_FOREACH(node, local_server_list.head)
1018 {
1019 const struct Client *target_p = node->data;
1020
1021 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1022 "v :%s (%s!%s@%s) Idle: %s",
1023 target_p->name,
1024 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1025 "*", "*", time_dissect(CurrentTime - target_p->connection->lasttime));
1026 }
1027
1028 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1029 "v :%u Server(s)",
1030 dlink_list_length(&local_server_list));
1031 }
1032
1033 static void
1034 stats_class(struct Client *source_p, int parc, char *parv[])
1035 {
1036 dlink_node *node;
1037
1038 DLINK_FOREACH(node, class_get_list()->head)
1039 {
1040 const struct ClassItem *class = node->data;
1041
1042 sendto_one_numeric(source_p, &me, RPL_STATSYLINE, 'Y',
1043 class->name, class->ping_freq,
1044 class->con_freq,
1045 class->max_total, class->max_sendq,
1046 class->max_recvq,
1047 class->ref_count,
1048 class->number_per_cidr, class->cidr_bitlen_ipv4,
1049 class->number_per_cidr, class->cidr_bitlen_ipv6,
1050 class->active ? "active" : "disabled");
1051 }
1052 }
1053
1054 static void
1055 stats_servlinks(struct Client *source_p, int parc, char *parv[])
1056 {
1057 dlink_node *node;
1058 uintmax_t sendB = 0, recvB = 0;
1059 uintmax_t uptime = 0;
1060
1061 if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1062 {
1063 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
1064 return;
1065 }
1066
1067 DLINK_FOREACH(node, local_server_list.head)
1068 {
1069 const struct Client *target_p = node->data;
1070
1071 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1072 if (!HasUMode(source_p, UMODE_OPER))
1073 continue;
1074
1075 sendB += target_p->connection->send.bytes;
1076 recvB += target_p->connection->recv.bytes;
1077
1078 /* ":%s 211 %s %s %u %u %ju %u %ju :%u %u %s" */
1079 sendto_one_numeric(source_p, &me, RPL_STATSLINKINFO,
1080 client_get_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1081 dbuf_length(&target_p->connection->buf_sendq),
1082 target_p->connection->send.messages,
1083 target_p->connection->send.bytes >> 10,
1084 target_p->connection->recv.messages,
1085 target_p->connection->recv.bytes >> 10,
1086 (unsigned int)(CurrentTime - target_p->connection->firsttime),
1087 (CurrentTime > target_p->connection->since) ? (unsigned int)(CurrentTime - target_p->connection->since) : 0,
1088 HasUMode(source_p, UMODE_OPER) ? get_capabilities(target_p) : "TS");
1089 }
1090
1091 sendB >>= 10;
1092 recvB >>= 10;
1093
1094 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :%u total server(s)",
1095 dlink_list_length(&local_server_list));
1096 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :Sent total: %7.2f %s",
1097 _GMKv(sendB), _GMKs(sendB));
1098 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT, "? :Recv total: %7.2f %s",
1099 _GMKv(recvB), _GMKs(recvB));
1100
1101 uptime = (CurrentTime - me.connection->since);
1102
1103 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1104 "? :Server send: %7.2f %s (%4.1f K/s)",
1105 _GMKv((me.connection->send.bytes >> 10)),
1106 _GMKs((me.connection->send.bytes >> 10)),
1107 (float)((float)((me.connection->send.bytes) >> 10) /
1108 (float)uptime));
1109 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG | SND_EXPLICIT,
1110 "? :Server recv: %7.2f %s (%4.1f K/s)",
1111 _GMKv((me.connection->recv.bytes >> 10)),
1112 _GMKs((me.connection->recv.bytes >> 10)),
1113 (float)((float)((me.connection->recv.bytes) >> 10) /
1114 (float)uptime));
1115 }
1116
1117 /* parse_stats_args()
1118 *
1119 * inputs - arg count
1120 * - args
1121 * - doall flag
1122 * - wild card or not
1123 * output - pointer to name to use
1124 * side effects -
1125 * common parse routine for m_stats args
1126 *
1127 */
1128 static const char *
1129 parse_stats_args(struct Client *source_p, int parc, char *parv[], int *doall, int *wilds)
1130 {
1131 if (parc > 2)
1132 {
1133 const char *name = parv[2];
1134
1135 if (!irccmp(name, ID_or_name(&me, source_p)))
1136 *doall = 2;
1137 else if (!match(name, ID_or_name(&me, source_p)))
1138 *doall = 1;
1139
1140 *wilds = has_wildcards(name);
1141
1142 return name;
1143 }
1144
1145 return NULL;
1146 }
1147
1148 static void
1149 stats_L_list(struct Client *source_p, const char *name, int doall, int wilds,
1150 dlink_list *list, const char statchar)
1151 {
1152 dlink_node *node;
1153
1154 /*
1155 * Send info about connections which match, or all if the
1156 * mask matches from.
1157 */
1158 DLINK_FOREACH(node, list->head)
1159 {
1160 const struct Client *target_p = node->data;
1161 enum addr_mask_type type = 0;
1162
1163 if (!doall && wilds && match(name, target_p->name))
1164 continue;
1165
1166 if (!(doall || wilds) && irccmp(name, target_p->name))
1167 continue;
1168
1169 if (IsUpper(statchar))
1170 type = SHOW_IP;
1171 else
1172 type = HIDE_IP;
1173
1174 if (IsServer(target_p) || IsConnecting(target_p) || IsHandshake(target_p))
1175 if (!HasUMode(source_p, UMODE_ADMIN))
1176 type = MASK_IP;
1177
1178 sendto_one_numeric(source_p, &me, RPL_STATSLINKINFO,
1179 client_get_name(target_p, type),
1180 dbuf_length(&target_p->connection->buf_sendq),
1181 target_p->connection->send.messages,
1182 target_p->connection->send.bytes >> 10,
1183 target_p->connection->recv.messages,
1184 target_p->connection->recv.bytes >> 10,
1185 (unsigned int)(CurrentTime - target_p->connection->firsttime),
1186 (CurrentTime > target_p->connection->since) ? (unsigned int)(CurrentTime - target_p->connection->since) : 0,
1187 IsServer(target_p) ? get_capabilities(target_p) : "-");
1188 }
1189 }
1190
1191 /*
1192 * stats_L
1193 *
1194 * inputs - pointer to client to report to
1195 * - doall flag
1196 * - wild card or not
1197 * output - NONE
1198 * side effects -
1199 */
1200 static void
1201 stats_L(struct Client *source_p, const char *name, int doall,
1202 int wilds, const char statchar)
1203 {
1204 stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1205 stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1206 stats_L_list(source_p, name, doall, wilds, &local_server_list, statchar);
1207 }
1208
1209 static void
1210 stats_ltrace(struct Client *source_p, int parc, char *parv[])
1211 {
1212 int doall = 0;
1213 int wilds = 0;
1214 const char *name = NULL;
1215
1216 if ((name = parse_stats_args(source_p, parc, parv, &doall, &wilds)))
1217 {
1218 const char statchar = *parv[1];
1219 stats_L(source_p, name, doall, wilds, statchar);
1220 }
1221 else
1222 sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "STATS");
1223 }
1224
1225 struct StatsStruct
1226 {
1227 const unsigned char letter;
1228 void (*handler)(struct Client *, int, char *[]);
1229 const unsigned int required_modes;
1230 };
1231
1232 static const struct StatsStruct *stats_map[256];
1233 static const struct StatsStruct stats_tab[] =
1234 {
1235 { 'a', stats_dns_servers, UMODE_ADMIN },
1236 { 'A', stats_dns_servers, UMODE_ADMIN },
1237 { 'c', stats_connect, UMODE_OPER },
1238 { 'C', stats_connect, UMODE_OPER },
1239 { 'd', stats_tdeny, UMODE_OPER },
1240 { 'D', stats_deny, UMODE_OPER },
1241 { 'e', stats_exempt, UMODE_OPER },
1242 { 'E', stats_events, UMODE_ADMIN },
1243 { 'f', fd_dump, UMODE_ADMIN },
1244 { 'F', fd_dump, UMODE_ADMIN },
1245 { 'h', stats_hubleaf, UMODE_OPER },
1246 { 'H', stats_hubleaf, UMODE_OPER },
1247 { 'i', stats_auth, 0 },
1248 { 'I', stats_auth, 0 },
1249 { 'k', stats_tklines, 0 },
1250 { 'K', stats_klines, 0 },
1251 { 'l', stats_ltrace, UMODE_OPER },
1252 { 'L', stats_ltrace, UMODE_OPER },
1253 { 'm', stats_messages, 0 },
1254 { 'M', stats_messages, 0 },
1255 { 'o', stats_operator, 0 },
1256 { 'O', stats_operator, 0 },
1257 { 'p', stats_operedup, 0 },
1258 { 'P', stats_ports, 0 },
1259 { 'q', stats_resv, UMODE_OPER },
1260 { 'Q', stats_resv, UMODE_OPER },
1261 { 's', stats_service, UMODE_OPER },
1262 { 'S', stats_service, UMODE_OPER },
1263 { 't', stats_tstats, UMODE_OPER },
1264 { 'T', motd_report, UMODE_OPER },
1265 { 'u', stats_uptime, 0 },
1266 { 'U', stats_shared, UMODE_OPER },
1267 { 'v', stats_servers, UMODE_OPER },
1268 { 'x', stats_gecos, UMODE_OPER },
1269 { 'X', stats_gecos, UMODE_OPER },
1270 { 'y', stats_class, UMODE_OPER },
1271 { 'Y', stats_class, UMODE_OPER },
1272 { 'z', stats_memory, UMODE_OPER },
1273 { '?', stats_servlinks, 0 },
1274 { '\0', NULL, 0 }
1275 };
1276
1277 static void
1278 do_stats(struct Client *source_p, int parc, char *parv[])
1279 {
1280 const unsigned char statchar = *parv[1];
1281 const struct StatsStruct *tab;
1282
1283 if (statchar == '\0')
1284 {
1285 sendto_one_numeric(source_p, &me, RPL_ENDOFSTATS, '*');
1286 return;
1287 }
1288
1289 if ((tab = stats_map[statchar]))
1290 {
1291 if (!tab->required_modes || HasUMode(source_p, tab->required_modes))
1292 tab->handler(source_p, parc, parv);
1293 else
1294 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
1295
1296 sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1297 "STATS %c requested by %s (%s@%s) [%s]",
1298 statchar, source_p->name, source_p->username,
1299 source_p->host, source_p->servptr->name);
1300 }
1301
1302 sendto_one_numeric(source_p, &me, RPL_ENDOFSTATS, statchar);
1303 }
1304
1305 /*
1306 * m_stats()
1307 * parv[0] = command
1308 * parv[1] = stat letter/command
1309 * parv[2] = (if present) server/mask in stats L
1310 */
1311 static int
1312 m_stats(struct Client *source_p, int parc, char *parv[])
1313 {
1314 static uintmax_t last_used = 0;
1315
1316 /* Check the user is actually allowed to do /stats, and isn't flooding */
1317 if ((last_used + ConfigGeneral.pace_wait) > CurrentTime)
1318 {
1319 sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "STATS");
1320 return 0;
1321 }
1322
1323 last_used = CurrentTime;
1324
1325 /* Is the stats meant for us? */
1326 if (!ConfigServerHide.disable_remote_commands)
1327 if (server_hunt(source_p, ":%s STATS %s :%s", 2, parc, parv)->ret != HUNTED_ISME)
1328 return 0;
1329
1330 do_stats(source_p, parc, parv);
1331 return 0;
1332 }
1333
1334 /*
1335 * ms_stats()
1336 * parv[0] = command
1337 * parv[1] = stat letter/command
1338 * parv[2] = (if present) server/mask in stats L, or target
1339 */
1340 static int
1341 ms_stats(struct Client *source_p, int parc, char *parv[])
1342 {
1343 if (server_hunt(source_p, ":%s STATS %s :%s", 2, parc, parv)->ret != HUNTED_ISME)
1344 return 0;
1345
1346 do_stats(source_p, parc, parv);
1347 return 0;
1348 }
1349
1350 static void
1351 stats_init(void)
1352 {
1353 for (const struct StatsStruct *tab = stats_tab; tab->letter; ++tab)
1354 stats_map[tab->letter] = tab;
1355 }
1356
1357 static struct Message stats_msgtab =
1358 {
1359 .cmd = "STATS",
1360 .args_min = 2,
1361 .args_max = MAXPARA,
1362 .handlers[UNREGISTERED_HANDLER] = m_unregistered,
1363 .handlers[CLIENT_HANDLER] = m_stats,
1364 .handlers[SERVER_HANDLER] = ms_stats,
1365 .handlers[ENCAP_HANDLER] = m_ignore,
1366 .handlers[OPER_HANDLER] = ms_stats
1367 };
1368
1369 static void
1370 module_init(void)
1371 {
1372 stats_init();
1373 mod_add_cmd(&stats_msgtab);
1374 }
1375
1376 static void
1377 module_exit(void)
1378 {
1379 mod_del_cmd(&stats_msgtab);
1380 }
1381
1382 struct module module_entry =
1383 {
1384 .version = "$Revision$",
1385 .modinit = module_init,
1386 .modexit = module_exit,
1387 };

Properties

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