ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
Revision: 7458
Committed: Sat Mar 12 12:51:54 2016 UTC (10 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 46488 byte(s)
Log Message:
- m_stats.c:stats_events(): use proper conversion specifier

File Contents

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

Properties

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