1 /*
2  *  ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
3  *  m_stats.c: Sends the user statistics or config information.
4  *
5  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6  *  Copyright (C) 1996-2002 Hybrid Development Team
7  *  Copyright (C) 2002-2005 ircd-ratbox development team
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
22  *  USA
23  *
24  *  $Id: m_stats.c 26316 2008-12-16 19:28:23Z androsyn $
25  */
26 
27 #include "stdinc.h"
28 #include "struct.h"
29 #include "ratbox_lib.h"
30 #include "class.h"		/* report_classes */
31 #include "client.h"		/* Client */
32 #include "channel.h"
33 #include "match.h"
34 #include "ircd.h"		/* me */
35 #include "listener.h"		/* show_ports */
36 #include "s_gline.h"
37 #include "hostmask.h"		/* report_mtrie_conf_links */
38 #include "numeric.h"		/* ERR_xxx */
39 #include "send.h"		/* sendto_one */
40 #include "s_conf.h"		/* ConfItem */
41 #include "s_serv.h"		/* hunt_server */
42 #include "s_stats.h"		/* tstats */
43 #include "s_user.h"		/* show_opers */
44 #include "parse.h"
45 #include "hook.h"
46 #include "modules.h"
47 #include "s_newconf.h"
48 #include "hash.h"
49 #include "dns.h"
50 #include "reject.h"
51 #include "whowas.h"
52 #include "scache.h"
53 #include "s_log.h"
54 
55 static int m_stats(struct Client *, struct Client *, int, const char **);
56 
57 struct Message stats_msgtab = {
58 	"STATS", 0, 0, 0, MFLG_SLOW,
59 	{mg_unreg, {m_stats, 2}, {m_stats, 3}, mg_ignore, mg_ignore, {m_stats, 2}}
60 };
61 
62 int doing_stats_hook;
63 int doing_stats_p_hook;
64 
65 mapi_clist_av1 stats_clist[] = { &stats_msgtab, NULL };
66 
67 mapi_hlist_av1 stats_hlist[] = {
68 	{"doing_stats", &doing_stats_hook},
69 	{"doing_stats_p", &doing_stats_p_hook},
70 	{NULL, NULL}
71 };
72 
73 DECLARE_MODULE_AV1(stats, NULL, NULL, stats_clist, stats_hlist, NULL, "$Revision: 26316 $");
74 
75 
76 static void stats_l_list(struct Client *s, const char *, int, int, rb_dlink_list *, char);
77 static void stats_l_client(struct Client *source_p, struct Client *target_p, char statchar);
78 
79 static void stats_spy(struct Client *, char, const char *);
80 static void stats_p_spy(struct Client *);
81 
82 /* Heres our struct for the stats table */
83 struct StatsStruct
84 {
85 	char letter;
86 	void (*handler) ();
87 	int need_oper;
88 	int need_admin;
89 };
90 
91 static void stats_dns_servers(struct Client *);
92 static void stats_delay(struct Client *);
93 static void stats_hash(struct Client *);
94 static void stats_connect(struct Client *);
95 static void stats_tdeny(struct Client *);
96 static void stats_deny(struct Client *);
97 static void stats_exempt(struct Client *);
98 static void stats_events(struct Client *);
99 static void stats_glines(struct Client *);
100 static void stats_pending_glines(struct Client *);
101 static void stats_hubleaf(struct Client *);
102 static void stats_auth(struct Client *);
103 static void stats_tklines(struct Client *);
104 static void stats_klines(struct Client *);
105 static void stats_messages(struct Client *);
106 static void stats_oper(struct Client *);
107 static void stats_operedup(struct Client *);
108 static void stats_ports(struct Client *);
109 static void stats_tresv(struct Client *);
110 static void stats_resv(struct Client *);
111 static void stats_usage(struct Client *);
112 static void stats_tstats(struct Client *);
113 static void stats_uptime(struct Client *);
114 static void stats_shared(struct Client *);
115 static void stats_servers(struct Client *);
116 static void stats_tgecos(struct Client *);
117 static void stats_gecos(struct Client *);
118 static void stats_class(struct Client *);
119 static void stats_memory(struct Client *);
120 static void stats_servlinks(struct Client *);
121 static void stats_ltrace(struct Client *, int, const char **);
122 static void stats_ziplinks(struct Client *);
123 static void stats_comm(struct Client *);
124 /* This table contains the possible stats items, in order:
125  * stats letter,  function to call, operonly? adminonly?
126  * case only matters in the stats letter column.. -- fl_
127  */
128 static struct StatsStruct stats_cmd_table[] = {
129 	/* letter     function        need_oper need_admin */
130 	{'a', stats_dns_servers, 1, 1,},
131 	{'A', stats_dns_servers, 1, 1,},
132 	{'b', stats_delay, 1, 1,},
133 	{'B', stats_hash, 1, 1,},
134 	{'c', stats_connect, 0, 0,},
135 	{'C', stats_connect, 0, 0,},
136 	{'d', stats_tdeny, 1, 0,},
137 	{'D', stats_deny, 1, 0,},
138 	{'e', stats_exempt, 1, 0,},
139 	{'E', stats_events, 1, 1,},
140 	{'f', stats_comm, 1, 1,},
141 	{'F', stats_comm, 1, 1,},
142 	{'g', stats_pending_glines, 1, 0,},
143 	{'G', stats_glines, 1, 0,},
144 	{'h', stats_hubleaf, 0, 0,},
145 	{'H', stats_hubleaf, 0, 0,},
146 	{'i', stats_auth, 0, 0,},
147 	{'I', stats_auth, 0, 0,},
148 	{'k', stats_tklines, 0, 0,},
149 	{'K', stats_klines, 0, 0,},
150 	{'l', stats_ltrace, 0, 0,},
151 	{'L', stats_ltrace, 0, 0,},
152 	{'m', stats_messages, 0, 0,},
153 	{'M', stats_messages, 0, 0,},
154 	{'o', stats_oper, 0, 0,},
155 	{'O', stats_oper, 0, 0,},
156 	{'p', stats_operedup, 0, 0,},
157 	{'P', stats_ports, 0, 0,},
158 	{'q', stats_tresv, 1, 0,},
159 	{'Q', stats_resv, 1, 0,},
160 	{'r', stats_usage, 1, 0,},
161 	{'R', stats_usage, 1, 0,},
162 	{'t', stats_tstats, 1, 0,},
163 	{'T', stats_tstats, 1, 0,},
164 	{'u', stats_uptime, 0, 0,},
165 	{'U', stats_shared, 1, 0,},
166 	{'v', stats_servers, 0, 0,},
167 	{'V', stats_servers, 0, 0,},
168 	{'x', stats_tgecos, 1, 0,},
169 	{'X', stats_gecos, 1, 0,},
170 	{'y', stats_class, 0, 0,},
171 	{'Y', stats_class, 0, 0,},
172 	{'z', stats_memory, 1, 0,},
173 	{'Z', stats_ziplinks, 1, 0,},
174 	{'?', stats_servlinks, 0, 0,},
175 	{(char)0, (void (*)())0, 0, 0,}
176 };
177 
178 /*
179  * m_stats by fl_
180  *      parv[0] = sender prefix
181  *      parv[1] = stat letter/command
182  *      parv[2] = (if present) server/mask in stats L, or target
183  *
184  * This will search the tables for the appropriate stats letter,
185  * if found execute it.
186  */
187 static int
m_stats(struct Client * client_p,struct Client * source_p,int parc,const char * parv[])188 m_stats(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
189 {
190 	static time_t last_used = 0;
191 	int i;
192 	char statchar;
193 
194 	statchar = parv[1][0];
195 
196 	if(MyClient(source_p) && !IsOper(source_p))
197 	{
198 		/* Check the user is actually allowed to do /stats, and isnt flooding */
199 		if((last_used + ConfigFileEntry.pace_wait) > rb_current_time())
200 		{
201 			/* safe enough to give this on a local connect only */
202 			sendto_one(source_p, form_str(RPL_LOAD2HI),
203 				   me.name, source_p->name, "STATS");
204 			sendto_one_numeric(source_p, RPL_ENDOFSTATS,
205 					   form_str(RPL_ENDOFSTATS), statchar);
206 			return 0;
207 		}
208 		else
209 			last_used = rb_current_time();
210 	}
211 
212 	if(hunt_server(client_p, source_p, ":%s STATS %s :%s", 2, parc, parv) != HUNTED_ISME)
213 		return 0;
214 
215 	if((statchar != 'L') && (statchar != 'l'))
216 		stats_spy(source_p, statchar, NULL);
217 
218 	for(i = 0; stats_cmd_table[i].handler; i++)
219 	{
220 		if(stats_cmd_table[i].letter == statchar)
221 		{
222 			/* The stats table says what privs are needed, so check --fl_ */
223 			/* Called for remote clients and for local opers, so check need_admin
224 			 * and need_oper
225 			 */
226 			if((stats_cmd_table[i].need_admin && !IsOperAdmin(source_p)) ||
227 			   (stats_cmd_table[i].need_oper && !IsOper(source_p)))
228 			{
229 				sendto_one_numeric(source_p, ERR_NOPRIVILEGES,
230 						   form_str(ERR_NOPRIVILEGES));
231 				break;
232 			}
233 			SetCork(source_p);
234 			/* Blah, stats L needs the parameters, none of the others do.. */
235 			if(statchar == 'L' || statchar == 'l')
236 				stats_cmd_table[i].handler(source_p, parc, parv);
237 			else
238 				stats_cmd_table[i].handler(source_p);
239 			ClearCork(source_p);
240 
241 		}
242 	}
243 
244 	/* Send the end of stats notice */
245 	sendto_one_numeric(source_p, RPL_ENDOFSTATS, form_str(RPL_ENDOFSTATS), statchar);
246 
247 	return 0;
248 }
249 
250 static void
stats_dns_servers(struct Client * source_p)251 stats_dns_servers(struct Client *source_p)
252 {
253 	report_dns_servers(source_p);
254 }
255 
256 static void
stats_delay(struct Client * source_p)257 stats_delay(struct Client *source_p)
258 {
259 	struct nd_entry *nd;
260 	rb_dlink_node *ptr;
261 	int i;
262 
263 	HASH_WALK(i, U_MAX, ptr, ndTable)
264 	{
265 		nd = ptr->data;
266 		sendto_one_notice(source_p, "Delaying: %s for %ld", nd->name, (long)nd->expire);
267 	}
268 HASH_WALK_END}
269 
270 static void
stats_hash(struct Client * source_p)271 stats_hash(struct Client *source_p)
272 {
273 	hash_stats(source_p);
274 }
275 
276 static void
stats_connect(struct Client * source_p)277 stats_connect(struct Client *source_p)
278 {
279 	static char buf[5];
280 	struct server_conf *server_p;
281 	char *s;
282 	rb_dlink_node *ptr;
283 
284 	if((ConfigFileEntry.stats_c_oper_only ||
285 	    (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) && !IsOper(source_p))
286 	{
287 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
288 		return;
289 	}
290 
291 	RB_DLINK_FOREACH(ptr, server_conf_list.head)
292 	{
293 		server_p = ptr->data;
294 
295 		if(ServerConfIllegal(server_p))
296 			continue;
297 
298 		buf[0] = '\0';
299 		s = buf;
300 
301 		if(IsOper(source_p))
302 		{
303 			if(ServerConfAutoconn(server_p))
304 				*s++ = 'A';
305 			if(ServerConfSSL(server_p))
306 				*s++ = 'S';
307 			if(ServerConfTb(server_p))
308 				*s++ = 'T';
309 			if(ServerConfCompressed(server_p))
310 				*s++ = 'Z';
311 		}
312 
313 		if(!buf[0])
314 			*s++ = '*';
315 
316 		*s = '\0';
317 
318 		sendto_one_numeric(source_p, RPL_STATSCLINE,
319 				   form_str(RPL_STATSCLINE),
320 				   "*@127.0.0.1", buf, server_p->name,
321 				   server_p->port, server_p->class_name);
322 	}
323 }
324 
325 /* stats_tdeny()
326  *
327  * input	- client to report to
328  * output	- none
329  * side effects - client is given temp dline list.
330  */
331 static void
stats_tdeny(struct Client * source_p)332 stats_tdeny(struct Client *source_p)
333 {
334 	report_tdlines(source_p);
335 }
336 
337 /* stats_deny()
338  *
339  * input	- client to report to
340  * output	- none
341  * side effects - client is given dline list.
342  */
343 static void
stats_deny(struct Client * source_p)344 stats_deny(struct Client *source_p)
345 {
346 	report_dlines(source_p);
347 }
348 
349 
350 /* stats_exempt()
351  *
352  * input	- client to report to
353  * output	- none
354  * side effects - client is given list of exempt blocks
355  */
356 static void
stats_exempt(struct Client * source_p)357 stats_exempt(struct Client *source_p)
358 {
359 	if(ConfigFileEntry.stats_e_disabled)
360 	{
361 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
362 		return;
363 	}
364 
365 	report_elines(source_p);
366 }
367 
368 static void
stats_events_cb(char * str,void * ptr)369 stats_events_cb(char *str, void *ptr)
370 {
371 	sendto_one_numeric(ptr, RPL_STATSDEBUG, "E :%s", str);
372 }
373 
374 static void
stats_events(struct Client * source_p)375 stats_events(struct Client *source_p)
376 {
377 	rb_dump_events(stats_events_cb, source_p);
378 	send_pop_queue(source_p);
379 }
380 
381 /* stats_pending_glines()
382  *
383  * input	- client pointer
384  * output	- none
385  * side effects - client is shown list of pending glines
386  */
387 static void
stats_pending_glines(struct Client * source_p)388 stats_pending_glines(struct Client *source_p)
389 {
390 	if(ConfigFileEntry.glines)
391 	{
392 		rb_dlink_node *pending_node;
393 		struct gline_pending *glp_ptr;
394 		char timebuffer[MAX_DATE_STRING];
395 		struct tm *tmptr;
396 
397 		RB_DLINK_FOREACH(pending_node, pending_glines.head)
398 		{
399 			glp_ptr = pending_node->data;
400 
401 			tmptr = gmtime(&glp_ptr->time_request1);
402 			strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
403 
404 			sendto_one_notice(source_p,
405 					  ":1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
406 					  glp_ptr->oper_nick1,
407 					  glp_ptr->oper_user1, glp_ptr->oper_host1,
408 					  glp_ptr->oper_server1, timebuffer,
409 					  glp_ptr->user, glp_ptr->host, glp_ptr->reason1);
410 
411 			if(glp_ptr->oper_nick2[0])
412 			{
413 				tmptr = gmtime(&glp_ptr->time_request2);
414 				strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
415 				sendto_one_notice(source_p,
416 						  ":2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
417 						  glp_ptr->oper_nick2,
418 						  glp_ptr->oper_user2, glp_ptr->oper_host2,
419 						  glp_ptr->oper_server2, timebuffer,
420 						  glp_ptr->user, glp_ptr->host, glp_ptr->reason2);
421 			}
422 		}
423 
424 		if(rb_dlink_list_length(&pending_glines) > 0)
425 			sendto_one_notice(source_p, ":End of Pending G-lines");
426 	}
427 	else
428 		sendto_one_notice(source_p, ":This server does not support G-Lines");
429 
430 }
431 
432 /* stats_glines()
433  *
434  * input	- client pointer
435  * output	- none
436  * side effects - client is shown list of glines
437  */
438 static void
stats_glines(struct Client * source_p)439 stats_glines(struct Client *source_p)
440 {
441 	if(ConfigFileEntry.glines)
442 	{
443 		rb_dlink_node *gline_node;
444 		struct ConfItem *kill_ptr;
445 
446 		RB_DLINK_FOREACH_PREV(gline_node, glines.tail)
447 		{
448 			kill_ptr = gline_node->data;
449 
450 			sendto_one_numeric(source_p, RPL_STATSKLINE,
451 					   form_str(RPL_STATSKLINE), 'G',
452 					   kill_ptr->host ? kill_ptr->host : "*",
453 					   kill_ptr->user ? kill_ptr->user : "*",
454 					   kill_ptr->passwd ? kill_ptr->passwd : "No Reason",
455 					   kill_ptr->spasswd ? "|" : "",
456 					   kill_ptr->spasswd ? kill_ptr->spasswd : "");
457 		}
458 	}
459 	else
460 		sendto_one_notice(source_p, ":This server does not support G-Lines");
461 }
462 
463 
464 static void
stats_hubleaf(struct Client * source_p)465 stats_hubleaf(struct Client *source_p)
466 {
467 	struct remote_conf *hub_p;
468 	rb_dlink_node *ptr;
469 
470 	if((ConfigFileEntry.stats_h_oper_only ||
471 	    (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) && !IsOper(source_p))
472 	{
473 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
474 		return;
475 	}
476 
477 	RB_DLINK_FOREACH(ptr, hubleaf_conf_list.head)
478 	{
479 		hub_p = ptr->data;
480 
481 		if(hub_p->flags & CONF_HUB)
482 			sendto_one_numeric(source_p, RPL_STATSHLINE,
483 					   form_str(RPL_STATSHLINE), hub_p->host, hub_p->server);
484 		else
485 			sendto_one_numeric(source_p, RPL_STATSLLINE,
486 					   form_str(RPL_STATSLLINE), hub_p->host, hub_p->server);
487 	}
488 }
489 
490 
491 static void
stats_auth(struct Client * source_p)492 stats_auth(struct Client *source_p)
493 {
494 	const char *name, *host, *pass, *user, *classname;
495 	struct AddressRec *arec;
496 	struct ConfItem *aconf;
497 	int i, port;
498 
499 	/* Oper only, if unopered, return ERR_NOPRIVS */
500 	if((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
501 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
502 
503 	/* If unopered, Only return matching auth blocks */
504 	else if((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
505 	{
506 		if(MyConnect(source_p))
507 			aconf = find_auth(source_p->host, source_p->sockhost,
508 					  (struct sockaddr *)&source_p->localClient->ip,
509 					  GET_SS_FAMILY(&source_p->localClient->ip),
510 					  source_p->username);
511 		else
512 			aconf = find_auth(source_p->host, NULL, NULL, 0, source_p->username);
513 
514 		if(aconf == NULL)
515 			return;
516 
517 		get_printable_conf(aconf, &name, &host, &pass, &user, &port, &classname);
518 
519 		sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
520 				   name, show_iline_prefix(source_p, aconf, user),
521 				   host, port, classname);
522 	}
523 
524 	/* Theyre opered, or allowed to see all auth blocks */
525 	else
526 	{
527 		HOSTHASH_WALK(i, arec)
528 		{
529 			if((arec->type & ~CONF_SKIPUSER) == CONF_CLIENT)
530 			{
531 				aconf = arec->aconf;
532 				if(!MyOper(source_p) && IsConfDoSpoofIp(aconf))
533 					continue;
534 				get_printable_conf(aconf, &name, &host, &pass, &user, &port,
535 						   &classname);
536 
537 				sendto_one_numeric(source_p, RPL_STATSILINE,
538 						   form_str(RPL_STATSILINE), name,
539 						   show_iline_prefix(source_p, aconf, user),
540 						   show_ip_conf(aconf,
541 								source_p) ? host :
542 						   "255.255.255.255", port, classname);
543 			}
544 		}
545 		HOSTHASH_WALK_END;
546 		send_pop_queue(source_p);
547 	}
548 }
549 
550 
551 static void
stats_tklines(struct Client * source_p)552 stats_tklines(struct Client *source_p)
553 {
554 	const char *host, *pass, *user, *oper_reason;
555 	struct ConfItem *aconf;
556 
557 	/* Oper only, if unopered, return ERR_NOPRIVS */
558 	if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
559 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
560 
561 	/* If unopered, Only return matching klines */
562 	else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
563 	{
564 
565 		if(MyConnect(source_p))
566 			aconf = find_conf_by_address(source_p->host, source_p->sockhost,
567 						     (struct sockaddr *)&source_p->localClient->ip,
568 						     CONF_KILL,
569 						     GET_SS_FAMILY(&source_p->localClient->ip),
570 						     source_p->username);
571 		else
572 			aconf = find_conf_by_address(source_p->host, NULL, NULL, CONF_KILL,
573 						     0, source_p->username);
574 
575 		if(aconf == NULL)
576 			return;
577 
578 		/* dont report a permanent kline as a tkline */
579 		if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0)
580 			return;
581 
582 		get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
583 
584 		sendto_one_numeric(source_p, RPL_STATSKLINE,
585 				   form_str(RPL_STATSKLINE), 'k',
586 				   user, pass, oper_reason ? "|" : "",
587 				   oper_reason ? oper_reason : "");
588 	}
589 	/* Theyre opered, or allowed to see all klines */
590 	else
591 	{
592 		rb_dlink_node *ptr;
593 		int i;
594 
595 		for(i = 0; i < LAST_TEMP_TYPE; i++)
596 		{
597 			RB_DLINK_FOREACH(ptr, temp_klines[i].head)
598 			{
599 				aconf = ptr->data;
600 
601 				get_printable_kline(source_p, aconf, &host, &pass,
602 						    &user, &oper_reason);
603 
604 				sendto_one_numeric(source_p, RPL_STATSKLINE,
605 						   form_str(RPL_STATSKLINE),
606 						   'k', host, user, pass,
607 						   oper_reason ? "|" : "",
608 						   oper_reason ? oper_reason : "");
609 			}
610 		}
611 	}
612 }
613 
614 static void
stats_klines(struct Client * source_p)615 stats_klines(struct Client *source_p)
616 {
617 	struct ConfItem *aconf;
618 	const char *host, *pass, *user, *oper_reason;
619 	struct AddressRec *arec;
620 	int i;
621 
622 	/* Oper only, if unopered, return ERR_NOPRIVS */
623 	if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
624 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
625 
626 	/* If unopered, Only return matching klines */
627 	else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
628 	{
629 
630 		/* search for a kline */
631 		if(MyConnect(source_p))
632 			aconf = find_conf_by_address(source_p->host, source_p->sockhost,
633 						     (struct sockaddr *)&source_p->localClient->ip,
634 						     CONF_KILL,
635 						     GET_SS_FAMILY(&source_p->localClient->ip),
636 						     source_p->username);
637 		else
638 			aconf = find_conf_by_address(source_p->host, NULL, NULL, CONF_KILL,
639 						     0, source_p->username);
640 
641 		if(aconf == NULL)
642 			return;
643 
644 		/* dont report a tkline as a kline */
645 		if(aconf->flags & CONF_FLAGS_TEMPORARY)
646 			return;
647 
648 		get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
649 
650 		sendto_one_numeric(source_p, RPL_STATSKLINE, form_str(RPL_STATSKLINE),
651 				   'K', host, user, pass, oper_reason ? "|" : "",
652 				   oper_reason ? oper_reason : "");
653 	}
654 	/* Theyre opered, or allowed to see all klines */
655 	else
656 	{
657 		HOSTHASH_WALK(i, arec)
658 		{
659 			if((arec->type & ~CONF_SKIPUSER) == CONF_KILL)
660 			{
661 				aconf = arec->aconf;
662 
663 				if(aconf->flags & CONF_FLAGS_TEMPORARY)	/* skip temps */
664 					continue;
665 
666 				get_printable_kline(source_p, aconf, &host, &pass, &user,
667 						    &oper_reason);
668 
669 				sendto_one_numeric(source_p, RPL_STATSKLINE,
670 						   form_str(RPL_STATSKLINE), 'K', host, user, pass,
671 						   oper_reason ? "|" : "",
672 						   oper_reason ? oper_reason : "");
673 
674 			}
675 		}
676 		HOSTHASH_WALK_END;
677 		send_pop_queue(source_p);
678 	}
679 }
680 
681 static void
stats_messages(struct Client * source_p)682 stats_messages(struct Client *source_p)
683 {
684 	int i;
685 	struct MessageHash *ptr;
686 
687 	for(i = 0; i < MAX_MSG_HASH; i++)
688 	{
689 		for(ptr = msg_hash_table[i]; ptr; ptr = ptr->next)
690 		{
691 			s_assert(ptr->msg != NULL);
692 			s_assert(ptr->cmd != NULL);
693 
694 			sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
695 					   form_str(RPL_STATSCOMMANDS),
696 					   ptr->cmd, ptr->msg->count,
697 					   ptr->msg->bytes, ptr->msg->rcount);
698 		}
699 	}
700 	send_pop_queue(source_p);
701 }
702 
703 static void
stats_oper(struct Client * source_p)704 stats_oper(struct Client *source_p)
705 {
706 	struct oper_conf *oper_p;
707 	rb_dlink_node *ptr;
708 
709 	if(!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
710 	{
711 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
712 		return;
713 	}
714 
715 	RB_DLINK_FOREACH(ptr, oper_conf_list.head)
716 	{
717 		oper_p = ptr->data;
718 
719 		sendto_one_numeric(source_p, RPL_STATSOLINE,
720 				   form_str(RPL_STATSOLINE),
721 				   oper_p->username, oper_p->host, oper_p->name,
722 				   IsOper(source_p) ? get_oper_privs(oper_p->flags) : "0", "-1");
723 	}
724 }
725 
726 
727 /* stats_operedup()
728  *
729  * input	- client pointer
730  * output	- none
731  * side effects - client is shown a list of active opers
732  */
733 static void
stats_operedup(struct Client * source_p)734 stats_operedup(struct Client *source_p)
735 {
736 	struct Client *target_p;
737 	rb_dlink_node *oper_ptr;
738 	unsigned int count = 0;
739 
740 	RB_DLINK_FOREACH(oper_ptr, oper_list.head)
741 	{
742 		target_p = oper_ptr->data;
743 
744 		if(IsOperInvis(target_p) && !IsOper(source_p))
745 			continue;
746 
747 		count++;
748 
749 		if(MyClient(source_p) && IsOper(source_p))
750 		{
751 			sendto_one_numeric(source_p, RPL_STATSDEBUG,
752 					   "p :[%c][%s] %s (%s@%s) Idle: %ld",
753 					   IsAdmin(target_p) ? 'A' : 'O',
754 					   get_oper_privs(target_p->operflags),
755 					   target_p->name, target_p->username, target_p->host,
756 					   (long)(rb_current_time() - target_p->localClient->last));
757 		}
758 		else
759 		{
760 			sendto_one_numeric(source_p, RPL_STATSDEBUG,
761 					   "p :[%c] %s (%s@%s) Idle: %ld",
762 					   IsAdmin(target_p) ? 'A' : 'O',
763 					   target_p->name, target_p->username, target_p->host,
764 					   (long)(rb_current_time() - target_p->localClient->last));
765 		}
766 	}
767 
768 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "p :%u OPER(s)", count);
769 
770 	stats_p_spy(source_p);
771 }
772 
773 static void
stats_ports(struct Client * source_p)774 stats_ports(struct Client *source_p)
775 {
776 	if(!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
777 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
778 	else
779 		show_ports(source_p);
780 }
781 
782 static void
stats_tresv(struct Client * source_p)783 stats_tresv(struct Client *source_p)
784 {
785 	struct ConfItem *aconf;
786 	rb_dlink_node *ptr;
787 	int i;
788 
789 	RB_DLINK_FOREACH(ptr, resv_conf_list.head)
790 	{
791 		aconf = ptr->data;
792 		if(aconf->flags & CONF_FLAGS_TEMPORARY)
793 			sendto_one_numeric(source_p, RPL_STATSQLINE,
794 					   form_str(RPL_STATSQLINE),
795 					   'q', aconf->port, aconf->host, aconf->passwd);
796 	}
797 
798 	HASH_WALK(i, R_MAX, ptr, resvTable)
799 	{
800 		aconf = ptr->data;
801 		if(aconf->flags & CONF_FLAGS_TEMPORARY)
802 			sendto_one_numeric(source_p, RPL_STATSQLINE,
803 					   form_str(RPL_STATSQLINE),
804 					   'q', aconf->port, aconf->host, aconf->passwd);
805 	}
806 HASH_WALK_END}
807 
808 
809 static void
stats_resv(struct Client * source_p)810 stats_resv(struct Client *source_p)
811 {
812 	struct ConfItem *aconf;
813 	rb_dlink_node *ptr;
814 	int i;
815 
816 	RB_DLINK_FOREACH(ptr, resv_conf_list.head)
817 	{
818 		aconf = ptr->data;
819 		if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0)
820 			sendto_one_numeric(source_p, RPL_STATSQLINE,
821 					   form_str(RPL_STATSQLINE),
822 					   'Q', aconf->port, aconf->host, aconf->passwd);
823 	}
824 
825 	HASH_WALK(i, R_MAX, ptr, resvTable)
826 	{
827 		aconf = ptr->data;
828 		if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0)
829 			sendto_one_numeric(source_p, RPL_STATSQLINE,
830 					   form_str(RPL_STATSQLINE),
831 					   'Q', aconf->port, aconf->host, aconf->passwd);
832 	}
833 HASH_WALK_END}
834 
835 static void
stats_usage(struct Client * source_p)836 stats_usage(struct Client *source_p)
837 {
838 #ifndef _WIN32
839 	struct rusage rus;
840 	time_t secs;
841 	time_t rup;
842 #ifdef  hz
843 # define hzz hz
844 #else
845 # ifdef HZ
846 #  define hzz HZ
847 # else
848 	int hzz = 1;
849 # endif
850 #endif
851 
852 	if(getrusage(RUSAGE_SELF, &rus) == -1)
853 	{
854 		sendto_one_notice(source_p, ":Getruseage error: %s.", strerror(errno));
855 		return;
856 	}
857 	secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
858 	if(0 == secs)
859 		secs = 1;
860 
861 	rup = (rb_current_time() - startup_time) * hzz;
862 	if(0 == rup)
863 		rup = 1;
864 
865 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
866 			   "R :CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
867 			   (long)(secs / 60), (long)(secs % 60),
868 			   (long)(rus.ru_utime.tv_sec / 60),
869 			   (long)(rus.ru_utime.tv_sec % 60),
870 			   (long)(rus.ru_stime.tv_sec / 60), (long)(rus.ru_stime.tv_sec % 60));
871 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
872 			   "R :RSS %ld ShMem %ld Data %ld Stack %ld",
873 			   rus.ru_maxrss, (rus.ru_ixrss / rup),
874 			   (rus.ru_idrss / rup), (rus.ru_isrss / rup));
875 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
876 			   "R :Swaps %ld Reclaims %ld Faults %ld",
877 			   rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
878 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
879 			   "R :Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
880 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
881 			   "R :Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
882 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
883 			   "R :Signals %ld Context Vol. %ld Invol %ld",
884 			   rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
885 #endif
886 }
887 
888 static void
stats_tstats(struct Client * source_p)889 stats_tstats(struct Client *source_p)
890 {
891 	struct Client *target_p;
892 	struct ServerStatistics sp;
893 	rb_dlink_node *ptr;
894 
895 	memcpy(&sp, &ServerStats, sizeof(struct ServerStatistics));
896 
897 	RB_DLINK_FOREACH(ptr, serv_list.head)
898 	{
899 		target_p = ptr->data;
900 
901 		sp.is_sbs += target_p->localClient->sendB;
902 		sp.is_sbr += target_p->localClient->receiveB;
903 		sp.is_sti += (unsigned long long)(rb_current_time() - target_p->localClient->firsttime);
904 		sp.is_sv++;
905 	}
906 
907 	RB_DLINK_FOREACH(ptr, lclient_list.head)
908 	{
909 		target_p = ptr->data;
910 
911 		sp.is_cbs += target_p->localClient->sendB;
912 		sp.is_cbr += target_p->localClient->receiveB;
913 		sp.is_cti += (unsigned long long)(rb_current_time() - target_p->localClient->firsttime);
914 		sp.is_cl++;
915 	}
916 
917 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
918 			   "T :accepts %u refused %u", sp.is_ac, sp.is_ref);
919 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
920 			   "T :rejected %u delaying %lu", sp.is_rej, delay_exit_length());
921 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
922 			   "T :throttled refused %u throttle list size %lu", sp.is_thr, throttle_size());
923 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :nicks being delayed %lu", get_nd_count());
924 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
925 			   "T :unknown commands %u prefixes %u", sp.is_unco, sp.is_unpf);
926 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
927 			   "T :nick collisions %u saves %u unknown closes %u",
928 			   sp.is_kill, sp.is_save, sp.is_ni);
929 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
930 			   "T :wrong direction %u empty %u", sp.is_wrdi, sp.is_empt);
931 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :numerics seen %u", sp.is_num);
932 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
933 			   "T :auth successes %u fails %u", sp.is_asuc, sp.is_abad);
934 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :Client Server");
935 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :connected %u %u", sp.is_cl, sp.is_sv);
936 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
937 			   "T :bytes sent %lluK %lluK", sp.is_cbs / 1024, sp.is_sbs / 1024);
938 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
939 			   "T :bytes recv %lluK %lluK", sp.is_cbr / 1024, sp.is_sbr / 1024);
940 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
941 			   "T :time connected %llu %llu", sp.is_cti, sp.is_sti);
942 }
943 
944 static void
stats_uptime(struct Client * source_p)945 stats_uptime(struct Client *source_p)
946 {
947 	time_t now;
948 
949 	now = rb_current_time() - startup_time;
950 	sendto_one_numeric(source_p, RPL_STATSUPTIME,
951 			   form_str(RPL_STATSUPTIME),
952 			   now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
953 	sendto_one_numeric(source_p, RPL_STATSCONN,
954 			   form_str(RPL_STATSCONN),
955 			   MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
956 }
957 
958 struct shared_flags
959 {
960 	int flag;
961 	char letter;
962 };
963 static struct shared_flags shared_flagtable[] = {
964 	{SHARED_PKLINE, 'K'},
965 	{SHARED_TKLINE, 'k'},
966 	{SHARED_UNKLINE, 'U'},
967 	{SHARED_PXLINE, 'X'},
968 	{SHARED_TXLINE, 'x'},
969 	{SHARED_UNXLINE, 'Y'},
970 	{SHARED_PRESV, 'Q'},
971 	{SHARED_TRESV, 'q'},
972 	{SHARED_UNRESV, 'R'},
973 	{SHARED_LOCOPS, 'L'},
974 	{0, '\0'}
975 };
976 
977 
978 static void
stats_shared(struct Client * source_p)979 stats_shared(struct Client *source_p)
980 {
981 	struct remote_conf *shared_p;
982 	rb_dlink_node *ptr;
983 	char buf[15];
984 	char *p;
985 	int i;
986 
987 	RB_DLINK_FOREACH(ptr, shared_conf_list.head)
988 	{
989 		shared_p = ptr->data;
990 
991 		p = buf;
992 
993 		*p++ = 'c';
994 
995 		for(i = 0; shared_flagtable[i].flag != 0; i++)
996 		{
997 			if(shared_p->flags & shared_flagtable[i].flag)
998 				*p++ = shared_flagtable[i].letter;
999 		}
1000 
1001 		*p = '\0';
1002 
1003 		sendto_one_numeric(source_p, RPL_STATSULINE,
1004 				   form_str(RPL_STATSULINE),
1005 				   shared_p->server, shared_p->username, shared_p->host, buf);
1006 	}
1007 
1008 	RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
1009 	{
1010 		shared_p = ptr->data;
1011 
1012 		p = buf;
1013 
1014 		*p++ = 'C';
1015 
1016 		for(i = 0; shared_flagtable[i].flag != 0; i++)
1017 		{
1018 			if(shared_p->flags & shared_flagtable[i].flag)
1019 				*p++ = shared_flagtable[i].letter;
1020 		}
1021 
1022 		*p = '\0';
1023 
1024 		sendto_one_numeric(source_p, RPL_STATSULINE,
1025 				   form_str(RPL_STATSULINE), shared_p->server, "*", "*", buf);
1026 	}
1027 }
1028 
1029 /* stats_servers()
1030  *
1031  * input	- client pointer
1032  * output	- none
1033  * side effects - client is shown lists of who connected servers
1034  */
1035 static void
stats_servers(struct Client * source_p)1036 stats_servers(struct Client *source_p)
1037 {
1038 	struct Client *target_p;
1039 	rb_dlink_node *ptr;
1040 	long days, hours, minutes, seconds;
1041 	int j = 0;
1042 
1043 	if(ConfigServerHide.flatten_links && !IsOper(source_p) && !IsExemptShide(source_p))
1044 	{
1045 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
1046 		return;
1047 	}
1048 
1049 	RB_DLINK_FOREACH(ptr, serv_list.head)
1050 	{
1051 		target_p = ptr->data;
1052 
1053 		j++;
1054 		seconds = (long)(rb_current_time() - target_p->localClient->firsttime);
1055 
1056 		days = seconds / 86400;
1057 		seconds %= 86400;
1058 		hours = seconds / 3600;
1059 		seconds %= 3600;
1060 		minutes = seconds / 60;
1061 		seconds %= 60;
1062 
1063 		sendto_one_numeric(source_p, RPL_STATSDEBUG,
1064 				   "V :%s (%s!*@*) Idle: %ld SendQ: %d "
1065 				   "Connected: %ld day%s, %ld:%02ld:%02ld",
1066 				   target_p->name,
1067 				   (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1068 				   (long)(rb_current_time() - target_p->localClient->lasttime),
1069 				   rb_linebuf_len(&target_p->localClient->buf_sendq),
1070 				   days, (days == 1) ? "" : "s", hours, minutes, seconds);
1071 	}
1072 
1073 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "V :%d Server(s)", j);
1074 }
1075 
1076 static void
stats_tgecos(struct Client * source_p)1077 stats_tgecos(struct Client *source_p)
1078 {
1079 	struct ConfItem *aconf;
1080 	rb_dlink_node *ptr;
1081 
1082 	RB_DLINK_FOREACH(ptr, xline_conf_list.head)
1083 	{
1084 		aconf = ptr->data;
1085 
1086 		if(aconf->flags & CONF_FLAGS_TEMPORARY)
1087 			sendto_one_numeric(source_p, RPL_STATSXLINE,
1088 					   form_str(RPL_STATSXLINE),
1089 					   'x', aconf->port, aconf->host, aconf->passwd);
1090 	}
1091 }
1092 
1093 static void
stats_gecos(struct Client * source_p)1094 stats_gecos(struct Client *source_p)
1095 {
1096 	struct ConfItem *aconf;
1097 	rb_dlink_node *ptr;
1098 
1099 	RB_DLINK_FOREACH(ptr, xline_conf_list.head)
1100 	{
1101 		aconf = ptr->data;
1102 
1103 		if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0)
1104 			sendto_one_numeric(source_p, RPL_STATSXLINE,
1105 					   form_str(RPL_STATSXLINE),
1106 					   'X', aconf->port, aconf->host, aconf->passwd);
1107 	}
1108 }
1109 
1110 static void
stats_class(struct Client * source_p)1111 stats_class(struct Client *source_p)
1112 {
1113 	struct Class *cltmp;
1114 	rb_dlink_node *ptr;
1115 
1116 	if(ConfigFileEntry.stats_y_oper_only && !IsOper(source_p))
1117 	{
1118 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
1119 		return;
1120 	}
1121 
1122 	RB_DLINK_FOREACH(ptr, class_list.head)
1123 	{
1124 		cltmp = ptr->data;
1125 
1126 		sendto_one_numeric(source_p, RPL_STATSYLINE,
1127 				   form_str(RPL_STATSYLINE),
1128 				   ClassName(cltmp), PingFreq(cltmp),
1129 				   ConFreq(cltmp), MaxUsers(cltmp),
1130 				   MaxSendq(cltmp),
1131 				   MaxLocal(cltmp), MaxIdent(cltmp),
1132 				   MaxGlobal(cltmp), MaxIdent(cltmp), CurrUsers(cltmp));
1133 	}
1134 
1135 	/* also output the default class */
1136 	sendto_one_numeric(source_p, RPL_STATSYLINE, form_str(RPL_STATSYLINE),
1137 			   ClassName(default_class), PingFreq(default_class),
1138 			   ConFreq(default_class), MaxUsers(default_class),
1139 			   MaxSendq(default_class),
1140 			   MaxLocal(default_class), MaxIdent(default_class),
1141 			   MaxGlobal(default_class), MaxIdent(default_class),
1142 			   CurrUsers(default_class));
1143 	send_pop_queue(source_p);
1144 }
1145 
1146 static void
stats_bh_callback(size_t bused,size_t bfree,size_t bmemusage,size_t heapalloc,const char * desc,void * data)1147 stats_bh_callback(size_t bused, size_t bfree, size_t bmemusage, size_t heapalloc, const char *desc,
1148 		  void *data)
1149 {
1150 	struct Client *source_p = (struct Client *)data;
1151 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1152 			   "z :blockheap %s elements used: %zu elements free: %zu memory in use: %zu total memory: %zu",
1153 			   desc, bused, bfree, bmemusage, heapalloc);
1154 
1155 	return;
1156 }
1157 
1158 static void
stats_memory(struct Client * source_p)1159 stats_memory(struct Client *source_p)
1160 {
1161 	struct Client *target_p;
1162 	struct Channel *chptr;
1163 	struct Ban *actualBan;
1164 	rb_dlink_node *dlink;
1165 	rb_dlink_node *ptr;
1166 	int channel_count = 0;
1167 	int local_client_conf_count = 0;	/* local client conf links */
1168 	int users_counted = 0;	/* user structs */
1169 
1170 	int channel_users = 0;
1171 	int channel_invites = 0;
1172 	int channel_bans = 0;
1173 	int channel_except = 0;
1174 	int channel_invex = 0;
1175 
1176 	size_t wwu = 0;		/* whowas users */
1177 	int class_count = 0;	/* classes */
1178 	int conf_count = 0;	/* conf lines */
1179 	int users_invited_count = 0;	/* users invited */
1180 	int user_channels = 0;	/* users in channels */
1181 	int aways_counted = 0;
1182 	size_t number_servers_cached;	/* number of servers cached by scache */
1183 
1184 	size_t channel_memory = 0;
1185 	size_t channel_ban_memory = 0;
1186 	size_t channel_except_memory = 0;
1187 	size_t channel_invex_memory = 0;
1188 
1189 	size_t away_memory = 0;	/* memory used by aways */
1190 	size_t wwm = 0;		/* whowas array memory used */
1191 	size_t conf_memory = 0;	/* memory used by conf lines */
1192 	size_t mem_servers_cached;	/* memory used by scache */
1193 
1194 	size_t rb_linebuf_count = 0;
1195 	size_t rb_linebuf_memory_used = 0;
1196 
1197 	size_t total_channel_memory = 0;
1198 	size_t totww = 0;
1199 
1200 	size_t local_client_count = 0;
1201 	size_t local_client_memory_used = 0;
1202 
1203 	size_t remote_client_count = 0;
1204 	size_t remote_client_memory_used = 0;
1205 
1206 	size_t total_memory = 0;
1207 	size_t bh_total, bh_used;
1208 	rb_bh_usage_all(stats_bh_callback, (void *)source_p);
1209 	rb_bh_total_usage(&bh_total, &bh_used);
1210 
1211 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1212 			   "z :blockheap Total Allocated: %zu Total Used: %zu", bh_total, bh_used);
1213 
1214 	count_whowas_memory(&wwu, &wwm);
1215 
1216 
1217 	RB_DLINK_FOREACH(ptr, global_client_list.head)
1218 	{
1219 		target_p = ptr->data;
1220 		if(MyConnect(target_p))
1221 		{
1222 			local_client_conf_count++;
1223 		}
1224 
1225 		if(target_p->user)
1226 		{
1227 			users_counted++;
1228 			if(MyConnect(target_p))
1229 				users_invited_count +=
1230 					rb_dlink_list_length(&target_p->localClient->invited);
1231 			user_channels += rb_dlink_list_length(&target_p->user->channel);
1232 			if(target_p->user->away)
1233 			{
1234 				aways_counted++;
1235 				away_memory += (strlen(target_p->user->away) + 1);
1236 			}
1237 		}
1238 	}
1239 
1240 	/* Count up all channels, ban lists, except lists, Invex lists */
1241 	RB_DLINK_FOREACH(ptr, global_channel_list.head)
1242 	{
1243 		chptr = ptr->data;
1244 		channel_count++;
1245 		channel_memory += (strlen(chptr->chname) + sizeof(struct Channel));
1246 
1247 		channel_users += rb_dlink_list_length(&chptr->members);
1248 		channel_invites += rb_dlink_list_length(&chptr->invites);
1249 
1250 		RB_DLINK_FOREACH(dlink, chptr->banlist.head)
1251 		{
1252 			actualBan = dlink->data;
1253 			channel_bans++;
1254 
1255 			channel_ban_memory += sizeof(rb_dlink_node) + sizeof(struct Ban);
1256 		}
1257 
1258 		RB_DLINK_FOREACH(dlink, chptr->exceptlist.head)
1259 		{
1260 			actualBan = dlink->data;
1261 			channel_except++;
1262 
1263 			channel_except_memory += (sizeof(rb_dlink_node) + sizeof(struct Ban));
1264 		}
1265 
1266 		RB_DLINK_FOREACH(dlink, chptr->invexlist.head)
1267 		{
1268 			actualBan = dlink->data;
1269 			channel_invex++;
1270 
1271 			channel_invex_memory += (sizeof(rb_dlink_node) + sizeof(struct Ban));
1272 		}
1273 	}
1274 
1275 	/* count up all classes */
1276 
1277 	class_count = rb_dlink_list_length(&class_list) + 1;
1278 
1279 	rb_count_rb_linebuf_memory(&rb_linebuf_count, &rb_linebuf_memory_used);
1280 
1281 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1282 			   "z :Users %u(%zu) Invites %u(%zu)",
1283 			   users_counted,
1284 			   users_counted * sizeof(struct User),
1285 			   users_invited_count, users_invited_count * sizeof(rb_dlink_node));
1286 
1287 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1288 			   "z :User channels %u(%zu) Aways %u(%zu)",
1289 			   user_channels,
1290 			   user_channels * sizeof(rb_dlink_node), aways_counted, away_memory);
1291 
1292 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1293 			   "z :Attached confs %u(%zu)",
1294 			   local_client_conf_count,
1295 			   local_client_conf_count * sizeof(rb_dlink_node));
1296 
1297 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1298 			   "z :Conflines %u(%zu)", conf_count, conf_memory);
1299 
1300 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1301 			   "z :Classes %u(%zu)", class_count, class_count * sizeof(struct Class));
1302 
1303 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1304 			   "z :Channels %u(%zu)", channel_count, channel_memory);
1305 
1306 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1307 			   "z :Bans %u(%zu)", channel_bans, channel_ban_memory);
1308 
1309 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1310 			   "z :Exceptions %u(%zu)", channel_except, channel_except_memory);
1311 
1312 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1313 			   "z :Invex %u(%zu)", channel_invex, channel_invex_memory);
1314 
1315 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1316 			   "z :Channel members %u(%zu) invite %u(%zu)",
1317 			   channel_users,
1318 			   channel_users * sizeof(rb_dlink_node),
1319 			   channel_invites, channel_invites * sizeof(rb_dlink_node));
1320 
1321 	total_channel_memory = channel_memory +
1322 		channel_ban_memory +
1323 		channel_users * sizeof(rb_dlink_node) + channel_invites * sizeof(rb_dlink_node);
1324 
1325 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1326 			   "z :Whowas users %zu(%zu)", wwu, (wwu * sizeof(struct User)));
1327 
1328 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1329 			   "z :Whowas array %u(%zu)", NICKNAMEHISTORYLENGTH, wwm);
1330 
1331 	totww = wwu * sizeof(struct User) + wwm;
1332 
1333 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1334 			   "z :Hash: client %u(%zu) chan %u(%zu)",
1335 			   U_MAX, (U_MAX * sizeof(rb_dlink_list)),
1336 			   CH_MAX, (CH_MAX * sizeof(rb_dlink_list)));
1337 
1338 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1339 			   "z :linebuf %zu(%zu)", rb_linebuf_count, rb_linebuf_memory_used);
1340 
1341 	count_scache(&number_servers_cached, &mem_servers_cached);
1342 
1343 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1344 			   "z :scache %ld(%ld)",
1345 			   (long)number_servers_cached, (long)mem_servers_cached);
1346 
1347 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1348 			   "z :hostname hash %d(%ld)",
1349 			   HOST_MAX, (long)HOST_MAX * sizeof(rb_dlink_list));
1350 
1351 	total_memory = totww + total_channel_memory + conf_memory +
1352 		class_count * sizeof(struct Class);
1353 
1354 	total_memory += mem_servers_cached;
1355 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1356 			   "z :Total: whowas %zu channel %zu conf %zu",
1357 			   totww, total_channel_memory, conf_memory);
1358 
1359 	count_local_client_memory(&local_client_count, &local_client_memory_used);
1360 	total_memory += local_client_memory_used;
1361 
1362 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1363 			   "z :Local client Memory in use: %zu(%zu)",
1364 			   local_client_count, local_client_memory_used);
1365 
1366 
1367 	count_remote_client_memory(&remote_client_count, &remote_client_memory_used);
1368 	total_memory += remote_client_memory_used;
1369 
1370 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1371 			   "z :Remote client Memory in use: %zu(%zu)",
1372 			   remote_client_count, remote_client_memory_used);
1373 
1374 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1375 			   "z :TOTAL: %zu Available:  Current max RSS: %lu",
1376 			   total_memory, get_maxrss());
1377 }
1378 
1379 static void
stats_ziplinks(struct Client * source_p)1380 stats_ziplinks(struct Client *source_p)
1381 {
1382 	rb_dlink_node *ptr;
1383 	struct Client *target_p;
1384 	struct ZipStats *zipstats;
1385 	int sent_data = 0;
1386 	char buf[128], buf1[128];
1387 	RB_DLINK_FOREACH(ptr, serv_list.head)
1388 	{
1389 		target_p = ptr->data;
1390 		if(IsCapable(target_p, CAP_ZIP))
1391 		{
1392 			zipstats = target_p->localClient->zipstats;
1393 			sprintf(buf, "%.2f%%", zipstats->out_ratio);
1394 			sprintf(buf1, "%.2f%%", zipstats->in_ratio);
1395 			sendto_one_numeric(source_p, RPL_STATSDEBUG,
1396 					   "Z :ZipLinks stats for %s send[%s compression "
1397 					   "(%llu kB data/%llu kB wire)] recv[%s compression "
1398 					   "(%llu kB data/%llu kB wire)]",
1399 					   target_p->name,
1400 					   buf, zipstats->out >> 10,
1401 					   zipstats->out_wire >> 10, buf1,
1402 					   zipstats->in >> 10, zipstats->in_wire >> 10);
1403 			sent_data++;
1404 		}
1405 	}
1406 
1407 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "Z :%u ziplink(s)", sent_data);
1408 }
1409 
1410 static void
stats_servlinks(struct Client * source_p)1411 stats_servlinks(struct Client *source_p)
1412 {
1413 	long uptime;
1414 	unsigned long long int sent, receive;
1415 	struct Client *target_p;
1416 	static char buf[512];
1417 	rb_dlink_node *ptr;
1418 	int j = 0;
1419 
1420 	if(ConfigServerHide.flatten_links && !IsOper(source_p) && !IsExemptShide(source_p))
1421 	{
1422 		sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
1423 		return;
1424 	}
1425 
1426 	sent = receive = 0;
1427 
1428 	RB_DLINK_FOREACH(ptr, serv_list.head)
1429 	{
1430 		target_p = ptr->data;
1431 
1432 		j++;
1433 		sent += target_p->localClient->sendB;
1434 		receive += target_p->localClient->receiveB;
1435 
1436 		sendto_one(source_p, ":%s %d %s %s %u %u %llu %u %llu :%lu %lu %s",
1437 			   get_id(&me, source_p), RPL_STATSLINKINFO, get_id(source_p, source_p),
1438 			   target_p->name,
1439 			   rb_linebuf_len(&target_p->localClient->buf_sendq),
1440 			   target_p->localClient->sendM,
1441 			   target_p->localClient->sendB / 1024,
1442 			   target_p->localClient->receiveM,
1443 			   target_p->localClient->receiveB / 1024,
1444 			   (long)(rb_current_time() - target_p->localClient->firsttime),
1445 			   (long)((rb_current_time() > target_p->localClient->lasttime) ?
1446 				  (rb_current_time() - target_p->localClient->lasttime) : 0),
1447 			   IsOper(source_p) ? show_capabilities(target_p) : "TS");
1448 	}
1449 
1450 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "? :%u total server(s)", j);
1451 
1452 	sprintf(buf, "%7.2f", _GMKv((sent / 1024)));
1453 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1454 			   "? :Sent total : %s %s", buf, _GMKs((sent / 1024)));
1455 
1456 	sprintf(buf, "%7.2f", _GMKv((receive / 1024)));
1457 	sendto_one_numeric(source_p, RPL_STATSDEBUG,
1458 			   "? :Recv total : %s %s", buf, _GMKs((receive / 1024)));
1459 
1460 	uptime = (rb_current_time() - startup_time);
1461 #ifdef HAVE_SNPRINTF
1462 	snprintf(buf, sizeof(buf),
1463 #else
1464 	sprintf(buf,
1465 #endif
1466 		"%7.2f %s (%4.1f K/s)", _GMKv(me.localClient->sendB / 1024),
1467 		_GMKs((me.localClient->sendB / 1024)),
1468 		(float)((float)(me.localClient->sendB / 1024) / (float)uptime));
1469 
1470 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "? :Server send: %s", buf);
1471 
1472 #ifdef HAVE_SNPRINTF
1473 	snprintf(buf, sizeof(buf),
1474 #else
1475 	sprintf(buf,
1476 #endif
1477 		"%7.2f %s (%4.1f K/s)", _GMKv((me.localClient->receiveB / 1024)),
1478 		_GMKs((me.localClient->receiveB / 1024)),
1479 		(float)((float)(me.localClient->receiveB / 1024) / (float)uptime));
1480 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "? :Server recv: %s", buf);
1481 }
1482 
1483 static void
stats_ltrace(struct Client * source_p,int parc,const char * parv[])1484 stats_ltrace(struct Client *source_p, int parc, const char *parv[])
1485 {
1486 	int doall = 0;
1487 	int wilds = 0;
1488 	const char *name;
1489 	char statchar = parv[1][0];
1490 
1491 	/* this is def targeted at us somehow.. */
1492 	if(parc > 2 && !EmptyString(parv[2]))
1493 	{
1494 		/* directed at us generically? */
1495 		if(match(parv[2], me.name) || (!MyClient(source_p) && !irccmp(parv[2], me.id)))
1496 		{
1497 			name = me.name;
1498 			doall = 1;
1499 		}
1500 		else
1501 		{
1502 			name = parv[2];
1503 			wilds = (strpbrk(name, "*?") != NULL);
1504 		}
1505 
1506 		/* must be directed at a specific person thats not us */
1507 		if(!doall && !wilds)
1508 		{
1509 			struct Client *target_p;
1510 
1511 			if(MyClient(source_p))
1512 				target_p = find_named_person(name);
1513 			else
1514 				target_p = find_person(name);
1515 
1516 			if(target_p != NULL)
1517 			{
1518 				stats_spy(source_p, statchar, target_p->name);
1519 				stats_l_client(source_p, target_p, statchar);
1520 			}
1521 			else
1522 				sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
1523 						   form_str(ERR_NOSUCHSERVER), name);
1524 
1525 			return;
1526 		}
1527 	}
1528 	else
1529 	{
1530 		name = me.name;
1531 		doall = 1;
1532 	}
1533 
1534 	stats_spy(source_p, statchar, name);
1535 
1536 	if(doall)
1537 	{
1538 		/* local opers get everyone */
1539 		if(MyOper(source_p))
1540 		{
1541 			stats_l_list(source_p, name, doall, wilds, &unknown_list, statchar);
1542 			stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar);
1543 		}
1544 		else
1545 		{
1546 			/* they still need themselves if theyre local.. */
1547 			if(MyClient(source_p))
1548 				stats_l_client(source_p, source_p, statchar);
1549 
1550 			stats_l_list(source_p, name, doall, wilds, &oper_list, statchar);
1551 		}
1552 
1553 		stats_l_list(source_p, name, doall, wilds, &serv_list, statchar);
1554 
1555 		return;
1556 	}
1557 
1558 	/* ok, at this point theyre looking for a specific client whos on
1559 	 * our server.. but it contains a wildcard.  --fl
1560 	 */
1561 	stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar);
1562 
1563 	return;
1564 }
1565 
1566 
1567 static void
stats_l_list(struct Client * source_p,const char * name,int doall,int wilds,rb_dlink_list * list,char statchar)1568 stats_l_list(struct Client *source_p, const char *name, int doall, int wilds,
1569 	     rb_dlink_list *list, char statchar)
1570 {
1571 	rb_dlink_node *ptr;
1572 	struct Client *target_p;
1573 
1574 	/* send information about connections which match.  note, we
1575 	 * dont need tests for IsInvisible(), because non-opers will
1576 	 * never get here for normal clients --fl
1577 	 */
1578 	RB_DLINK_FOREACH(ptr, list->head)
1579 	{
1580 		target_p = ptr->data;
1581 
1582 		if(!doall && wilds && !match(name, target_p->name))
1583 			continue;
1584 
1585 		stats_l_client(source_p, target_p, statchar);
1586 	}
1587 }
1588 
1589 #define Lformat "%s %u %u %llu %u %llu :%ld %ld %s"
1590 
1591 void
stats_l_client(struct Client * source_p,struct Client * target_p,char statchar)1592 stats_l_client(struct Client *source_p, struct Client *target_p, char statchar)
1593 {
1594 	if(IsAnyServer(target_p))
1595 	{
1596 		sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat,
1597 				   target_p->name,
1598 				   rb_linebuf_len(&target_p->localClient->buf_sendq),
1599 				   target_p->localClient->sendM,
1600 				   target_p->localClient->sendB / 1024,
1601 				   target_p->localClient->receiveM,
1602 				   target_p->localClient->receiveB / 1024,
1603 				   (long)rb_current_time() - target_p->localClient->firsttime,
1604 				   (long)(rb_current_time() > target_p->localClient->lasttime) ?
1605 				   (long)(rb_current_time() - target_p->localClient->lasttime) : 0,
1606 				   IsOper(source_p) ? show_capabilities(target_p) : "-");
1607 	}
1608 
1609 	else if(!show_ip(source_p, target_p))
1610 	{
1611 		sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat,
1612 				   get_client_name(target_p, MASK_IP),
1613 				   rb_linebuf_len(&target_p->localClient->buf_sendq),
1614 				   target_p->localClient->sendM,
1615 				   target_p->localClient->sendB / 1024,
1616 				   target_p->localClient->receiveM,
1617 				   target_p->localClient->receiveB / 1024,
1618 				   (long)(rb_current_time() - target_p->localClient->firsttime),
1619 				   (long)(rb_current_time() > target_p->localClient->lasttime) ?
1620 				   (long)(rb_current_time() - target_p->localClient->lasttime) : 0,
1621 				   "-");
1622 	}
1623 
1624 	else
1625 	{
1626 		sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat,
1627 				   IsUpper(statchar) ?
1628 				   get_client_name(target_p, SHOW_IP) :
1629 				   get_client_name(target_p, HIDE_IP),
1630 				   rb_linebuf_len(&target_p->localClient->buf_sendq),
1631 				   target_p->localClient->sendM,
1632 				   target_p->localClient->sendB / 1024,
1633 				   target_p->localClient->receiveM,
1634 				   target_p->localClient->receiveB / 1024,
1635 				   (long)rb_current_time() - target_p->localClient->firsttime,
1636 				   (long)(rb_current_time() > target_p->localClient->lasttime) ?
1637 				   (long)(rb_current_time() - target_p->localClient->lasttime) : 0,
1638 				   "-");
1639 	}
1640 }
1641 
1642 static void
rb_dump_fd_callback(int fd,const char * desc,void * data)1643 rb_dump_fd_callback(int fd, const char *desc, void *data)
1644 {
1645 	struct Client *source_p = data;
1646 	sendto_one_numeric(source_p, RPL_STATSDEBUG, "F :fd %-3d desc '%s'", fd, desc);
1647 }
1648 
1649 static void
stats_comm(struct Client * source_p)1650 stats_comm(struct Client *source_p)
1651 {
1652 	rb_dump_fd(rb_dump_fd_callback, source_p);
1653 	send_pop_queue(source_p);
1654 }
1655 
1656 /*
1657  * stats_spy
1658  *
1659  * inputs	- pointer to client doing the /stats
1660  *		- char letter they are doing /stats on
1661  * output	- none
1662  * side effects -
1663  * This little helper function reports to opers if configured.
1664  * personally, I don't see why opers need to see stats requests
1665  * at all. They are just "noise" to an oper, and users can't do
1666  * any damage with stats requests now anyway. So, why show them?
1667  * -Dianora
1668  */
1669 static void
stats_spy(struct Client * source_p,char statchar,const char * name)1670 stats_spy(struct Client *source_p, char statchar, const char *name)
1671 {
1672 	hook_data_int data;
1673 
1674 	data.client = source_p;
1675 	data.arg1 = name;
1676 	data.arg2 = (int)statchar;
1677 
1678 	call_hook(doing_stats_hook, &data);
1679 }
1680 
1681 /* stats_p_spy()
1682  *
1683  * input	- pointer to client doing stats
1684  * ouput	-
1685  * side effects - call hook doing_stats_p
1686  */
1687 static void
stats_p_spy(struct Client * source_p)1688 stats_p_spy(struct Client *source_p)
1689 {
1690 	hook_data data;
1691 
1692 	data.client = source_p;
1693 	data.arg1 = data.arg2 = NULL;
1694 
1695 	call_hook(doing_stats_p_hook, &data);
1696 }
1697