unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
stats.c (34355B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/stats.c 3 * (C) 2004-present The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 CMD_FUNC(cmd_stats); 26 27 #define MSG_STATS "STATS" 28 29 ModuleHeader MOD_HEADER 30 = { 31 "stats", 32 "5.0", 33 "command /stats", 34 "UnrealIRCd Team", 35 "unrealircd-6", 36 }; 37 38 MOD_INIT() 39 { 40 CommandAdd(modinfo->handle, MSG_STATS, cmd_stats, 3, CMD_USER); 41 MARK_AS_OFFICIAL_MODULE(modinfo); 42 return MOD_SUCCESS; 43 } 44 45 MOD_LOAD() 46 { 47 return MOD_SUCCESS; 48 } 49 50 MOD_UNLOAD() 51 { 52 return MOD_SUCCESS; 53 } 54 55 extern MODVAR int max_connection_count; 56 57 int stats_banversion(Client *, const char *); 58 int stats_links(Client *, const char *); 59 int stats_gline(Client *, const char *); 60 int stats_except(Client *, const char *); 61 int stats_allow(Client *, const char *); 62 int stats_command(Client *, const char *); 63 int stats_oper(Client *, const char *); 64 int stats_port(Client *, const char *); 65 int stats_bannick(Client *, const char *); 66 int stats_traffic(Client *, const char *); 67 int stats_uline(Client *, const char *); 68 int stats_vhost(Client *, const char *); 69 int stats_kline(Client *, const char *); 70 int stats_banrealname(Client *, const char *); 71 int stats_sqline(Client *, const char *); 72 int stats_linkinfoint(Client *, const char *, int); 73 int stats_linkinfo(Client *, const char *); 74 int stats_linkinfoall(Client *, const char *); 75 int stats_chanrestrict(Client *, const char *); 76 int stats_shun(Client *, const char *); 77 int stats_set(Client *, const char *); 78 int stats_tld(Client *, const char *); 79 int stats_uptime(Client *, const char *); 80 int stats_denyver(Client *, const char *); 81 int stats_notlink(Client *, const char *); 82 int stats_class(Client *, const char *); 83 int stats_officialchannels(Client *, const char *); 84 int stats_spamfilter(Client *, const char *); 85 int stats_fdtable(Client *, const char *); 86 87 #define SERVER_AS_PARA 0x1 88 #define FLAGS_AS_PARA 0x2 89 90 struct statstab { 91 char flag; 92 char *longflag; 93 int (*func)(Client *client, const char *para); 94 int options; 95 }; 96 97 /* Must be listed lexicographically */ 98 /* Long flags must be lowercase */ 99 struct statstab StatsTable[] = { 100 { 'B', "banversion", stats_banversion, 0 }, 101 { 'C', "link", stats_links, 0 }, 102 { 'G', "gline", stats_gline, FLAGS_AS_PARA }, 103 { 'H', "link", stats_links, 0 }, 104 { 'I', "allow", stats_allow, 0 }, 105 { 'K', "kline", stats_kline, 0 }, 106 { 'L', "linkinfoall", stats_linkinfoall, SERVER_AS_PARA }, 107 { 'M', "command", stats_command, 0 }, 108 { 'O', "oper", stats_oper, 0 }, 109 { 'P', "port", stats_port, 0 }, 110 { 'Q', "sqline", stats_sqline, FLAGS_AS_PARA }, 111 { 'S', "set", stats_set, 0 }, 112 { 'T', "traffic", stats_traffic, 0 }, 113 { 'U', "uline", stats_uline, 0 }, 114 { 'V', "vhost", stats_vhost, 0 }, 115 { 'W', "fdtable", stats_fdtable, 0 }, 116 { 'X', "notlink", stats_notlink, 0 }, 117 { 'Y', "class", stats_class, 0 }, 118 { 'c', "link", stats_links, 0 }, 119 { 'e', "except", stats_except, 0 }, 120 { 'f', "spamfilter", stats_spamfilter, FLAGS_AS_PARA }, 121 { 'g', "gline", stats_gline, FLAGS_AS_PARA }, 122 { 'h', "link", stats_links, 0 }, 123 { 'j', "officialchans", stats_officialchannels, 0 }, 124 { 'k', "kline", stats_kline, 0 }, 125 { 'l', "linkinfo", stats_linkinfo, SERVER_AS_PARA }, 126 { 'm', "command", stats_command, 0 }, 127 { 'n', "banrealname", stats_banrealname, 0 }, 128 { 'o', "oper", stats_oper, 0 }, 129 { 'q', "bannick", stats_bannick, FLAGS_AS_PARA }, 130 { 'r', "chanrestrict", stats_chanrestrict, 0 }, 131 { 's', "shun", stats_shun, FLAGS_AS_PARA }, 132 { 't', "tld", stats_tld, 0 }, 133 { 'u', "uptime", stats_uptime, 0 }, 134 { 'v', "denyver", stats_denyver, 0 }, 135 { 'x', "notlink", stats_notlink, 0 }, 136 { 'y', "class", stats_class, 0 }, 137 { 0, NULL, NULL, 0 } 138 }; 139 140 int stats_compare(const char *s1, const char *s2) 141 { 142 /* The long stats flags are always lowercase */ 143 while (*s1 == tolower(*s2)) 144 { 145 if (*s1 == 0) 146 return 0; 147 s1++; 148 s2++; 149 } 150 return 1; 151 } 152 153 static inline struct statstab *stats_binary_search(char c) { 154 int start = 0; 155 int stop = sizeof(StatsTable)/sizeof(StatsTable[0])-1; 156 int mid; 157 while (start <= stop) { 158 mid = (start+stop)/2; 159 if (c < StatsTable[mid].flag) 160 stop = mid-1; 161 else if (StatsTable[mid].flag == c) 162 return &StatsTable[mid]; 163 else 164 start = mid+1; 165 } 166 return NULL; 167 } 168 169 static inline struct statstab *stats_search(const char *s) { 170 int i; 171 for (i = 0; StatsTable[i].flag; i++) 172 if (!stats_compare(StatsTable[i].longflag,s)) 173 return &StatsTable[i]; 174 return NULL; 175 } 176 177 static inline char *stats_combine_parv(const char *p1, const char *p2) 178 { 179 static char buf[BUFSIZE+1]; 180 ircsnprintf(buf, sizeof(buf), "%s %s", p1, p2); 181 return buf; 182 } 183 184 static inline void stats_help(Client *client) 185 { 186 sendnumeric(client, RPL_STATSHELP, "/Stats flags:"); 187 sendnumeric(client, RPL_STATSHELP, "B - banversion - Send the ban version list"); 188 sendnumeric(client, RPL_STATSHELP, "b - badword - Send the badwords list"); 189 sendnumeric(client, RPL_STATSHELP, "C - link - Send the link block list"); 190 sendnumeric(client, RPL_STATSHELP, "d - denylinkauto - Send the deny link (auto) block list"); 191 sendnumeric(client, RPL_STATSHELP, "D - denylinkall - Send the deny link (all) block list"); 192 sendnumeric(client, RPL_STATSHELP, "e - except - Send the ban exception list (ELINEs and in config))"); 193 sendnumeric(client, RPL_STATSHELP, "f - spamfilter - Send the spamfilter list"); 194 sendnumeric(client, RPL_STATSHELP, "F - denydcc - Send the deny dcc and allow dcc block lists"); 195 sendnumeric(client, RPL_STATSHELP, "G - gline - Send the gline and gzline list"); 196 sendnumeric(client, RPL_STATSHELP, " Extended flags: [+/-mrs] [mask] [reason] [setby]"); 197 sendnumeric(client, RPL_STATSHELP, " m Return glines matching/not matching the specified mask"); 198 sendnumeric(client, RPL_STATSHELP, " r Return glines with a reason matching/not matching the specified reason"); 199 sendnumeric(client, RPL_STATSHELP, " s Return glines set by/not set by clients matching the specified name"); 200 sendnumeric(client, RPL_STATSHELP, "I - allow - Send the allow block list"); 201 sendnumeric(client, RPL_STATSHELP, "j - officialchans - Send the offical channels list"); 202 sendnumeric(client, RPL_STATSHELP, "K - kline - Send the ban user/ban ip/except ban block list"); 203 sendnumeric(client, RPL_STATSHELP, "l - linkinfo - Send link information"); 204 sendnumeric(client, RPL_STATSHELP, "L - linkinfoall - Send all link information"); 205 sendnumeric(client, RPL_STATSHELP, "M - command - Send list of how many times each command was used"); 206 sendnumeric(client, RPL_STATSHELP, "n - banrealname - Send the ban realname block list"); 207 sendnumeric(client, RPL_STATSHELP, "O - oper - Send the oper block list"); 208 sendnumeric(client, RPL_STATSHELP, "P - port - Send information about ports"); 209 sendnumeric(client, RPL_STATSHELP, "q - bannick - Send the ban nick block list"); 210 sendnumeric(client, RPL_STATSHELP, "Q - sqline - Send the global qline list"); 211 sendnumeric(client, RPL_STATSHELP, "r - chanrestrict - Send the channel deny/allow block list"); 212 sendnumeric(client, RPL_STATSHELP, "S - set - Send the set block list"); 213 sendnumeric(client, RPL_STATSHELP, "s - shun - Send the shun list"); 214 sendnumeric(client, RPL_STATSHELP, " Extended flags: [+/-mrs] [mask] [reason] [setby]"); 215 sendnumeric(client, RPL_STATSHELP, " m Return shuns matching/not matching the specified mask"); 216 sendnumeric(client, RPL_STATSHELP, " r Return shuns with a reason matching/not matching the specified reason"); 217 sendnumeric(client, RPL_STATSHELP, " s Return shuns set by/not set by clients matching the specified name"); 218 sendnumeric(client, RPL_STATSHELP, "t - tld - Send the tld block list"); 219 sendnumeric(client, RPL_STATSHELP, "T - traffic - Send traffic information"); 220 sendnumeric(client, RPL_STATSHELP, "u - uptime - Send the server uptime and connection count"); 221 sendnumeric(client, RPL_STATSHELP, "U - uline - Send the ulines block list"); 222 sendnumeric(client, RPL_STATSHELP, "v - denyver - Send the deny version block list"); 223 sendnumeric(client, RPL_STATSHELP, "V - vhost - Send the vhost block list"); 224 sendnumeric(client, RPL_STATSHELP, "W - fdtable - Send the FD table listing"); 225 sendnumeric(client, RPL_STATSHELP, "X - notlink - Send the list of servers that are not current linked"); 226 sendnumeric(client, RPL_STATSHELP, "Y - class - Send the class block list"); 227 } 228 229 static inline int allow_user_stats_short(char c) 230 { 231 char l; 232 if (!ALLOW_USER_STATS) 233 return 0; 234 if (strchr(ALLOW_USER_STATS, c)) 235 return 1; 236 l = tolower(c); 237 /* Hack for the flags that are case insensitive */ 238 if (l == 'o' || l == 'y' || l == 'k' || l == 'g' || l == 'x' || l == 'c' || 239 l =='f' || l == 'i' || l == 'h' || l == 'm') 240 { 241 if (islower(c) && strchr(ALLOW_USER_STATS, toupper(c))) 242 return 1; 243 else if (isupper(c) && strchr(ALLOW_USER_STATS, tolower(c))) 244 return 1; 245 } 246 /* Hack for c/C/H/h */ 247 if (l == 'c') 248 { 249 if (strpbrk(ALLOW_USER_STATS, "hH")) 250 return 1; 251 } else if (l == 'h') 252 if (strpbrk(ALLOW_USER_STATS, "cC")) 253 return 1; 254 return 0; 255 } 256 257 static inline int allow_user_stats_long(const char *s) 258 { 259 OperStat *os; 260 for (os = iConf.allow_user_stats_ext; os; os = os->next) 261 { 262 if (!strcasecmp(os->flag, s)) 263 return 1; 264 } 265 return 0; 266 } 267 268 /* This is pretty slow, but it isn't used often so it isn't a big deal */ 269 static inline char *allow_user_stats_long_to_short() 270 { 271 static char buffer[BUFSIZE+1]; 272 int i = 0; 273 OperStat *os; 274 for (os = iConf.allow_user_stats_ext; os; os = os->next) 275 { 276 struct statstab *stat = stats_search(os->flag); 277 if (!stat) 278 continue; 279 if (!strchr(ALLOW_USER_STATS, stat->flag)) 280 buffer[i++] = stat->flag; 281 } 282 buffer[i] = 0; 283 return buffer; 284 } 285 286 CMD_FUNC(cmd_stats) 287 { 288 struct statstab *stat; 289 char flags[2]; 290 291 if (parc == 3 && parv[2][0] != '+' && parv[2][0] != '-') 292 { 293 if (hunt_server(client, recv_mtags, "STATS", 2, parc, parv) != HUNTED_ISME) 294 return; 295 } 296 else if (parc == 4 && parv[2][0] != '+' && parv[2][0] != '-') 297 { 298 if (hunt_server(client, recv_mtags, "STATS", 2, parc, parv) != HUNTED_ISME) 299 return; 300 } 301 if (parc < 2 || !*parv[1]) 302 { 303 stats_help(client); 304 sendnumeric(client, RPL_ENDOFSTATS, '*'); 305 return; 306 } 307 308 /* Decide if we are looking for 1 char or a string */ 309 if (parv[1][0] && !parv[1][1]) 310 { 311 if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL) && !allow_user_stats_short(parv[1][0])) 312 { 313 sendnumeric(client, ERR_NOPRIVILEGES); 314 return; 315 } 316 /* Old style, we can use a binary search here */ 317 stat = stats_binary_search(parv[1][0]); 318 } 319 else 320 { 321 if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL) && !allow_user_stats_long(parv[1])) 322 { 323 sendnumeric(client, ERR_NOPRIVILEGES); 324 return; 325 } 326 /* New style, search the hard way */ 327 stat = stats_search(parv[1]); 328 } 329 330 if (!stat) 331 { 332 /* Not found. Perhaps a module provides it? */ 333 Hook *h; 334 int found = 0, n; 335 for (h = Hooks[HOOKTYPE_STATS]; h; h = h->next) 336 { 337 n = (*(h->func.intfunc))(client, parv[1]); 338 if (n == 1) 339 found = 1; 340 } 341 if (!found) 342 stats_help(client); 343 sendnumeric(client, RPL_ENDOFSTATS, '*'); 344 return; 345 } 346 347 flags[0] = stat->flag; 348 flags[1] = '\0'; 349 350 if (stat->options & FLAGS_AS_PARA) 351 { 352 if (parc > 2 && (parv[2][0] == '+' || parv[2][0] == '-')) 353 { 354 if (parc > 3) 355 stat->func(client, stats_combine_parv(parv[2],parv[3])); 356 else 357 stat->func(client, parv[2]); 358 } 359 else if (parc > 3) 360 stat->func(client, parv[3]); 361 else 362 stat->func(client, NULL); 363 } 364 else if (stat->options & SERVER_AS_PARA) 365 { 366 if (parc > 2) 367 stat->func(client, parv[2]); 368 else 369 stat->func(client, NULL); 370 } 371 else 372 stat->func(client, NULL); 373 374 /* Modules can append data: 375 * ('STATS S' already has special code for this that 376 * maintains certain ordering, so not included here) 377 */ 378 if (stat->flag != 'S') 379 { 380 RunHook(HOOKTYPE_STATS, client, flags); 381 } 382 383 sendnumeric(client, RPL_ENDOFSTATS, stat->flag); 384 } 385 386 int stats_banversion(Client *client, const char *para) 387 { 388 ConfigItem_ban *bans; 389 for (bans = conf_ban; bans; bans = bans->next) 390 { 391 if (bans->flag.type != CONF_BAN_VERSION) 392 continue; 393 sendnumeric(client, RPL_STATSBANVER, 394 bans->mask, bans->reason ? bans->reason : "No Reason"); 395 } 396 return 0; 397 } 398 399 int stats_links(Client *client, const char *para) 400 { 401 ConfigItem_link *link_p; 402 #ifdef DEBUGMODE 403 Client *acptr; 404 #endif 405 for (link_p = conf_link; link_p; link_p = link_p->next) 406 { 407 sendnumericfmt(client, RPL_STATSCLINE, "C - * %s %i %s %s%s%s", 408 link_p->servername, 409 link_p->outgoing.port, 410 link_p->class->name, 411 (link_p->outgoing.options & CONNECT_AUTO) ? "a" : "", 412 (link_p->outgoing.options & CONNECT_TLS) ? "S" : "", 413 (link_p->flag.temporary == 1) ? "T" : ""); 414 #ifdef DEBUGMODE 415 sendnotice(client, "%s (%p) has refcount %d", 416 link_p->servername, link_p, link_p->refcount); 417 #endif 418 if (link_p->hub) 419 sendnumericfmt(client, RPL_STATSHLINE, "H %s * %s", 420 link_p->hub, link_p->servername); 421 else if (link_p->leaf) 422 sendnumericfmt(client, RPL_STATSLLINE, "L %s * %s %d", 423 link_p->leaf, link_p->servername, link_p->leaf_depth); 424 } 425 #ifdef DEBUGMODE 426 list_for_each_entry(acptr, &client_list, client_node) 427 if (MyConnect(acptr) && acptr->server && !IsMe(acptr)) 428 { 429 if (!acptr->server->conf) 430 sendnotice(client, "client '%s' (%p) has NO CONF attached (? :P)", 431 acptr->name, acptr); 432 else 433 sendnotice(client, "client '%s' (%p) has conf %p attached, refcount: %d, temporary: %s", 434 acptr->name, acptr, 435 acptr->server->conf, 436 acptr->server->conf->refcount, 437 acptr->server->conf->flag.temporary ? "YES" : "NO"); 438 } 439 #endif 440 return 0; 441 } 442 443 int stats_gline(Client *client, const char *para) 444 { 445 int cnt = 0; 446 tkl_stats(client, TKL_GLOBAL|TKL_KILL, para, &cnt); 447 tkl_stats(client, TKL_GLOBAL|TKL_ZAP, para, &cnt); 448 return 0; 449 } 450 451 int stats_spamfilter(Client *client, const char *para) 452 { 453 int cnt = 0; 454 tkl_stats(client, TKL_SPAMF, para, &cnt); 455 tkl_stats(client, TKL_GLOBAL|TKL_SPAMF, para, &cnt); 456 return 0; 457 } 458 459 int stats_except(Client *client, const char *para) 460 { 461 int cnt = 0; 462 tkl_stats(client, TKL_EXCEPTION, para, &cnt); 463 tkl_stats(client, TKL_EXCEPTION|TKL_GLOBAL, para, &cnt); 464 return 0; 465 } 466 467 int stats_allow(Client *client, const char *para) 468 { 469 ConfigItem_allow *allows; 470 NameValuePrioList *m; 471 472 for (allows = conf_allow; allows; allows = allows->next) 473 { 474 for (m = allows->match->printable_list; m; m = m->next) 475 { 476 sendnumeric(client, RPL_STATSILINE, 477 namevalue_nospaces(m), "-", 478 allows->maxperip, 479 allows->global_maxperip, 480 allows->class->name, 481 allows->server ? allows->server : DEFAULT_SERVER, 482 allows->port ? allows->port : 6667); 483 } 484 } 485 return 0; 486 } 487 488 int stats_command(Client *client, const char *para) 489 { 490 int i; 491 RealCommand *mptr; 492 for (i = 0; i < 256; i++) 493 for (mptr = CommandHash[i]; mptr; mptr = mptr->next) 494 if (mptr->count) 495 sendnumeric(client, RPL_STATSCOMMANDS, mptr->cmd, 496 mptr->count, mptr->bytes); 497 498 return 0; 499 } 500 501 int stats_oper(Client *client, const char *para) 502 { 503 ConfigItem_oper *o; 504 NameValuePrioList *m; 505 506 for (o = conf_oper; o; o = o->next) 507 { 508 for (m = o->match->printable_list; m; m = m->next) 509 { 510 sendnumeric(client, RPL_STATSOLINE, 511 'O', namevalue_nospaces(m), o->name, 512 o->operclass ? o->operclass: "", 513 o->class->name ? o->class->name : ""); 514 } 515 } 516 return 0; 517 } 518 519 static char *stats_port_helper(ConfigItem_listen *listener) 520 { 521 static char buf[256]; 522 523 ircsnprintf(buf, sizeof(buf), "%s%s%s", 524 (listener->options & LISTENER_CLIENTSONLY)? "clientsonly ": "", 525 (listener->options & LISTENER_SERVERSONLY)? "serversonly ": "", 526 (listener->options & LISTENER_DEFER_ACCEPT)? "defer-accept ": ""); 527 528 /* And one of these.. */ 529 if (listener->options & LISTENER_CONTROL) 530 strlcat(buf, "control ", sizeof(buf)); 531 else if (listener->socket_type == SOCKET_TYPE_UNIX) 532 ; 533 else if (listener->options & LISTENER_TLS) 534 strlcat(buf, "tls ", sizeof(buf)); 535 else 536 strlcat(buf, "plaintext ", sizeof(buf)); 537 return buf; 538 } 539 540 int stats_port(Client *client, const char *para) 541 { 542 ConfigItem_listen *listener; 543 544 for (listener = conf_listen; listener != NULL; listener = listener->next) 545 { 546 if (!(listener->options & LISTENER_BOUND)) 547 continue; 548 if ((listener->options & LISTENER_SERVERSONLY) && !ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL)) 549 continue; 550 if (listener->socket_type == SOCKET_TYPE_UNIX) 551 { 552 sendnotice(client, "*** Listener on %s (UNIX): has %i client(s), options: %s %s", 553 listener->file, 554 listener->clients, 555 stats_port_helper(listener), 556 listener->flag.temporary ? "[TEMPORARY]" : ""); 557 } else { 558 sendnotice(client, "*** Listener on %s:%i (%s): has %i client(s), options: %s %s", 559 listener->ip, 560 listener->port, 561 listener->socket_type == SOCKET_TYPE_IPV6 ? "IPv6" : "IPv4", 562 listener->clients, 563 stats_port_helper(listener), 564 listener->flag.temporary ? "[TEMPORARY]" : ""); 565 } 566 } 567 return 0; 568 } 569 570 int stats_bannick(Client *client, const char *para) 571 { 572 int cnt = 0; 573 tkl_stats(client, TKL_NAME, para, &cnt); 574 tkl_stats(client, TKL_GLOBAL|TKL_NAME, para, &cnt); 575 return 0; 576 } 577 578 int stats_traffic(Client *client, const char *para) 579 { 580 Client *acptr; 581 IRCStatistics *sp; 582 IRCStatistics tmp; 583 time_t now = TStime(); 584 585 sp = &tmp; 586 memcpy(sp, &ircstats, sizeof(IRCStatistics)); 587 588 list_for_each_entry(acptr, &lclient_list, lclient_node) 589 { 590 if (IsServer(acptr)) 591 { 592 sp->is_sti += now - acptr->local->creationtime; 593 sp->is_sv++; 594 } 595 else if (IsUser(acptr)) 596 { 597 sp->is_cti += now - acptr->local->creationtime; 598 sp->is_cl++; 599 } 600 else if (IsUnknown(acptr)) 601 sp->is_ni++; 602 } 603 604 sendnumericfmt(client, RPL_STATSDEBUG, "accepts %u refused %u", sp->is_ac, sp->is_ref); 605 sendnumericfmt(client, RPL_STATSDEBUG, "unknown commands %u prefixes %u", sp->is_unco, sp->is_unpf); 606 sendnumericfmt(client, RPL_STATSDEBUG, "nick collisions %u unknown closes %u", sp->is_kill, sp->is_ni); 607 sendnumericfmt(client, RPL_STATSDEBUG, "wrong direction %u empty %u", sp->is_wrdi, sp->is_empt); 608 sendnumericfmt(client, RPL_STATSDEBUG, "numerics seen %u mode fakes %u", sp->is_num, sp->is_fake); 609 sendnumericfmt(client, RPL_STATSDEBUG, "auth successes %u fails %u", sp->is_asuc, sp->is_abad); 610 sendnumericfmt(client, RPL_STATSDEBUG, "local connections %u udp packets %u", sp->is_loc, sp->is_udp); 611 sendnumericfmt(client, RPL_STATSDEBUG, "Client Server"); 612 sendnumericfmt(client, RPL_STATSDEBUG, "connected %u %u", sp->is_cl, sp->is_sv); 613 sendnumericfmt(client, RPL_STATSDEBUG, "messages sent %lld", me.local->traffic.messages_sent); 614 sendnumericfmt(client, RPL_STATSDEBUG, "messages received %lld", me.local->traffic.messages_received); 615 sendnumericfmt(client, RPL_STATSDEBUG, "bytes sent %lld", me.local->traffic.bytes_sent); 616 sendnumericfmt(client, RPL_STATSDEBUG, "bytes received %lld", me.local->traffic.bytes_received); 617 sendnumericfmt(client, RPL_STATSDEBUG, "time connected %lld %lld", 618 (long long)sp->is_cti, (long long)sp->is_sti); 619 620 return 0; 621 } 622 623 int stats_fdtable(Client *client, const char *para) 624 { 625 int i; 626 627 for (i = 0; i < MAXCONNECTIONS; i++) 628 { 629 FDEntry *fde = &fd_table[i]; 630 631 if (!fde->is_open) 632 continue; 633 634 sendnumericfmt(client, RPL_STATSDEBUG, 635 "fd %3d, desc '%s', read-hdl %p, write-hdl %p, cbdata %p", 636 fde->fd, fde->desc, fde->read_callback, fde->write_callback, fde->data); 637 } 638 639 return 0; 640 } 641 642 int stats_uline(Client *client, const char *para) 643 { 644 ConfigItem_ulines *ulines; 645 for (ulines = conf_ulines; ulines; ulines = ulines->next) 646 sendnumeric(client, RPL_STATSULINE, ulines->servername); 647 return 0; 648 } 649 int stats_vhost(Client *client, const char *para) 650 { 651 ConfigItem_vhost *vhosts; 652 NameValuePrioList *m; 653 654 for (vhosts = conf_vhost; vhosts; vhosts = vhosts->next) 655 { 656 for (m = vhosts->match->printable_list; m; m = m->next) 657 { 658 sendtxtnumeric(client, "vhost %s%s%s %s %s", 659 vhosts->virtuser ? vhosts->virtuser : "", 660 vhosts->virtuser ? "@" : "", 661 vhosts->virthost, 662 vhosts->login, 663 namevalue_nospaces(m)); 664 } 665 } 666 return 0; 667 } 668 669 int stats_kline(Client *client, const char *para) 670 { 671 int cnt = 0; 672 tkl_stats(client, TKL_KILL, NULL, &cnt); 673 tkl_stats(client, TKL_ZAP, NULL, &cnt); 674 return 0; 675 } 676 677 int stats_banrealname(Client *client, const char *para) 678 { 679 ConfigItem_ban *bans; 680 for (bans = conf_ban; bans; bans = bans->next) 681 { 682 if (bans->flag.type == CONF_BAN_REALNAME) 683 { 684 sendnumeric(client, RPL_STATSNLINE, bans->mask, bans->reason 685 ? bans->reason : "<no reason>"); 686 } 687 } 688 return 0; 689 } 690 691 int stats_sqline(Client *client, const char *para) 692 { 693 int cnt = 0; 694 tkl_stats(client, TKL_NAME|TKL_GLOBAL, para, &cnt); 695 return 0; 696 } 697 698 int stats_chanrestrict(Client *client, const char *para) 699 { 700 ConfigItem_deny_channel *dchans; 701 ConfigItem_allow_channel *achans; 702 for (dchans = conf_deny_channel; dchans; dchans = dchans->next) 703 { 704 sendtxtnumeric(client, "deny %s %c %s", dchans->channel, dchans->warn ? 'w' : '-', dchans->reason); 705 } 706 for (achans = conf_allow_channel; achans; achans = achans->next) 707 { 708 sendtxtnumeric(client, "allow %s", achans->channel); 709 } 710 return 0; 711 } 712 713 int stats_shun(Client *client, const char *para) 714 { 715 int cnt = 0; 716 tkl_stats(client, TKL_GLOBAL|TKL_SHUN, para, &cnt); 717 return 0; 718 } 719 720 /* should this be moved to a seperate stats flag? */ 721 int stats_officialchannels(Client *client, const char *para) 722 { 723 ConfigItem_offchans *x; 724 725 for (x = conf_offchans; x; x = x->next) 726 { 727 sendtxtnumeric(client, "%s %s", x->name, x->topic ? x->topic : ""); 728 } 729 return 0; 730 } 731 732 #define SafePrint(x) ((x) ? (x) : "") 733 734 /** Helper for stats_set() */ 735 static void stats_set_anti_flood(Client *client, FloodSettings *f) 736 { 737 int i; 738 739 for (i=0; floodoption_names[i]; i++) 740 { 741 if (i == FLD_CONVERSATIONS) 742 { 743 sendtxtnumeric(client, "anti-flood::%s::%s: %d users, new user every %s", 744 f->name, floodoption_names[i], 745 (int)f->limit[i], pretty_time_val(f->period[i])); 746 } 747 if (i == FLD_LAG_PENALTY) 748 { 749 sendtxtnumeric(client, "anti-flood::%s::lag-penalty: %d msec", 750 f->name, (int)f->period[i]); 751 sendtxtnumeric(client, "anti-flood::%s::lag-penalty-bytes: %d", 752 f->name, 753 f->limit[i] == INT_MAX ? 0 : (int)f->limit[i]); 754 } 755 else 756 { 757 sendtxtnumeric(client, "anti-flood::%s::%s: %d per %s", 758 f->name, floodoption_names[i], 759 (int)f->limit[i], pretty_time_val(f->period[i])); 760 } 761 } 762 } 763 764 int stats_set(Client *client, const char *para) 765 { 766 char *uhallow; 767 SecurityGroup *s; 768 FloodSettings *f; 769 char modebuf[BUFSIZE], parabuf[BUFSIZE]; 770 771 if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL)) 772 { 773 sendnumeric(client, ERR_NOPRIVILEGES); 774 return 0; 775 } 776 777 sendtxtnumeric(client, "*** Configuration Report ***"); 778 sendtxtnumeric(client, "network-name: %s", NETWORK_NAME); 779 sendtxtnumeric(client, "default-server: %s", DEFAULT_SERVER); 780 if (SERVICES_NAME) 781 { 782 sendtxtnumeric(client, "services-server: %s", SERVICES_NAME); 783 } 784 if (STATS_SERVER) 785 { 786 sendtxtnumeric(client, "stats-server: %s", STATS_SERVER); 787 } 788 if (SASL_SERVER) 789 { 790 sendtxtnumeric(client, "sasl-server: %s", SASL_SERVER); 791 } 792 sendtxtnumeric(client, "cloak-prefix: %s", CLOAK_PREFIX); 793 sendtxtnumeric(client, "help-channel: %s", HELP_CHANNEL); 794 sendtxtnumeric(client, "cloak-keys: %s", CLOAK_KEY_CHECKSUM); 795 sendtxtnumeric(client, "kline-address: %s", KLINE_ADDRESS); 796 if (GLINE_ADDRESS) 797 sendtxtnumeric(client, "gline-address: %s", GLINE_ADDRESS); 798 sendtxtnumeric(client, "modes-on-connect: %s", get_usermode_string_raw(CONN_MODES)); 799 sendtxtnumeric(client, "modes-on-oper: %s", get_usermode_string_raw(OPER_MODES)); 800 *modebuf = *parabuf = 0; 801 chmode_str(&iConf.modes_on_join, modebuf, parabuf, sizeof(modebuf), sizeof(parabuf)); 802 sendtxtnumeric(client, "modes-on-join: %s %s", modebuf, parabuf); 803 if (iConf.min_nick_length) 804 sendtxtnumeric(client, "min-nick-length: %i", iConf.min_nick_length); 805 sendtxtnumeric(client, "nick-length: %i", iConf.nick_length); 806 sendtxtnumeric(client, "snomask-on-oper: %s", OPER_SNOMASK); 807 if (ALLOW_USER_STATS) 808 { 809 char *longflags = allow_user_stats_long_to_short(); 810 sendtxtnumeric(client, "allow-user-stats: %s%s", ALLOW_USER_STATS, longflags ? longflags : ""); 811 } 812 if (RESTRICT_USERMODES) 813 sendtxtnumeric(client, "restrict-usermodes: %s", RESTRICT_USERMODES); 814 if (RESTRICT_CHANNELMODES) 815 sendtxtnumeric(client, "restrict-channelmodes: %s", RESTRICT_CHANNELMODES); 816 if (RESTRICT_EXTENDEDBANS) 817 sendtxtnumeric(client, "restrict-extendedbans: %s", RESTRICT_EXTENDEDBANS); 818 switch (UHOST_ALLOWED) 819 { 820 case UHALLOW_NEVER: 821 uhallow = "never"; 822 break; 823 case UHALLOW_NOCHANS: 824 uhallow = "not-on-channels"; 825 break; 826 case UHALLOW_REJOIN: 827 uhallow = "force-rejoin"; 828 break; 829 case UHALLOW_ALWAYS: 830 default: 831 uhallow = "always"; 832 break; 833 } 834 if (uhallow) 835 sendtxtnumeric(client, "allow-userhost-change: %s", uhallow); 836 sendtxtnumeric(client, "hide-ban-reason: %d", HIDE_BAN_REASON); 837 sendtxtnumeric(client, "anti-spam-quit-message-time: %s", pretty_time_val(ANTI_SPAM_QUIT_MSG_TIME)); 838 sendtxtnumeric(client, "channel-command-prefix: %s", CHANCMDPFX ? CHANCMDPFX : "`"); 839 sendtxtnumeric(client, "tls::certificate: %s", SafePrint(iConf.tls_options->certificate_file)); 840 sendtxtnumeric(client, "tls::key: %s", SafePrint(iConf.tls_options->key_file)); 841 sendtxtnumeric(client, "tls::trusted-ca-file: %s", SafePrint(iConf.tls_options->trusted_ca_file)); 842 sendtxtnumeric(client, "tls::options: %s", iConf.tls_options->options & TLSFLAG_FAILIFNOCERT ? "FAILIFNOCERT" : ""); 843 sendtxtnumeric(client, "options::show-opermotd: %d", SHOWOPERMOTD); 844 sendtxtnumeric(client, "options::hide-ulines: %d", HIDE_ULINES); 845 sendtxtnumeric(client, "options::identd-check: %d", IDENT_CHECK); 846 sendtxtnumeric(client, "options::fail-oper-warn: %d", FAILOPER_WARN); 847 sendtxtnumeric(client, "options::show-connect-info: %d", SHOWCONNECTINFO); 848 sendtxtnumeric(client, "options::no-connect-tls-info: %d", NOCONNECTTLSLINFO); 849 sendtxtnumeric(client, "options::dont-resolve: %d", DONT_RESOLVE); 850 sendtxtnumeric(client, "options::mkpasswd-for-everyone: %d", MKPASSWD_FOR_EVERYONE); 851 sendtxtnumeric(client, "options::allow-insane-bans: %d", ALLOW_INSANE_BANS); 852 sendtxtnumeric(client, "options::allow-part-if-shunned: %d", ALLOW_PART_IF_SHUNNED); 853 sendtxtnumeric(client, "maxchannelsperuser: %i", MAXCHANNELSPERUSER); 854 sendtxtnumeric(client, "ping-warning: %i seconds", PINGWARNING); 855 sendtxtnumeric(client, "auto-join: %s", AUTO_JOIN_CHANS ? AUTO_JOIN_CHANS : "0"); 856 sendtxtnumeric(client, "oper-auto-join: %s", OPER_AUTO_JOIN_CHANS ? OPER_AUTO_JOIN_CHANS : "0"); 857 sendtxtnumeric(client, "static-quit: %s", STATIC_QUIT ? STATIC_QUIT : "<none>"); 858 sendtxtnumeric(client, "static-part: %s", STATIC_PART ? STATIC_PART : "<none>"); 859 sendtxtnumeric(client, "who-limit: %d", WHOLIMIT); 860 sendtxtnumeric(client, "silence-limit: %d", SILENCE_LIMIT); 861 sendtxtnumeric(client, "ban-version-tkl-time: %s", pretty_time_val(BAN_VERSION_TKL_TIME)); 862 if (LINK_BINDIP) 863 sendtxtnumeric(client, "link::bind-ip: %s", LINK_BINDIP); 864 sendtxtnumeric(client, "anti-flood::connect-flood: %d per %s", THROTTLING_COUNT, pretty_time_val(THROTTLING_PERIOD)); 865 sendtxtnumeric(client, "anti-flood::handshake-data-flood::amount: %ld bytes", iConf.handshake_data_flood_amount); 866 sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-action: %s", banact_valtostring(iConf.handshake_data_flood_ban_action)); 867 sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-time: %s", pretty_time_val(iConf.handshake_data_flood_ban_time)); 868 869 /* set::anti-flood */ 870 for (s = securitygroups; s; s = s->next) 871 if ((f = find_floodsettings_block(s->name))) 872 stats_set_anti_flood(client, f); 873 f = find_floodsettings_block("unknown-users"); 874 stats_set_anti_flood(client, f); 875 876 //if (AWAY_PERIOD) 877 // sendtxtnumeric(client, "anti-flood::away-flood: %d per %s", AWAY_COUNT, pretty_time_val(AWAY_PERIOD)); 878 //sendtxtnumeric(client, "anti-flood::nick-flood: %d per %s", NICK_COUNT, pretty_time_val(NICK_PERIOD)); 879 sendtxtnumeric(client, "handshake-timeout: %s", pretty_time_val(iConf.handshake_timeout)); 880 sendtxtnumeric(client, "sasl-timeout: %s", pretty_time_val(iConf.sasl_timeout)); 881 sendtxtnumeric(client, "ident::connect-timeout: %s", pretty_time_val(IDENT_CONNECT_TIMEOUT)); 882 sendtxtnumeric(client, "ident::read-timeout: %s", pretty_time_val(IDENT_READ_TIMEOUT)); 883 sendtxtnumeric(client, "spamfilter::ban-time: %s", pretty_time_val(SPAMFILTER_BAN_TIME)); 884 sendtxtnumeric(client, "spamfilter::ban-reason: %s", SPAMFILTER_BAN_REASON); 885 sendtxtnumeric(client, "spamfilter::virus-help-channel: %s", SPAMFILTER_VIRUSCHAN); 886 if (SPAMFILTER_EXCEPT) 887 sendtxtnumeric(client, "spamfilter::except: %s", SPAMFILTER_EXCEPT); 888 sendtxtnumeric(client, "check-target-nick-bans: %s", CHECK_TARGET_NICK_BANS ? "yes" : "no"); 889 sendtxtnumeric(client, "plaintext-policy::user: %s", policy_valtostr(iConf.plaintext_policy_user)); 890 sendtxtnumeric(client, "plaintext-policy::oper: %s", policy_valtostr(iConf.plaintext_policy_oper)); 891 sendtxtnumeric(client, "plaintext-policy::server: %s", policy_valtostr(iConf.plaintext_policy_server)); 892 sendtxtnumeric(client, "outdated-tls-policy::user: %s", policy_valtostr(iConf.outdated_tls_policy_user)); 893 sendtxtnumeric(client, "outdated-tls-policy::oper: %s", policy_valtostr(iConf.outdated_tls_policy_oper)); 894 sendtxtnumeric(client, "outdated-tls-policy::server: %s", policy_valtostr(iConf.outdated_tls_policy_server)); 895 RunHook(HOOKTYPE_STATS, client, "S"); 896 #ifndef _WIN32 897 sendtxtnumeric(client, "This server can handle %d concurrent sockets (%d clients + %d reserve)", 898 maxclients+CLIENTS_RESERVE, maxclients, CLIENTS_RESERVE); 899 #endif 900 return 1; 901 } 902 903 int stats_tld(Client *client, const char *para) 904 { 905 ConfigItem_tld *tld; 906 NameValuePrioList *m; 907 908 for (tld = conf_tld; tld; tld = tld->next) 909 { 910 for (m = tld->match->printable_list; m; m = m->next) 911 { 912 sendnumeric(client, RPL_STATSTLINE, namevalue_nospaces(m), 913 tld->motd_file, 914 tld->rules_file ? tld->rules_file : "none"); 915 } 916 } 917 918 return 0; 919 } 920 921 int stats_uptime(Client *client, const char *para) 922 { 923 long long uptime; 924 925 uptime = TStime() - me.local->fake_lag; 926 sendnumeric(client, RPL_STATSUPTIME, 927 uptime / 86400, (uptime / 3600) % 24, (uptime / 60) % 60, 928 uptime % 60); 929 sendnumeric(client, RPL_STATSCONN, 930 max_connection_count, irccounts.me_max); 931 return 0; 932 } 933 934 int stats_denyver(Client *client, const char *para) 935 { 936 ConfigItem_deny_version *versions; 937 for (versions = conf_deny_version; versions; versions = versions->next) 938 { 939 sendnumeric(client, RPL_STATSVLINE, 940 versions->version, versions->flags, versions->mask); 941 } 942 return 0; 943 } 944 945 int stats_notlink(Client *client, const char *para) 946 { 947 ConfigItem_link *link_p; 948 949 for (link_p = conf_link; link_p; link_p = link_p->next) 950 { 951 if (!find_server_quick(link_p->servername)) 952 { 953 sendnumeric(client, RPL_STATSXLINE, link_p->servername, 954 link_p->outgoing.port); 955 } 956 } 957 return 0; 958 } 959 960 int stats_class(Client *client, const char *para) 961 { 962 ConfigItem_class *classes; 963 964 for (classes = conf_class; classes; classes = classes->next) 965 { 966 sendnumeric(client, RPL_STATSYLINE, classes->name, classes->pingfreq, classes->connfreq, 967 classes->maxclients, classes->sendq, classes->recvq ? classes->recvq : DEFAULT_RECVQ); 968 #ifdef DEBUGMODE 969 sendnotice(client, "class '%s' has clients=%d, xrefcount=%d", 970 classes->name, classes->clients, classes->xrefcount); 971 #endif 972 } 973 return 0; 974 } 975 976 int stats_linkinfo(Client *client, const char *para) 977 { 978 return stats_linkinfoint(client, para, 0); 979 } 980 981 int stats_linkinfoall(Client *client, const char *para) 982 { 983 return stats_linkinfoint(client, para, 1); 984 } 985 986 int stats_linkinfoint(Client *client, const char *para, int all) 987 { 988 int remote = 0; 989 int wilds = 0; 990 int doall = 0; 991 Client *acptr; 992 993 /* 994 * send info about connections which match, or all if the 995 * mask matches me.name. Only restrictions are on those who 996 * are invisible not being visible to 'foreigners' who use 997 * a wild card based search to list it. 998 */ 999 if (para) 1000 { 1001 if (!mycmp(para, me.name)) 1002 doall = 2; 1003 else if (match_simple(para, me.name)) 1004 doall = 1; 1005 if (strchr(para, '*') || strchr(para, '?')) 1006 wilds = 1; 1007 } 1008 else 1009 para = me.name; 1010 1011 sendnumericfmt(client, RPL_STATSLINKINFO, "Name SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle"); 1012 1013 if (!MyUser(client)) 1014 { 1015 remote = 1; 1016 wilds = 0; 1017 } 1018 1019 list_for_each_entry(acptr, &lclient_list, lclient_node) 1020 { 1021 if (IsInvisible(acptr) && (doall || wilds) && 1022 !IsOper(acptr) && (acptr != client)) 1023 continue; 1024 if (remote && doall && !IsServer(acptr) && !IsMe(acptr)) 1025 continue; 1026 if (remote && !doall && IsServer(acptr)) 1027 continue; 1028 if (!doall && wilds && !match_simple(para, acptr->name)) 1029 continue; 1030 if (!(para && (IsServer(acptr) || IsListening(acptr))) && 1031 !(doall || wilds) && 1032 mycmp(para, acptr->name)) 1033 { 1034 continue; 1035 } 1036 1037 sendnumericfmt(client, RPL_STATSLINKINFO, 1038 "%s%s %lld %lld %lld %lld %lld %lld :%lld", 1039 acptr->name, get_client_status(acptr), 1040 (long long)DBufLength(&acptr->local->sendQ), 1041 (long long)acptr->local->traffic.messages_sent, 1042 (long long)acptr->local->traffic.bytes_sent, 1043 (long long)acptr->local->traffic.messages_received, 1044 (long long)acptr->local->traffic.bytes_received, 1045 (long long)(TStime() - acptr->local->creationtime), 1046 (long long)(TStime() - acptr->local->last_msg_received)); 1047 } 1048 #ifdef DEBUGMODE 1049 list_for_each_entry(acptr, &client_list, client_node) 1050 { 1051 if (IsServer(acptr)) 1052 sendnotice(client, "Server %s is %s", 1053 acptr->name, acptr->server->flags.synced ? "SYNCED" : "NOT SYNCED!!"); 1054 } 1055 #endif 1056 return 0; 1057 }