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