ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/newio/modules/m_stats.c
Revision: 1927
Committed: Tue Apr 30 17:46:40 2013 UTC (10 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/m_stats.c
File size: 54260 byte(s)
Log Message:
- Move report_resv() to m_stats.c

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_stats.c: Sends the user statistics or config information.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h" /* dlink_node/dlink_list */
27 #include "client.h" /* Client */
28 #include "irc_string.h"
29 #include "ircd.h" /* me */
30 #include "listener.h" /* show_ports */
31 #include "s_gline.h"
32 #include "conf.h"
33 #include "conf_class.h"
34 #include "hostmask.h"
35 #include "numeric.h" /* ERR_xxx */
36 #include "send.h" /* sendto_one */
37 #include "fdlist.h" /* PF and friends */
38 #include "s_bsd.h" /* highest_fd */
39 #include "s_misc.h" /* serv_info */
40 #include "s_serv.h" /* hunt_server */
41 #include "s_user.h" /* show_opers */
42 #include "event.h" /* events */
43 #include "dbuf.h"
44 #include "hook.h"
45 #include "parse.h"
46 #include "modules.h"
47 #include "resv.h" /* report_resv */
48 #include "whowas.h"
49 #include "watch.h"
50 #include "irc_res.h"
51
52
53 const char *from, *to;
54
55 static const struct shared_flags
56 {
57 const unsigned int type;
58 const unsigned char letter;
59 } flag_table[] = {
60 { SHARED_KLINE, 'K' },
61 { SHARED_UNKLINE, 'U' },
62 { SHARED_XLINE, 'X' },
63 { SHARED_UNXLINE, 'Y' },
64 { SHARED_RESV, 'Q' },
65 { SHARED_UNRESV, 'R' },
66 { SHARED_LOCOPS, 'L' },
67 { SHARED_DLINE, 'D' },
68 { SHARED_UNDLINE, 'E' },
69 { 0, '\0' }
70 };
71
72 /*
73 * inputs - pointer to client requesting confitem report
74 * - ConfType to report
75 * output - none
76 * side effects -
77 */
78 static void
79 report_confitem_types(struct Client *source_p, enum maskitem_type type)
80 {
81 dlink_node *ptr = NULL, *dptr = NULL;
82 struct MaskItem *conf = NULL;
83 const struct ClassItem *class = NULL;
84 const struct shared_flags *shared = NULL;
85 char buf[12];
86 char *p = NULL;
87
88 switch (type)
89 {
90 case CONF_XLINE:
91 DLINK_FOREACH(ptr, xconf_items.head)
92 {
93 conf = ptr->data;
94
95 sendto_one(source_p, form_str(RPL_STATSXLINE),
96 me.name, source_p->name,
97 conf->until ? 'x': 'X', conf->count,
98 conf->name, conf->reason);
99 }
100 break;
101
102 case CONF_ULINE:
103 shared = flag_table;
104 DLINK_FOREACH(ptr, uconf_items.head)
105 {
106 conf = ptr->data;
107
108 p = buf;
109
110 *p++ = 'c';
111 for (; shared->type; ++shared)
112 if (shared->type & conf->flags)
113 *p++ = shared->letter;
114 else
115 *p++ = ToLower(shared->letter);
116
117 sendto_one(source_p, form_str(RPL_STATSULINE),
118 me.name, source_p->name, conf->name,
119 conf->user?conf->user: "*",
120 conf->host?conf->host: "*", buf);
121 }
122
123 shared = flag_table;
124 DLINK_FOREACH(ptr, cluster_items.head)
125 {
126 conf = ptr->data;
127
128 p = buf;
129
130 *p++ = 'C';
131 for (; shared->type; ++shared)
132 if (shared->type & conf->flags)
133 *p++ = shared->letter;
134 else
135 *p++ = ToLower(shared->letter);
136
137 sendto_one(source_p, form_str(RPL_STATSULINE),
138 me.name, source_p->name, conf->name,
139 "*", "*", buf);
140 }
141
142 break;
143
144 case CONF_OPER:
145 DLINK_FOREACH(ptr, oconf_items.head)
146 {
147 conf = ptr->data;
148
149 /* Don't allow non opers to see oper privs */
150 if (HasUMode(source_p, UMODE_OPER))
151 sendto_one(source_p, form_str(RPL_STATSOLINE),
152 me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
153 conf->name, oper_privs_as_string(conf->port),
154 conf->class ? conf->class->name : "<default>");
155 else
156 sendto_one(source_p, form_str(RPL_STATSOLINE),
157 me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
158 conf->name, "0",
159 conf->class ? conf->class->name : "<default>");
160 }
161 break;
162
163 case CONF_CLASS:
164 DLINK_FOREACH(ptr, class_get_list()->head)
165 {
166 class = ptr->data;
167 sendto_one(source_p, form_str(RPL_STATSYLINE),
168 me.name, source_p->name, 'Y',
169 class->name, class->ping_freq,
170 class->con_freq,
171 class->max_total, class->max_sendq,
172 class->max_recvq,
173 class->ref_count,
174 class->number_per_cidr, class->cidr_bitlen_ipv4,
175 class->number_per_cidr, class->cidr_bitlen_ipv6,
176 class->active ? "active" : "disabled");
177 }
178 break;
179
180 case CONF_SERVICE:
181 DLINK_FOREACH(ptr, service_items.head)
182 {
183 conf = ptr->data;
184 sendto_one(source_p, form_str(RPL_STATSSERVICE),
185 me.name, source_p->name, 'S', "*", conf->name, 0, 0);
186 }
187 break;
188
189 case CONF_SERVER:
190 DLINK_FOREACH(ptr, server_items.head)
191 {
192 p = buf;
193 conf = ptr->data;
194
195 buf[0] = '\0';
196
197 if (IsConfAllowAutoConn(conf))
198 *p++ = 'A';
199 if (IsConfSSL(conf))
200 *p++ = 'S';
201 if (buf[0] == '\0')
202 *p++ = '*';
203
204 *p = '\0';
205
206 /*
207 * Allow admins to see actual ips unless hide_server_ips is enabled
208 */
209 if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
210 sendto_one(source_p, form_str(RPL_STATSCLINE),
211 me.name, source_p->name, 'C', conf->host,
212 buf, conf->name, conf->port,
213 conf->class ? conf->class->name : "<default>");
214 else
215 sendto_one(source_p, form_str(RPL_STATSCLINE),
216 me.name, source_p->name, 'C',
217 "*@127.0.0.1", buf, conf->name, conf->port,
218 conf->class ? conf->class->name : "<default>");
219 }
220 break;
221
222 case CONF_HUB:
223 DLINK_FOREACH(ptr, server_items.head)
224 {
225 conf = ptr->data;
226
227 DLINK_FOREACH(dptr, conf->hub_list.head)
228 sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
229 source_p->name, 'H', dptr->data, conf->name, 0, "*");
230 }
231
232 DLINK_FOREACH(ptr, server_items.head)
233 {
234 conf = ptr->data;
235
236 DLINK_FOREACH(dptr, conf->leaf_list.head)
237 sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
238 source_p->name, 'L', dptr->data, conf->name, 0, "*");
239 }
240
241 break;
242
243 default:
244 break;
245 }
246 }
247
248 /* report_resv()
249 *
250 * inputs - pointer to client pointer to report to.
251 * output - NONE
252 * side effects - report all resvs to client.
253 */
254 static void
255 report_resv(struct Client *source_p)
256 {
257 dlink_node *ptr = NULL;
258 struct MaskItem *conf = NULL;
259
260 DLINK_FOREACH(ptr, resv_channel_list.head)
261 {
262 conf = ptr->data;
263 sendto_one(source_p, form_str(RPL_STATSQLINE),
264 me.name, source_p->name,
265 conf->until ? 'q' : 'Q', conf->count,
266 conf->name, conf->reason);
267 }
268
269 DLINK_FOREACH(ptr, nresv_items.head)
270 {
271 conf = ptr->data;
272 sendto_one(source_p, form_str(RPL_STATSQLINE),
273 me.name, source_p->name,
274 conf->until ? 'q' : 'Q', conf->count,
275 conf->name, conf->reason);
276 }
277 }
278
279 /*
280 * This is part of the STATS replies. There is no offical numeric for this
281 * since this isnt an official command, in much the same way as HASH isnt.
282 * It is also possible that some systems wont support this call or have
283 * different field names for "struct rusage".
284 * -avalon
285 */
286 static void
287 stats_usage(struct Client *source_p, int parc, char *parv[])
288 {
289 struct rusage rus;
290 time_t secs;
291 time_t rup;
292 #ifdef hz
293 # define hzz hz
294 #else
295 # ifdef HZ
296 # define hzz HZ
297 # else
298 int hzz = 1;
299 # endif
300 #endif
301
302 if (getrusage(RUSAGE_SELF, &rus) == -1)
303 {
304 sendto_one(source_p, ":%s NOTICE %s :Getruseage error: %s",
305 me.name, source_p->name, strerror(errno));
306 return;
307 }
308
309 secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
310
311 if (secs == 0)
312 secs = 1;
313
314 rup = (CurrentTime - me.localClient->since) * hzz;
315
316 if (rup == 0)
317 rup = 1;
318
319 sendto_one(source_p,
320 ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
321 me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
322 (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
323 (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
324 sendto_one(source_p, ":%s %d %s R :RSS %ld ShMem %ld Data %ld Stack %ld",
325 me.name, RPL_STATSDEBUG, source_p->name, rus.ru_maxrss,
326 (rus.ru_ixrss / rup), (rus.ru_idrss / rup),
327 (rus.ru_isrss / rup));
328 sendto_one(source_p, ":%s %d %s R :Swaps %d Reclaims %d Faults %d",
329 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nswap,
330 (int)rus.ru_minflt, (int)rus.ru_majflt);
331 sendto_one(source_p, ":%s %d %s R :Block in %d out %d",
332 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_inblock,
333 (int)rus.ru_oublock);
334 sendto_one(source_p, ":%s %d %s R :Msg Rcv %d Send %d",
335 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_msgrcv,
336 (int)rus.ru_msgsnd);
337 sendto_one(source_p, ":%s %d %s R :Signals %d Context Vol. %d Invol %d",
338 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nsignals,
339 (int)rus.ru_nvcsw, (int)rus.ru_nivcsw);
340 }
341
342 static void
343 stats_memory(struct Client *source_p, int parc, char *parv[])
344 {
345 const dlink_node *gptr = NULL;
346 const dlink_node *dlink = NULL;
347
348 unsigned int local_client_conf_count = 0; /* local client conf links */
349 unsigned int users_counted = 0; /* user structs */
350
351 unsigned int channel_members = 0;
352 unsigned int channel_invites = 0;
353 unsigned int channel_bans = 0;
354 unsigned int channel_except = 0;
355 unsigned int channel_invex = 0;
356
357 unsigned int wwu = 0; /* whowas users */
358 unsigned int class_count = 0; /* classes */
359 unsigned int aways_counted = 0;
360 unsigned int number_ips_stored; /* number of ip addresses hashed */
361
362 uint64_t channel_memory = 0;
363 uint64_t channel_ban_memory = 0;
364 uint64_t channel_except_memory = 0;
365 uint64_t channel_invex_memory = 0;
366
367 unsigned int safelist_count = 0;
368 uint64_t safelist_memory = 0;
369
370 uint64_t wwm = 0; /* whowas array memory used */
371 uint64_t conf_memory = 0; /* memory used by conf lines */
372 uint64_t mem_ips_stored; /* memory used by ip address hash */
373
374 uint64_t total_channel_memory = 0;
375 uint64_t totww = 0;
376
377 unsigned int local_client_count = 0;
378 unsigned int remote_client_count = 0;
379
380 uint64_t local_client_memory_used = 0;
381 uint64_t remote_client_memory_used = 0;
382
383 uint64_t total_memory = 0;
384 unsigned int topic_count = 0;
385
386 unsigned int watch_list_headers = 0; /* watchlist headers */
387 unsigned int watch_list_entries = 0; /* watchlist entries */
388 uint64_t watch_list_memory = 0; /* watchlist memory used */
389
390
391 DLINK_FOREACH(gptr, global_client_list.head)
392 {
393 struct Client *target_p = gptr->data;
394
395 if (MyConnect(target_p))
396 {
397 ++local_client_count;
398 local_client_conf_count += dlink_list_length(&target_p->localClient->confs);
399 watch_list_entries += dlink_list_length(&target_p->localClient->watches);
400 }
401 else
402 ++remote_client_count;
403
404 if (IsClient(target_p))
405 {
406 ++users_counted;
407
408 if (target_p->away[0])
409 ++aways_counted;
410 }
411 }
412
413 /* Count up all channels, ban lists, except lists, Invex lists */
414 channel_memory = dlink_list_length(&global_channel_list) *
415 sizeof(struct Channel);
416 DLINK_FOREACH(gptr, global_channel_list.head)
417 {
418 const struct Ban *actualBan;
419 const struct Channel *chptr = gptr->data;
420
421 channel_members += dlink_list_length(&chptr->members);
422 channel_invites += dlink_list_length(&chptr->invites);
423
424 if (chptr->topic[0])
425 ++topic_count;
426
427 channel_bans += dlink_list_length(&chptr->banlist);
428 channel_ban_memory += dlink_list_length(&chptr->banlist) * sizeof(struct Ban);
429
430 DLINK_FOREACH(dlink, chptr->banlist.head)
431 {
432 actualBan = dlink->data;
433 assert(actualBan->who);
434
435 channel_ban_memory += actualBan->len + 1;
436 channel_ban_memory += strlen(actualBan->who) + 1;
437 }
438
439 channel_except += dlink_list_length(&chptr->exceptlist);
440 channel_except_memory += dlink_list_length(&chptr->exceptlist) * sizeof(struct Ban);
441
442 DLINK_FOREACH(dlink, chptr->exceptlist.head)
443 {
444 actualBan = dlink->data;
445 assert(actualBan->who);
446
447 channel_except_memory += actualBan->len + 1;
448 channel_except_memory += strlen(actualBan->who) + 1;
449 }
450
451 channel_invex += dlink_list_length(&chptr->invexlist);
452 channel_invex_memory += dlink_list_length(&chptr->invexlist) * sizeof(struct Ban);
453
454 DLINK_FOREACH(dlink, chptr->invexlist.head)
455 {
456 actualBan = dlink->data;
457 assert(actualBan->who);
458
459 channel_invex_memory += actualBan->len + 1;
460 channel_invex_memory += strlen(actualBan->who) + 1;
461 }
462 }
463
464 if ((safelist_count = dlink_list_length(&listing_client_list)))
465 {
466 safelist_memory = safelist_count * sizeof(struct ListTask);
467 DLINK_FOREACH(gptr, listing_client_list.head)
468 {
469 const struct Client *acptr = gptr->data;
470
471 DLINK_FOREACH(dlink, acptr->localClient->list_task->show_mask.head)
472 safelist_memory += strlen(dlink->data);
473
474 DLINK_FOREACH(dlink, acptr->localClient->list_task->hide_mask.head)
475 safelist_memory += strlen(dlink->data);
476 }
477 }
478
479 #if 0
480 /* XXX THIS has to be fixed !!!! -db */
481 /* count up all config items */
482 DLINK_FOREACH(dlink, ConfigItemList.head)
483 {
484 aconf = dlink->data;
485 conf_memory += aconf->host ? strlen(aconf->host)+1 : 0;
486 conf_memory += aconf->passwd ? strlen(aconf->passwd)+1 : 0;
487 conf_memory += aconf->name ? strlen(aconf->name)+1 : 0;
488 conf_memory += sizeof(struct AccessItem);
489 }
490 #endif
491 /* count up all classes */
492 class_count = dlink_list_length(class_get_list());
493
494 count_whowas_memory(&wwu, &wwm);
495 watch_count_memory(&watch_list_headers, &watch_list_memory);
496
497 sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%llu) entries %d(%u)",
498 me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
499 watch_list_memory, watch_list_entries,
500 watch_list_entries * sizeof(dlink_node) * 2);
501
502 sendto_one(source_p, ":%s %d %s z :Clients %u(%u)",
503 me.name, RPL_STATSDEBUG, source_p->name, users_counted,
504 (users_counted * sizeof(struct Client)));
505
506 sendto_one(source_p, ":%s %d %s z :User aways %u",
507 me.name, RPL_STATSDEBUG, source_p->name,
508 aways_counted);
509
510 sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
511 me.name, RPL_STATSDEBUG, source_p->name,
512 local_client_conf_count,
513 (unsigned long long)(local_client_conf_count * sizeof(dlink_node)));
514
515 sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
516 me.name, RPL_STATSDEBUG, source_p->name,
517 dlink_list_length(&resv_channel_list),
518 dlink_list_length(&resv_channel_list) * sizeof(struct MaskItem),
519 dlink_list_length(&nresv_items),
520 dlink_list_length(&nresv_items) * sizeof(struct MaskItem));
521
522 sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
523 me.name, RPL_STATSDEBUG, source_p->name,
524 class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
525
526 sendto_one(source_p, ":%s %d %s z :Channels %u(%llu) Topics %u(%u)",
527 me.name, RPL_STATSDEBUG, source_p->name,
528 dlink_list_length(&global_channel_list),
529 channel_memory, topic_count, topic_count *
530 (TOPICLEN + 1 + USERHOST_REPLYLEN));
531
532 sendto_one(source_p, ":%s %d %s z :Bans %u(%llu)",
533 me.name, RPL_STATSDEBUG, source_p->name,
534 channel_bans, channel_ban_memory);
535
536 sendto_one(source_p, ":%s %d %s z :Exceptions %u(%llu)",
537 me.name, RPL_STATSDEBUG, source_p->name,
538 channel_except, channel_except_memory);
539
540 sendto_one(source_p, ":%s %d %s z :Invex %u(%llu)",
541 me.name, RPL_STATSDEBUG, source_p->name,
542 channel_invex, channel_invex_memory);
543
544 sendto_one(source_p, ":%s %d %s z :Channel members %u(%llu) invites %u(%llu)",
545 me.name, RPL_STATSDEBUG, source_p->name, channel_members,
546 (unsigned long long)(channel_members * sizeof(struct Membership)),
547 channel_invites, (unsigned long long)channel_invites *
548 sizeof(dlink_node) * 2);
549
550 total_channel_memory = channel_memory + channel_ban_memory +
551 channel_members * sizeof(struct Membership) +
552 (channel_invites * sizeof(dlink_node)*2);
553
554 sendto_one(source_p, ":%s %d %s z :Safelist %u(%llu)",
555 me.name, RPL_STATSDEBUG, source_p->name,
556 safelist_count, safelist_memory);
557
558 sendto_one(source_p, ":%s %d %s z :Whowas users %u(%llu)",
559 me.name, RPL_STATSDEBUG, source_p->name,
560 wwu, (unsigned long long)(wwu * sizeof(struct Client)));
561
562 sendto_one(source_p, ":%s %d %s z :Whowas array %u(%llu)",
563 me.name, RPL_STATSDEBUG, source_p->name,
564 NICKNAMEHISTORYLENGTH, wwm);
565
566 totww = wwu * sizeof(struct Client) + wwm;
567
568 count_ip_hash(&number_ips_stored,&mem_ips_stored);
569 sendto_one(source_p, ":%s %d %s z :iphash %u(%llu)",
570 me.name, RPL_STATSDEBUG, source_p->name,
571 number_ips_stored, mem_ips_stored);
572
573 total_memory = totww + total_channel_memory + conf_memory + class_count *
574 sizeof(struct ClassItem);
575 sendto_one(source_p, ":%s %d %s z :Total: whowas %llu channel %llu conf %llu",
576 me.name, RPL_STATSDEBUG, source_p->name, totww,
577 total_channel_memory, conf_memory);
578
579 local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
580 total_memory += local_client_memory_used;
581 sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %u(%llu)",
582 me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
583 local_client_memory_used);
584
585 remote_client_memory_used = remote_client_count * sizeof(struct Client);
586 total_memory += remote_client_memory_used;
587 sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %u(%llu)",
588 me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
589 remote_client_memory_used);
590
591 sendto_one(source_p,
592 ":%s %d %s z :TOTAL: %llu",
593 me.name, RPL_STATSDEBUG, source_p->name,
594 total_memory);
595 }
596
597 static void
598 stats_dns_servers(struct Client *source_p)
599 {
600 report_dns_servers(source_p);
601 }
602
603 static void
604 stats_connect(struct Client *source_p, int parc, char *parv[])
605 {
606 report_confitem_types(source_p, CONF_SERVER);
607 }
608
609 /* stats_deny()
610 *
611 * input - client to report to
612 * output - none
613 * side effects - client is given dline list.
614 */
615 static void
616 stats_deny(struct Client *source_p, int parc, char *parv[])
617 {
618 struct MaskItem *conf;
619 dlink_node *ptr = NULL;
620 unsigned int i = 0;
621
622
623 for (i = 0; i < ATABLE_SIZE; ++i)
624 {
625 DLINK_FOREACH(ptr, atable[i].head)
626 {
627 struct AddressRec *arec = ptr->data;
628
629 if (arec->type != CONF_DLINE)
630 continue;
631
632 conf = arec->conf;
633
634 /* dont report a tdline as a dline */
635 if (conf->until)
636 continue;
637
638 sendto_one(source_p, form_str(RPL_STATSDLINE),
639 from, to, 'D', conf->host, conf->reason);
640 }
641 }
642 }
643
644 /* stats_tdeny()
645 *
646 * input - client to report to
647 * output - none
648 * side effects - client is given dline list.
649 */
650 static void
651 stats_tdeny(struct Client *source_p, int parc, char *parv[])
652 {
653 struct MaskItem *conf = NULL;
654 dlink_node *ptr = NULL;
655 unsigned int i = 0;
656
657
658 for (i = 0; i < ATABLE_SIZE; ++i)
659 {
660 DLINK_FOREACH(ptr, atable[i].head)
661 {
662 struct AddressRec *arec = ptr->data;
663
664 if (arec->type != CONF_DLINE)
665 continue;
666
667 conf = arec->conf;
668
669 /* dont report a permanent dline as a tdline */
670 if (!conf->until)
671 continue;
672
673 sendto_one(source_p, form_str(RPL_STATSDLINE),
674 from, to, 'd', conf->host, conf->reason);
675 }
676 }
677 }
678
679 /* stats_exempt()
680 *
681 * input - client to report to
682 * output - none
683 * side effects - client is given list of exempt blocks
684 */
685 static void
686 stats_exempt(struct Client *source_p, int parc, char *parv[])
687 {
688 struct MaskItem *conf;
689 dlink_node *ptr = NULL;
690 unsigned int i = 0;
691
692 if (ConfigFileEntry.stats_e_disabled)
693 {
694 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
695 from, to);
696 return;
697 }
698
699
700 for (i = 0; i < ATABLE_SIZE; ++i)
701 {
702 DLINK_FOREACH(ptr, atable[i].head)
703 {
704 struct AddressRec *arec = ptr->data;
705
706 if (arec->type != CONF_EXEMPT)
707 continue;
708
709 conf = arec->conf;
710
711 sendto_one(source_p, form_str(RPL_STATSDLINE), from, to, 'e',
712 conf->host, "");
713 }
714 }
715 }
716
717 static void
718 stats_events(struct Client *source_p, int parc, char *parv[])
719 {
720 show_events(source_p);
721 }
722
723 /* stats_pending_glines()
724 *
725 * input - client pointer
726 * output - none
727 * side effects - client is shown list of pending glines
728 */
729 static void
730 stats_pending_glines(struct Client *source_p, int parc, char *parv[])
731 {
732 const dlink_node *dn_ptr = NULL;
733 const struct gline_pending *glp_ptr = NULL;
734 char timebuffer[MAX_DATE_STRING] = { '\0' };
735 struct tm *tmptr = NULL;
736
737 if (!ConfigFileEntry.glines)
738 {
739 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
740 from, to);
741 return;
742 }
743
744 if (dlink_list_length(&pending_glines[GLINE_PENDING_ADD_TYPE]) > 0)
745 sendto_one(source_p, ":%s NOTICE %s :Pending G-lines",
746 from, to);
747
748 DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_ADD_TYPE].head)
749 {
750 glp_ptr = dn_ptr->data;
751 tmptr = localtime(&glp_ptr->vote_1.time_request);
752 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
753
754 sendto_one(source_p,
755 ":%s NOTICE %s :1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
756 from, to, glp_ptr->vote_1.oper_nick,
757 glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
758 glp_ptr->vote_1.oper_server, timebuffer,
759 glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
760
761 if (glp_ptr->vote_2.oper_nick[0] != '\0')
762 {
763 tmptr = localtime(&glp_ptr->vote_2.time_request);
764 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
765 sendto_one(source_p,
766 ":%s NOTICE %s :2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
767 from, to, glp_ptr->vote_2.oper_nick,
768 glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
769 glp_ptr->vote_2.oper_server, timebuffer,
770 glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
771 }
772 }
773
774 sendto_one(source_p, ":%s NOTICE %s :End of Pending G-lines",
775 from, to);
776
777 if (dlink_list_length(&pending_glines[GLINE_PENDING_DEL_TYPE]) > 0)
778 sendto_one(source_p, ":%s NOTICE %s :Pending UNG-lines",
779 from, to);
780
781 DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_DEL_TYPE].head)
782 {
783 glp_ptr = dn_ptr->data;
784 tmptr = localtime(&glp_ptr->vote_1.time_request);
785 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
786
787 sendto_one(source_p,
788 ":%s NOTICE %s :1) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
789 from, to, glp_ptr->vote_1.oper_nick,
790 glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
791 glp_ptr->vote_1.oper_server, timebuffer,
792 glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
793
794 if (glp_ptr->vote_2.oper_nick[0] != '\0')
795 {
796 tmptr = localtime(&glp_ptr->vote_2.time_request);
797 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
798 sendto_one(source_p,
799 ":%s NOTICE %s :2) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
800 from, to, glp_ptr->vote_2.oper_nick,
801 glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
802 glp_ptr->vote_2.oper_server, timebuffer,
803 glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
804
805 }
806 }
807
808 sendto_one(source_p, ":%s NOTICE %s :End of Pending UNG-lines",
809 from, to);
810 }
811
812 /* stats_glines()
813 *
814 * input - client pointer
815 * output - none
816 * side effects - client is shown list of glines
817 */
818 static void
819 stats_glines(struct Client *source_p, int parc, char *parv[])
820 {
821 dlink_node *ptr = NULL;
822 unsigned int i = 0;
823
824 if (!ConfigFileEntry.glines)
825 {
826 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
827 from, to);
828 return;
829 }
830
831 for (i = 0; i < ATABLE_SIZE; ++i)
832 {
833 DLINK_FOREACH(ptr, atable[i].head)
834 {
835 const struct AddressRec *arec = ptr->data;
836
837 if (arec->type == CONF_GLINE)
838 {
839 const struct MaskItem *conf = arec->conf;
840
841 sendto_one(source_p, form_str(RPL_STATSKLINE),
842 from, to, 'G',
843 conf->host ? conf->host : "*",
844 conf->user ? conf->user : "*",
845 conf->reason ? conf->reason : CONF_NOREASON);
846 }
847 }
848 }
849 }
850
851 static void
852 stats_hubleaf(struct Client *source_p, int parc, char *parv[])
853 {
854 report_confitem_types(source_p, CONF_HUB);
855 }
856
857 /*
858 * show_iline_prefix()
859 *
860 * inputs - pointer to struct Client requesting output
861 * - pointer to struct MaskItem
862 * - name to which iline prefix will be prefixed to
863 * output - pointer to static string with prefixes listed in ascii form
864 * side effects - NONE
865 */
866 static const char *
867 show_iline_prefix(const struct Client *sptr, const struct MaskItem *conf)
868 {
869 static char prefix_of_host[USERLEN + 15];
870 char *prefix_ptr = prefix_of_host;
871
872 if (IsConfWebIRC(conf))
873 *prefix_ptr++ = '<';
874 if (IsNoTilde(conf))
875 *prefix_ptr++ = '-';
876 if (IsLimitIp(conf))
877 *prefix_ptr++ = '!';
878 if (IsNeedIdentd(conf))
879 *prefix_ptr++ = '+';
880 if (!IsNeedPassword(conf))
881 *prefix_ptr++ = '&';
882 if (IsConfExemptResv(conf))
883 *prefix_ptr++ = '$';
884 if (IsNoMatchIp(conf))
885 *prefix_ptr++ = '%';
886 if (IsConfDoSpoofIp(conf))
887 *prefix_ptr++ = '=';
888 if (MyOper(sptr) && IsConfExemptKline(conf))
889 *prefix_ptr++ = '^';
890 if (MyOper(sptr) && IsConfExemptGline(conf))
891 *prefix_ptr++ = '_';
892 if (MyOper(sptr) && IsConfExemptLimits(conf))
893 *prefix_ptr++ = '>';
894 if (IsConfCanFlood(conf))
895 *prefix_ptr++ = '|';
896
897 strlcpy(prefix_ptr, conf->user, USERLEN+1);
898
899 return prefix_of_host;
900 }
901
902 static void
903 report_auth(struct Client *client_p, int parc, char *parv[])
904 {
905 struct MaskItem *conf = NULL;
906 dlink_node *ptr = NULL;
907 unsigned int i;
908
909
910 for (i = 0; i < ATABLE_SIZE; ++i)
911 {
912 DLINK_FOREACH(ptr, atable[i].head)
913 {
914 struct AddressRec *arec = ptr->data;
915
916 if (arec->type != CONF_CLIENT)
917 continue;
918
919 conf = arec->conf;
920
921 if (!MyOper(client_p) && IsConfDoSpoofIp(conf))
922 continue;
923
924 /* We are doing a partial list, based on what matches the u@h of the
925 * sender, so prepare the strings for comparing --fl_
926 */
927 if (ConfigFileEntry.hide_spoof_ips)
928 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
929 client_p->name, 'I',
930 conf->name == NULL ? "*" : conf->name,
931 show_iline_prefix(client_p, conf),
932 IsConfDoSpoofIp(conf) ? "255.255.255.255" :
933 conf->host, conf->port,
934 conf->class ? conf->class->name : "<default>");
935
936 else
937 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
938 client_p->name, 'I',
939 conf->name == NULL ? "*" : conf->name,
940 show_iline_prefix(client_p, conf),
941 conf->host, conf->port,
942 conf->class ? conf->class->name : "<default>");
943 }
944 }
945 }
946
947 static void
948 stats_auth(struct Client *source_p, int parc, char *parv[])
949 {
950 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
951 if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
952 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
953 from, to);
954
955 /* If unopered, Only return matching auth blocks */
956 else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
957 {
958 struct MaskItem *conf;
959
960 if (MyConnect(source_p))
961 conf = find_conf_by_address(source_p->host,
962 &source_p->localClient->ip,
963 CONF_CLIENT,
964 source_p->localClient->aftype,
965 source_p->username,
966 source_p->localClient->passwd, 1);
967 else
968 conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
969 0, source_p->username, NULL, 1);
970
971 if (conf == NULL)
972 return;
973
974 sendto_one(source_p, form_str(RPL_STATSILINE), from,
975 to, 'I',
976 "*", show_iline_prefix(source_p, conf),
977 conf->host, conf->port,
978 conf->class ? conf->class->name : "<default>");
979 }
980 /* They are opered, or allowed to see all auth blocks */
981 else
982 report_auth(source_p, 0, NULL);
983 }
984
985 /* report_Klines()
986 * Inputs: Client to report to,
987 * type(==0 for perm, !=0 for temporary)
988 * mask
989 * Output: None
990 * Side effects: Reports configured K(or k)-lines to client_p.
991 */
992 static void
993 report_Klines(struct Client *client_p, int tkline)
994 {
995 struct MaskItem *conf = NULL;
996 unsigned int i = 0;
997 char c = '\0';
998 dlink_node *ptr = NULL;
999
1000 if (tkline)
1001 c = 'k';
1002 else
1003 c = 'K';
1004
1005 for (i = 0; i < ATABLE_SIZE; ++i)
1006 {
1007 DLINK_FOREACH(ptr, atable[i].head)
1008 {
1009 struct AddressRec *arec = ptr->data;
1010
1011 if (arec->type != CONF_KLINE)
1012 continue;
1013
1014 conf = arec->conf;
1015
1016 if ((!tkline && conf->until) ||
1017 (tkline && !conf->until))
1018 continue;
1019
1020 if (HasUMode(client_p, UMODE_OPER))
1021 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1022 client_p->name, c, conf->host, conf->user,
1023 conf->reason);
1024 else
1025 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1026 client_p->name, c, conf->host, conf->user,
1027 conf->reason);
1028 }
1029 }
1030 }
1031
1032 static void
1033 stats_tklines(struct Client *source_p, int parc, char *parv[])
1034 {
1035 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1036 if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1037 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1038 from, to);
1039
1040 /* If unopered, Only return matching klines */
1041 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1042 {
1043 struct MaskItem *conf = NULL;
1044
1045 if (MyConnect(source_p))
1046 conf = find_conf_by_address(source_p->host,
1047 &source_p->localClient->ip,
1048 CONF_KLINE,
1049 source_p->localClient->aftype,
1050 source_p->username, NULL, 1);
1051 else
1052 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1053 0, source_p->username, NULL, 1);
1054
1055 if (!conf)
1056 return;
1057
1058 /* dont report a permanent kline as a tkline */
1059 if (!conf->until)
1060 return;
1061
1062 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1063 to, 'k', conf->host, conf->user, conf->reason);
1064 }
1065 /* Theyre opered, or allowed to see all klines */
1066 else {
1067 report_Klines(source_p, 1);
1068 }
1069 }
1070
1071 static void
1072 stats_klines(struct Client *source_p, int parc, char *parv[])
1073 {
1074 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1075 if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1076 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1077 from, to);
1078
1079 /* If unopered, Only return matching klines */
1080 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1081 {
1082 struct MaskItem *conf = NULL;
1083
1084 /* search for a kline */
1085 if (MyConnect(source_p))
1086 conf = find_conf_by_address(source_p->host,
1087 &source_p->localClient->ip,
1088 CONF_KLINE,
1089 source_p->localClient->aftype,
1090 source_p->username, NULL, 0);
1091 else
1092 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1093 0, source_p->username, NULL, 0);
1094
1095 if (!conf)
1096 return;
1097
1098 /* dont report a tkline as a kline */
1099 if (conf->until)
1100 return;
1101
1102 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1103 to, 'K', conf->host, conf->user, conf->reason);
1104 }
1105 /* Theyre opered, or allowed to see all klines */
1106 else
1107 report_Klines(source_p, 0);
1108 }
1109
1110 static void
1111 stats_messages(struct Client *source_p, int parc, char *parv[])
1112 {
1113 report_messages(source_p);
1114 }
1115
1116 static void
1117 stats_oper(struct Client *source_p, int parc, char *parv[])
1118 {
1119 if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
1120 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1121 from, to);
1122 else
1123 report_confitem_types(source_p, CONF_OPER);
1124 }
1125
1126 /* stats_operedup()
1127 *
1128 * input - client pointer
1129 * output - none
1130 * side effects - client is shown a list of active opers
1131 */
1132 static void
1133 stats_operedup(struct Client *source_p, int parc, char *parv[])
1134 {
1135 dlink_node *ptr;
1136
1137 DLINK_FOREACH(ptr, oper_list.head)
1138 {
1139 const struct Client *target_p = ptr->data;
1140
1141 if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
1142 continue;
1143
1144 if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
1145 sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %u",
1146 from, RPL_STATSDEBUG, to,
1147 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1148 oper_privs_as_string(target_p->localClient->operflags),
1149 target_p->name, target_p->username, target_p->host,
1150 idle_time_get(source_p, target_p));
1151 else
1152 sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %u",
1153 from, RPL_STATSDEBUG, to,
1154 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1155 target_p->name, target_p->username, target_p->host,
1156 idle_time_get(source_p, target_p));
1157 }
1158
1159 sendto_one(source_p, ":%s %d %s p :%u OPER(s)",
1160 from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1161 }
1162
1163 static void
1164 stats_ports(struct Client *source_p, int parc, char *parv[])
1165 {
1166 if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
1167 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1168 from, to);
1169 else
1170 show_ports(source_p);
1171 }
1172
1173 static void
1174 stats_resv(struct Client *source_p, int parc, char *parv[])
1175 {
1176 report_resv(source_p);
1177 }
1178
1179 static void
1180 stats_service(struct Client *source_p, int parc, char *parv[])
1181 {
1182 report_confitem_types(source_p, CONF_SERVICE);
1183 }
1184
1185 static void
1186 stats_tstats(struct Client *source_p, int parc, char *parv[])
1187 {
1188 const struct Client *target_p = NULL;
1189 const dlink_node *ptr = NULL;
1190 struct ServerStatistics tmp;
1191 struct ServerStatistics *sp = &tmp;
1192
1193 memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
1194
1195 /*
1196 * must use the += operator. is_sv is not the number of currently
1197 * active server connections. Note the incrementation in
1198 * s_bsd.c:close_connection.
1199 */
1200 sp->is_sv += dlink_list_length(&serv_list);
1201
1202 DLINK_FOREACH(ptr, serv_list.head)
1203 {
1204 target_p = ptr->data;
1205
1206 sp->is_sbs += target_p->localClient->send.bytes;
1207 sp->is_sbr += target_p->localClient->recv.bytes;
1208 sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1209 }
1210
1211 sp->is_cl += dlink_list_length(&local_client_list);
1212
1213 DLINK_FOREACH(ptr, local_client_list.head)
1214 {
1215 target_p = ptr->data;
1216
1217 sp->is_cbs += target_p->localClient->send.bytes;
1218 sp->is_cbr += target_p->localClient->recv.bytes;
1219 sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1220 }
1221
1222 sp->is_ni += dlink_list_length(&unknown_list);
1223
1224 sendto_one(source_p, ":%s %d %s T :accepts %u refused %u",
1225 me.name, RPL_STATSDEBUG, source_p->name, sp->is_ac, sp->is_ref);
1226 sendto_one(source_p, ":%s %d %s T :unknown commands %u prefixes %u",
1227 me.name, RPL_STATSDEBUG, source_p->name, sp->is_unco, sp->is_unpf);
1228 sendto_one(source_p, ":%s %d %s T :nick collisions %u unknown closes %u",
1229 me.name, RPL_STATSDEBUG, source_p->name, sp->is_kill, sp->is_ni);
1230 sendto_one(source_p, ":%s %d %s T :wrong direction %u empty %u",
1231 me.name, RPL_STATSDEBUG, source_p->name, sp->is_wrdi, sp->is_empt);
1232 sendto_one(source_p, ":%s %d %s T :numerics seen %u",
1233 me.name, RPL_STATSDEBUG, source_p->name, sp->is_num);
1234 sendto_one(source_p, ":%s %d %s T :auth successes %u fails %u",
1235 me.name, RPL_STATSDEBUG, source_p->name, sp->is_asuc, sp->is_abad);
1236 sendto_one(source_p, ":%s %d %s T :Client Server",
1237 me.name, RPL_STATSDEBUG, source_p->name);
1238
1239 sendto_one(source_p, ":%s %d %s T :connected %u %u",
1240 me.name, RPL_STATSDEBUG, source_p->name,
1241 (unsigned int)sp->is_cl,
1242 (unsigned int)sp->is_sv);
1243 sendto_one(source_p, ":%s %d %s T :bytes sent %llu %llu",
1244 me.name, RPL_STATSDEBUG, source_p->name,
1245 sp->is_cbs, sp->is_sbs);
1246 sendto_one(source_p, ":%s %d %s T :bytes recv %llu %llu",
1247 me.name, RPL_STATSDEBUG, source_p->name,
1248 sp->is_cbr, sp->is_sbr);
1249 sendto_one(source_p, ":%s %d %s T :time connected %u %u",
1250 me.name, RPL_STATSDEBUG, source_p->name,
1251 (unsigned int)sp->is_cti,
1252 (unsigned int)sp->is_sti);
1253 }
1254
1255 static void
1256 stats_uptime(struct Client *source_p, int parc, char *parv[])
1257 {
1258 time_t now = CurrentTime - me.localClient->since;
1259
1260 sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1261 now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1262
1263 if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1264 sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1265 Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1266 }
1267
1268 static void
1269 stats_shared(struct Client *source_p, int parc, char *parv[])
1270 {
1271 report_confitem_types(source_p, CONF_ULINE);
1272 }
1273
1274 /* stats_servers()
1275 *
1276 * input - client pointer
1277 * output - none
1278 * side effects - client is shown lists of who connected servers
1279 */
1280 static void
1281 stats_servers(struct Client *source_p, int parc, char *parv[])
1282 {
1283 dlink_node *ptr = NULL;
1284
1285 DLINK_FOREACH(ptr, serv_list.head)
1286 {
1287 const struct Client *target_p = ptr->data;
1288
1289 sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1290 from, RPL_STATSDEBUG, to, target_p->name,
1291 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1292 "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1293 }
1294
1295 sendto_one(source_p, ":%s %d %s v :%u Server(s)",
1296 from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1297 }
1298
1299 static void
1300 stats_gecos(struct Client *source_p, int parc, char *parv[])
1301 {
1302 report_confitem_types(source_p, CONF_XLINE);
1303 }
1304
1305 static void
1306 stats_class(struct Client *source_p, int parc, char *parv[])
1307 {
1308 report_confitem_types(source_p, CONF_CLASS);
1309 }
1310
1311 static void
1312 stats_servlinks(struct Client *source_p, int parc, char *parv[])
1313 {
1314 uint64_t sendB = 0, recvB = 0;
1315 time_t uptime = 0;
1316 dlink_node *ptr = NULL;
1317
1318 if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1319 {
1320 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1321 from, to);
1322 return;
1323 }
1324
1325 DLINK_FOREACH(ptr, serv_list.head)
1326 {
1327 struct Client *target_p = ptr->data;
1328
1329 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1330 if (!HasUMode(source_p, UMODE_OPER))
1331 continue;
1332
1333 sendB += target_p->localClient->send.bytes;
1334 recvB += target_p->localClient->recv.bytes;
1335
1336 /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1337 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1338 from, to,
1339 get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1340 dbuf_length(&target_p->localClient->buf_sendq),
1341 target_p->localClient->send.messages,
1342 target_p->localClient->send.bytes >> 10,
1343 target_p->localClient->recv.messages,
1344 target_p->localClient->recv.bytes >> 10,
1345 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1346 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1347 HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1348 }
1349
1350 sendB >>= 10;
1351 recvB >>= 10;
1352
1353 sendto_one(source_p, ":%s %d %s ? :%u total server(s)",
1354 from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1355 sendto_one(source_p, ":%s %d %s ? :Sent total : %7.2f %s",
1356 from, RPL_STATSDEBUG, to,
1357 _GMKv(sendB), _GMKs(sendB));
1358 sendto_one(source_p, ":%s %d %s ? :Recv total : %7.2f %s",
1359 from, RPL_STATSDEBUG, to,
1360 _GMKv(recvB), _GMKs(recvB));
1361
1362 uptime = (CurrentTime - me.localClient->since);
1363
1364 sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1365 from, RPL_STATSDEBUG, to,
1366 _GMKv((me.localClient->send.bytes>>10)),
1367 _GMKs((me.localClient->send.bytes>>10)),
1368 (float)((float)((me.localClient->send.bytes) >> 10) /
1369 (float)uptime));
1370 sendto_one(source_p, ":%s %d %s ? :Server recv: %7.2f %s (%4.1f K/s)",
1371 from, RPL_STATSDEBUG, to,
1372 _GMKv((me.localClient->recv.bytes>>10)),
1373 _GMKs((me.localClient->recv.bytes>>10)),
1374 (float)((float)((me.localClient->recv.bytes) >> 10) /
1375 (float)uptime));
1376 }
1377
1378 /* parse_stats_args()
1379 *
1380 * inputs - arg count
1381 * - args
1382 * - doall flag
1383 * - wild card or not
1384 * output - pointer to name to use
1385 * side effects -
1386 * common parse routine for m_stats args
1387 *
1388 */
1389 static char *
1390 parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1391 {
1392 char *name;
1393
1394 if (parc > 2)
1395 {
1396 name = parv[2];
1397
1398 if (!irccmp(name, from))
1399 *doall = 2;
1400 else if (!match(name, from))
1401 *doall = 1;
1402
1403 *wilds = has_wildcards(name);
1404
1405 return name;
1406 }
1407
1408 return NULL;
1409 }
1410
1411 static void
1412 stats_L_list(struct Client *source_p,char *name, int doall, int wilds,
1413 dlink_list *list,char statchar)
1414 {
1415 dlink_node *ptr;
1416 struct Client *target_p;
1417
1418 /*
1419 * send info about connections which match, or all if the
1420 * mask matches from. Only restrictions are on those who
1421 * are invisible not being visible to 'foreigners' who use
1422 * a wild card based search to list it.
1423 */
1424 DLINK_FOREACH(ptr, list->head)
1425 {
1426 target_p = ptr->data;
1427
1428 if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1429 !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1430 !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1431 continue;
1432 if (!doall && wilds && match(name, target_p->name))
1433 continue;
1434 if (!(doall || wilds) && irccmp(name, target_p->name))
1435 continue;
1436
1437 /* This basically shows ips for our opers if its not a server/admin, or
1438 * its one of our admins. */
1439 if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1440 (HasUMode(source_p, UMODE_ADMIN) ||
1441 (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1442 !IsHandshake(target_p) && !IsConnecting(target_p))))
1443 {
1444 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1445 from, to,
1446 (IsUpper(statchar)) ?
1447 get_client_name(target_p, SHOW_IP) :
1448 get_client_name(target_p, HIDE_IP),
1449 dbuf_length(&target_p->localClient->buf_sendq),
1450 target_p->localClient->send.messages,
1451 target_p->localClient->send.bytes>>10,
1452 target_p->localClient->recv.messages,
1453 target_p->localClient->recv.bytes>>10,
1454 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1455 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1456 IsServer(target_p) ? show_capabilities(target_p) : "-");
1457 }
1458 else
1459 {
1460 /* If its a hidden ip, an admin, or a server, mask the real IP */
1461 if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1462 || IsHandshake(target_p) || IsConnecting(target_p))
1463 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1464 from, to,
1465 get_client_name(target_p, MASK_IP),
1466 dbuf_length(&target_p->localClient->buf_sendq),
1467 target_p->localClient->send.messages,
1468 target_p->localClient->send.bytes>>10,
1469 target_p->localClient->recv.messages,
1470 target_p->localClient->recv.bytes>>10,
1471 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1472 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1473 IsServer(target_p) ? show_capabilities(target_p) : "-");
1474 else /* show the real IP */
1475 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1476 from, to,
1477 (IsUpper(statchar)) ?
1478 get_client_name(target_p, SHOW_IP) :
1479 get_client_name(target_p, HIDE_IP),
1480 dbuf_length(&target_p->localClient->buf_sendq),
1481 target_p->localClient->send.messages,
1482 target_p->localClient->send.bytes>>10,
1483 target_p->localClient->recv.messages,
1484 target_p->localClient->recv.bytes>>10,
1485 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1486 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1487 IsServer(target_p) ? show_capabilities(target_p) : "-");
1488 }
1489 }
1490 }
1491
1492 /*
1493 * stats_L
1494 *
1495 * inputs - pointer to client to report to
1496 * - doall flag
1497 * - wild card or not
1498 * output - NONE
1499 * side effects -
1500 */
1501 static void
1502 stats_L(struct Client *source_p,char *name,int doall,
1503 int wilds,char statchar)
1504 {
1505 stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1506 stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1507 stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1508 }
1509
1510 static void
1511 stats_ltrace(struct Client *source_p, int parc, char *parv[])
1512 {
1513 int doall = 0;
1514 int wilds = 0;
1515 char *name = NULL;
1516 char statchar;
1517
1518 if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1519 {
1520 statchar = parv[1][0];
1521
1522 stats_L(source_p, name, doall, wilds, statchar);
1523 }
1524 else
1525 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1526 from, to, "STATS");
1527 }
1528
1529 static const struct StatsStruct
1530 {
1531 const unsigned char letter;
1532 void (*handler)();
1533 const unsigned int need_oper;
1534 const unsigned int need_admin;
1535 } stats_cmd_table[] = {
1536 /* letter function need_oper need_admin */
1537 { 'a', stats_dns_servers, 1, 1 },
1538 { 'A', stats_dns_servers, 1, 1 },
1539 { 'c', stats_connect, 1, 0 },
1540 { 'C', stats_connect, 1, 0 },
1541 { 'd', stats_tdeny, 1, 0 },
1542 { 'D', stats_deny, 1, 0 },
1543 { 'e', stats_exempt, 1, 0 },
1544 { 'E', stats_events, 1, 1 },
1545 { 'f', fd_dump, 1, 1 },
1546 { 'F', fd_dump, 1, 1 },
1547 { 'g', stats_pending_glines, 1, 0 },
1548 { 'G', stats_glines, 1, 0 },
1549 { 'h', stats_hooks, 1, 1 },
1550 { 'H', stats_hubleaf, 1, 0 },
1551 { 'i', stats_auth, 0, 0 },
1552 { 'I', stats_auth, 0, 0 },
1553 { 'k', stats_tklines, 0, 0 },
1554 { 'K', stats_klines, 0, 0 },
1555 { 'l', stats_ltrace, 1, 0 },
1556 { 'L', stats_ltrace, 1, 0 },
1557 { 'm', stats_messages, 0, 0 },
1558 { 'M', stats_messages, 0, 0 },
1559 { 'o', stats_oper, 0, 0 },
1560 { 'O', stats_oper, 0, 0 },
1561 { 'p', stats_operedup, 0, 0 },
1562 { 'P', stats_ports, 0, 0 },
1563 { 'q', stats_resv, 1, 0 },
1564 { 'Q', stats_resv, 1, 0 },
1565 { 'r', stats_usage, 1, 0 },
1566 { 'R', stats_usage, 1, 0 },
1567 { 's', stats_service, 1, 0 },
1568 { 'S', stats_service, 1, 0 },
1569 { 't', stats_tstats, 1, 0 },
1570 { 'T', stats_tstats, 1, 0 },
1571 { 'u', stats_uptime, 0, 0 },
1572 { 'U', stats_shared, 1, 0 },
1573 { 'v', stats_servers, 1, 0 },
1574 { 'x', stats_gecos, 1, 0 },
1575 { 'X', stats_gecos, 1, 0 },
1576 { 'y', stats_class, 1, 0 },
1577 { 'Y', stats_class, 1, 0 },
1578 { 'z', stats_memory, 1, 0 },
1579 { '?', stats_servlinks, 0, 0 },
1580 { '\0', NULL, 0, 0 }
1581 };
1582
1583 static void
1584 do_stats(struct Client *source_p, int parc, char *parv[])
1585 {
1586 const struct StatsStruct *tab = stats_cmd_table;
1587 const char statchar = *parv[1];
1588
1589 if (statchar == '\0')
1590 {
1591 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1592 from, to, '*');
1593 return;
1594 }
1595
1596 for (; tab->handler; ++tab)
1597 {
1598 if (tab->letter == statchar)
1599 {
1600 /* The stats table says what privs are needed, so check --fl_ */
1601 if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1602 (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1603 {
1604 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1605 from, to);
1606 break;
1607 }
1608
1609 sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1610 "STATS %c requested by %s (%s@%s) [%s]",
1611 statchar, source_p->name, source_p->username,
1612 source_p->host, source_p->servptr->name);
1613 tab->handler(source_p, parc, parv);
1614 break;
1615 }
1616 }
1617
1618 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1619 from, to, statchar);
1620 }
1621
1622 /*
1623 * m_stats()
1624 * parv[0] = sender prefix
1625 * parv[1] = stat letter/command
1626 * parv[2] = (if present) server/mask in stats L
1627 *
1628 * This will search the tables for the appropriate stats letter/command,
1629 * if found execute it.
1630 */
1631 static void
1632 m_stats(struct Client *client_p, struct Client *source_p,
1633 int parc, char *parv[])
1634 {
1635 static time_t last_used = 0;
1636
1637 /* Is the stats meant for us? */
1638 if (!ConfigFileEntry.disable_remote)
1639 if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1640 parc, parv) != HUNTED_ISME)
1641 return;
1642
1643 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1644 {
1645 from = me.id;
1646 to = source_p->id;
1647 }
1648 else
1649 {
1650 from = me.name;
1651 to = source_p->name;
1652 }
1653
1654 /* Check the user is actually allowed to do /stats, and isnt flooding */
1655 if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1656 {
1657 sendto_one(source_p,form_str(RPL_LOAD2HI),
1658 from, to);
1659 return;
1660 }
1661
1662 last_used = CurrentTime;
1663
1664 do_stats(source_p, parc, parv);
1665 }
1666
1667 /*
1668 * mo_stats()
1669 * parv[0] = sender prefix
1670 * parv[1] = stat letter/command
1671 * parv[2] = (if present) server/mask in stats L, or target
1672 *
1673 * This will search the tables for the appropriate stats letter,
1674 * if found execute it.
1675 */
1676 static void
1677 mo_stats(struct Client *client_p, struct Client *source_p,
1678 int parc, char *parv[])
1679 {
1680 if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1681 parc, parv) != HUNTED_ISME)
1682 return;
1683
1684 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1685 {
1686 from = me.id;
1687 to = source_p->id;
1688 }
1689 else
1690 {
1691 from = me.name;
1692 to = source_p->name;
1693 }
1694
1695 do_stats(source_p, parc, parv);
1696 }
1697
1698 /*
1699 * ms_stats - STATS message handler
1700 * parv[0] = sender prefix
1701 * parv[1] = statistics selector (defaults to Message frequency)
1702 * parv[2] = server name (current server defaulted, if omitted)
1703 */
1704 static void
1705 ms_stats(struct Client *client_p, struct Client *source_p,
1706 int parc, char *parv[])
1707 {
1708 if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1709 parc, parv) != HUNTED_ISME)
1710 return;
1711
1712 if (IsClient(source_p))
1713 mo_stats(client_p, source_p, parc, parv);
1714 }
1715
1716 static struct Message stats_msgtab = {
1717 "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1718 { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1719 };
1720
1721 static void
1722 module_init(void)
1723 {
1724 mod_add_cmd(&stats_msgtab);
1725 }
1726
1727 static void
1728 module_exit(void)
1729 {
1730 mod_del_cmd(&stats_msgtab);
1731 }
1732
1733 struct module module_entry = {
1734 .node = { NULL, NULL, NULL },
1735 .name = NULL,
1736 .version = "$Revision$",
1737 .handle = NULL,
1738 .modinit = module_init,
1739 .modexit = module_exit,
1740 .flags = 0
1741 };

Properties

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