Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

m_stats.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: m_stats.c,v 1.106.2.4 2005/05/06 22:57:41 amcwilliam Exp $
 */

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "h.h"
#include "memory.h"
#include "res.h"
#include "fd.h"
#include "hook.h"
#include "modules.h"
#include "xmode.h"
#include "conf2.h"
#include "user_ban.h"
#include "zlink.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

Hook *h_stats = NULL;

Module MOD_HEADER(m_stats) = {
      "m_stats",
      "/STATS command",
      6, "$Revision: 1.106.2.4 $"
};

int MOD_LOAD(m_stats)()
{
      if ((h_stats = register_hook(&MOD_HEADER(m_stats), "h_stats")) == NULL) {
            return MOD_FAILURE;
      }
      if (register_command(&MOD_HEADER(m_stats), &CMD_STATS, m_stats) == NULL) {
            return MOD_FAILURE;
      }
      return MOD_SUCCESS;
}

int MOD_UNLOAD(m_stats)()
{
      return MOD_SUCCESS;
}

static void stats_kill_net(aClient *, char *);
static void stats_adns(aClient *, char *);
static void stats_bandwidth(aClient *, char *);
static void stats_link(aClient *, char *);
static void stats_restrict_file(aClient *, char *);
static void stats_event(aClient *, char *);
static void stats_restrict_gcos_loc(aClient *, char *);
static void stats_restrict_gcos_net(aClient *, char *);
static void stats_hook(aClient *, char *);
static void stats_allow(aClient *, char *);
static void stats_iphash(aClient *, char *);
static void stats_kill_perm(aClient *, char *);
static void stats_kill_temp(aClient *, char *);
static void stats_linkinfo(aClient *, char *);
static void stats_modules(aClient *, char *);
static void stats_command(aClient *, char *);
static void stats_usercount(aClient *, char *);
static void stats_oper(aClient *, char *);
static void stats_listener(aClient *, char *);
static void stats_restrict_nick_loc(aClient *, char *);
static void stats_restrict_nick_net(aClient *, char *);
static void stats_rusage(aClient *, char *);
static void stats_scache(aClient *, char *);
static void stats_throttle(aClient *, char *);
static void stats_server(aClient *, char *);
static void stats_super(aClient *, char *);
static void stats_uptime(aClient *, char *);
static void stats_class(aClient *, char *);
static void stats_memory(aClient *, char *);

/* These are some ugly (but useful) macros for stats_bandwidth() */
#define _1MEG           (1024.0)
#define _1GIG           (1024.0 * 1024.0)
#define _1TER           (1024.0 * 1024.0 * 1024.0)
#define _GMKs(x)  ((x > _1TER) ? "Terabytes" : \
                        ((x > _1GIG) ? "Gigabytes" : \
                              ((x > _1MEG) ? "Megabytes" : "Kilobytes")))
#define _GMKS(x)  ((x > _1TER) ? "TB" : \
                        ((x > _1GIG) ? "GB" : \
                              ((x > _1MEG) ? "MB" : "KB")))
#define _GMKv(x)  ((x > _1TER) ? (float)(x / _1TER) : \
                        ((x > _1GIG) ? (float)(x / _1GIG) : \
                              ((x > _1MEG) ? (float)(x / _1MEG) : (float)x)))

static StatsRequest stats_table[] = {
      { 'A',      0,    stats_kill_net,         STATS_OPERONLY,         "List network k-lines (autokills)" },
      { 0,  'a',  stats_adns,       STATS_ADMINONLY,  "List resolver name servers" },
      { 'B',      'b',  stats_bandwidth,  STATS_PACESIMPLE, "Show bandwidth statistics" },
      { 'C',      'c',  stats_link,       STATS_PACESIMPLE, "List link config" },
      { 'D',      'd',  stats_restrict_file,    STATS_PACEINTENSE,      "List restricted files (DCC block)" },
      { 'E',      'e',  stats_event,            STATS_ADMINONLY,  "List internal events" },
      { 'G',      0,    stats_restrict_gcos_loc,STATS_OPERONLY,         "List local gcos restrictions" },
      { 0,  'g',  stats_restrict_gcos_net,STATS_OPERONLY,         "List network gcos restrictions" },
      { 'H',      'h',  stats_hook,       STATS_ADMINONLY,  "List internal hooks" },
      { 'I',      0,    stats_allow,            STATS_PACESIMPLE, "List allow config" },
      { 0,  'i',  stats_iphash,           STATS_OPERONLY,         "List hashed IP addresses" },
      { 'K',      0,    stats_kill_perm,  STATS_OPERONLY,         "List permanent k-lines" },
      { 0,  'k',  stats_kill_temp,  STATS_OPERONLY,         "List temporary k-lines" },
      { 'L',      'l',  stats_linkinfo,         STATS_PACEINTENSE,      "List connected link details" },
      { 'M',      0,    stats_modules,          STATS_PACESIMPLE, "List loaded modules" },
      { 0,  'm',  stats_command,          STATS_PACEINTENSE,      "List server commands" },
      { 'N',      'n',  stats_usercount,  STATS_PACESIMPLE, "List user connection statistics" },
      { 'O',      'o',  stats_oper,       STATS_PACESIMPLE, "List server operators" },
      { 'P',      'p',  stats_listener,         STATS_PACESIMPLE, "List server ports (listeners)" },
      { 'Q',      0,    stats_restrict_nick_loc,STATS_OPERONLY,         "List local nick/chan restrictions" },
      { 0,  'q',  stats_restrict_nick_net,STATS_OPERONLY,         "List network nick/chan restrictions" },
      { 'R',      'r',  stats_rusage,           STATS_OPERONLY,         "List process resource usage" },
      { 'S',      's',  stats_scache,           STATS_OPERONLY,         "List server cache entries" },
      { 'T',      0,    stats_throttle,         STATS_OPERONLY,         "List throttle hash entries" },
      { 0,  't',  stats_server,           STATS_OPERONLY,         "List server statistics" },
      { 'U',      0,    stats_super,            STATS_PACESIMPLE, "List super servers" },
      { 0,  'u',  stats_uptime,           STATS_NONE,       "Show server uptime" },
      { 'Y',      'y',  stats_class,            STATS_PACESIMPLE, "List connection class config" },
      { 'Z',      'z',  stats_memory,           STATS_ADMINONLY,  "Show detailed memory statistics" },
      { 0,  0,    NULL,             0,                NULL }
};

static void stats_kill_net(aClient *sptr, char *unused)
{
      report_userbans_match_flags(sptr, BAN_NETWORK, 0);
}

static void stats_adns(aClient *sptr, char *unused)
{
      report_dns_nameservers(sptr);
}

static void stats_bandwidth(aClient *sptr, char *unused)
{
      char *format = "B :%s %u %u %u %u %u %u %u %s";
      unsigned long sendK = 0, receiveK = 0;
      time_t uptime;
      aClient *acptr;
      LocalClient *lcptr;
      int i = 0;
      dlink_node *node;

      DLINK_FOREACH_DATA(lserver_list.head, node, acptr, aClient) {
            if (GeneralConfig.hide_super_servers && IsULine(acptr) && !HasMode(sptr, UMODE_OPER)) {
                  continue;
            }

            i++;
            lcptr = acptr->localClient;

            sendK += lcptr->sendK;
            receiveK += lcptr->receiveK;

            send_me_numeric_buf(sptr, format, RPL_STATSLINKINFO,
                  get_client_name(acptr, HasMode(sptr, UMODE_RSTAFF) ? SHOW_IP : HIDE_IP),
                  SBufLength(&lcptr->sendQ),
                  lcptr->sendM, lcptr->sendK,
                  lcptr->receiveM, lcptr->receiveK,
                  (timeofday - acptr->firsttime), (timeofday - acptr->since),
                  CapTS(acptr) ? "TS" : "Non-TS");

            if (InputRC4(acptr) && OutputRC4(acptr)) {
                  send_me_debugNA(sptr, ":B  - RC4 Encrypted");
            }

#ifdef USE_ZLIB
            if (InputZIP(acptr)) {
                  unsigned long in_b, out_b;
                  double ratio;

                  zip_in_get_stats(acptr->serv->zip_in, &in_b, &out_b, &ratio);
                  if (out_b) {
                        send_me_debug(sptr, "B : - [I] Zip in %7.2f %s, out %7.2f %s (%3.2f%%)",
                              _GMKv(in_b / 1024.0), _GMKS(in_b / 1024.0), _GMKv(out_b / 1024.0),
                              _GMKS(out_b / 1024.0), ratio);
                  }
            }
            if (OutputZIP(acptr)) {
                  unsigned long in_b, out_b;
                  double ratio;

                  zip_out_get_stats(acptr->serv->zip_out, &in_b, &out_b, &ratio);
                  if (in_b) {
                        send_me_debug(sptr, "B : - [O] Zip in %7.2f %s, out %7.2f %s (%3.2f%%)",
                              _GMKv(in_b / 1024.0), _GMKS(in_b / 1024.0), _GMKv(out_b / 1024.0),
                              _GMKS(out_b / 1024.0), ratio);
                  }
            }
#endif /* USE_ZLIB */
      }

      send_me_debug(sptr, "B :%d total servers", i);
      send_me_debug(sptr, "B :Sent total : %7.2f %s", _GMKv(sendK), _GMKs(sendK));
      send_me_debug(sptr, "B :Recv total : %7.2f %s", _GMKv(receiveK), _GMKs(receiveK));

      uptime = (timeofday - me.since);
      send_me_debug(sptr, "B :Server send: %7.2f %s (%4.1fK/s total, %4.1fK/s current)",
            _GMKv(me.localClient->sendK), _GMKs(me.localClient->sendK),
            (float)((float)me.localClient->sendK/(float)uptime), Internal.curr_sendK);
      send_me_debug(sptr, "B :Server recv: %7.2f %s (%4.1fK/s total, %4.1fK/s current)",
            _GMKv(me.localClient->receiveK), _GMKs(me.localClient->receiveK),
            (float)((float)me.localClient->receiveK/(float)uptime), Internal.curr_recvK);
}

static void stats_link(aClient *sptr, char *unused)
{
      dlink_node *node;
      ConfigItem_link *linkp;

      if (GeneralConfig.hide_super_servers && !HasMode(sptr, UMODE_OPER)) {
            send_me_numericNA(sptr, ERR_NOPRIVILEGES);
            return;
      }
      DLINK_FOREACH_DATA(conf_link_list.head, node, linkp, ConfigItem_link) {
            send_me_numeric(sptr, RPL_STATSCLINE,
                  HasMode(sptr, UMODE_RSTAFF) ? linkp->host : HIDDEN_IP,
                  linkp->servername, linkp->port, linkp->class->name);
      }
}

static void stats_restrict_file(aClient *sptr, char *unused)
{
      report_simbans_match_flags(sptr, SBAN_FILE, 0);
}

static void stats_event(aClient *sptr, char *unused)
{
      show_events(sptr);
}

static void stats_restrict_gcos_loc(aClient *sptr, char *unused)
{
      report_simbans_match_flags(sptr, SBAN_GCOS|BAN_LOCAL, 0);
}

static void stats_restrict_gcos_net(aClient *sptr, char *unused)
{
      report_simbans_match_flags(sptr, SBAN_GCOS|BAN_NETWORK, 0);
}

static void stats_hook(aClient *sptr, char *unused)
{
      hook_report(sptr);
}

static void stats_allow(aClient *sptr, char *unused)
{
      dlink_node *node;
      ConfigItem_allow *allow;

      DLINK_FOREACH_PREV_DATA(conf_allow_list.tail, node, allow, ConfigItem_allow) {
            send_me_numeric(sptr, RPL_STATSILINE,
                  BadPtr(allow->ipaddr) ? "-" : allow->ipaddr,
                  BadPtr(allow->hostname) ? "-" : allow->hostname,
                  allow->max_per_ip, allow->class->name);
      }
}

static void stats_iphash(aClient *sptr, char *unused)
{
      list_ip_hash(sptr);
}

static void stats_kill_perm(aClient *sptr, char *unused)
{
      report_userbans_match_flags(sptr, BAN_LOCAL, BAN_TEMPORARY);
}

static void stats_kill_temp(aClient *sptr, char *unused)
{
      report_userbans_match_flags(sptr, BAN_LOCAL|BAN_TEMPORARY, 0);
}

static void stats_linkinfo(aClient *sptr, char *servermask)
{
      char *Sformat = "L :Name SendQ SendM SendBytes RcveM RcveBytes OpenSince Idle TS";
      char *Lformat = "L :%s %u %u %u %u %u %u %u %s";
      dlink_node *node;
      aClient *acptr;
      time_t sincetime;
      char *path;

      send_me_numeric_bufNA(sptr, Sformat, RPL_STATSLINKINFO);
      if (!BadPtr(servermask) && match(servermask, me.name) && !has_wilds(servermask)) {
            if (!MyConnect(sptr)) {
                  return;
            }
            if ((acptr = find_person(servermask, NULL)) == NULL) {
                  return;
            }

            ASSERT(acptr->localClient != NULL);

            sincetime = (acptr->since > timeofday) ? 0 : (timeofday - acptr->since);
            path = get_client_name(acptr, HasMode(sptr, UMODE_RSTAFF) ? SHOW_IP : HIDE_IP);

            send_me_numeric_buf(sptr, Lformat, RPL_STATSLINKINFO, path,
                  (int)SBufLength(&acptr->localClient->sendQ), (int)acptr->localClient->sendM,
                  (int)acptr->localClient->sendK, (int)acptr->localClient->receiveM,
                  (int)acptr->localClient->receiveK, (timeofday - acptr->firsttime),
                  sincetime, IsServer(acptr) ? CapTS(acptr) ? "TS" : "Non-TS" : "-");
            return;
      }

      DLINK_FOREACH_DATA(lserver_list.head, node, acptr, aClient) {
            if (GeneralConfig.hide_super_servers && IsULine(acptr) && !HasMode(sptr, UMODE_OPER)) {
                  continue;
            }

            sincetime = (acptr->since > timeofday) ? 0 : (timeofday - acptr->since);
            path = get_client_name(acptr, HIDE_IP);

            send_me_numeric_buf(sptr, Lformat, RPL_STATSLINKINFO, path,
                  (int)SBufLength(&acptr->localClient->sendQ), (int)acptr->localClient->sendM,
                  (int)acptr->localClient->sendK, (int)acptr->localClient->receiveM,
                  (int)acptr->localClient->receiveK, (timeofday - acptr->firsttime),
                  sincetime, IsServer(acptr) ? CapTS(acptr) ? "TS" : "Non-TS" : "-");
      }
}

static void stats_modules(aClient *sptr, char *unused)
{
      do_module_list(sptr);
}

static void stats_command(aClient *sptr, char *unused)
{
      int i;
      Command *cmd;

      for (i = 0; i < 256; i++) {
            for (cmd = command_table[i]; cmd != NULL; cmd = cmd->next) {
                  ASSERT(cmd->msg != NULL);
                  send_me_numeric(sptr, RPL_STATSCOMMANDS, cmd->msg->msg_str, cmd->count, cmd->bytes,
                        (!BadPtr(cmd->msg->tok_str)) ? cmd->msg->tok_str : "No Token");
            }
      }
}

static void stats_usercount(aClient *sptr, char *unused)
{
      send_me_numeric(sptr, RPL_STATSCOUNT, "User connects today: ", Count.today);
      send_me_numeric(sptr, RPL_STATSCOUNT, "User connects past week: ", Count.weekly);
      send_me_numeric(sptr, RPL_STATSCOUNT, "User connects past month: ", Count.monthly);
      send_me_numeric(sptr, RPL_STATSCOUNT, "User connects past year: ", Count.yearly);
}

static void stats_oper(aClient *sptr, char *unused)
{
      dlink_node *node;
      ConfigItem_oper *oper;
      int i;

      DLINK_FOREACH_DATA(conf_oper_list.head, node, oper, ConfigItem_oper) {
            if (!HasMode(sptr, UMODE_OPER)) {
                  send_me_numeric(sptr, RPL_STATSOLINE, "*", oper->name, oper->class->name);
                  continue;
            }

            for (i = 0; i < oper->from.host_count; i++) {
                  send_me_numeric(sptr, RPL_STATSOLINE, oper->from.hosts[i], oper->name,
                        oper->class->name);
            }
      }
}

static void stats_listener(aClient *sptr, char *unused)
{
      char *Sformat = "P :Name Clients TotalConnections SendM SendBytes RcvM RcvBytes Idle Options";
      char *Lformat = "P :%s %u %u %u %u %u %u %u (%s)";
      dlink_node *node;
      Listener *l;
      char *flags;

      send_me_numeric_bufNA(sptr, Sformat, RPL_STATSLINKINFO);
      DLINK_FOREACH_DATA(listener_list.head, node, l, Listener) {
            flags = get_listener_flags(l);
            send_me_numeric_buf(sptr, Lformat, RPL_STATSLINKINFO, get_listener_name(l), l->clients,
                  l->count, (int)l->sendM, (int)l->sendK, (int)l->receiveM, (int)l->receiveK,
                  (timeofday - l->lasttime), (flags != NULL) ? flags : "none");
      }
}

static void stats_restrict_nick_loc(aClient *sptr, char *unused)
{
      report_simbans_match_flags(sptr, SBAN_NICK|BAN_LOCAL, 0);
      report_simbans_match_flags(sptr, SBAN_CHAN|BAN_LOCAL, 0);
}

static void stats_restrict_nick_net(aClient *sptr, char *unused)
{
      report_simbans_match_flags(sptr, SBAN_NICK|BAN_NETWORK, 0);
      report_simbans_match_flags(sptr, SBAN_CHAN|BAN_NETWORK, 0);
}

static void stats_rusage(aClient *sptr, char *unused)
{
#ifdef DEBUGMODE
      send_usage(sptr);
#endif
}

static void stats_scache(aClient *sptr, char *unused)
{
      list_scache(sptr);
}

static void stats_throttle(aClient *sptr, char *unused)
{
#ifdef USE_THROTTLE
      throttle_stats(sptr);
#endif
}

static void stats_server(aClient *sptr, char *unused)
{
      serv_stats(sptr);
}

static void stats_super(aClient *sptr, char *unused)
{
      dlink_node *node;
      char *super;

      if (GeneralConfig.hide_super_servers && !HasMode(sptr, UMODE_OPER)) {
            send_me_numericNA(sptr, ERR_NOPRIVILEGES);
            return;
      }
      DLINK_FOREACH_DATA(conf_super_list.head, node, super, char) {
            send_me_numeric(sptr, RPL_STATSULINE, super);
      }
}

static void stats_uptime(aClient *sptr, char *unused)
{
      time_t now = timeofday - me.since;
      send_me_numeric(sptr, RPL_STATSUPTIME, (now / 86400), (now / 3600) % 24, (now / 60) % 60, now % 60);
      send_me_numeric(sptr, RPL_STATSCONN, Internal.max_con_count, Internal.max_cli_count, Count.cli_restart);
}

static void stats_class(aClient *sptr, char *unused)
{
      dlink_node *node;
      ConfigItem_class *class = NULL;

      DLINK_FOREACH_DATA(conf_class_list.head, node, class, ConfigItem_class) {
            send_me_numeric(sptr, RPL_STATSYLINE, class->name, class->ping_time,
                  GeneralConfig.auto_connect_freq, class->max_clients, class->sendq_length,
                  class->clients);
      }
}

static void stats_memory(aClient *sptr, char *unused)
{
      count_memory(sptr);
}

static int has_access(aClient *sptr, StatsRequest *sr)
{
      if ((sr->options & STATS_NETADMINONLY) && !HasMode(sptr, UMODE_NETADMIN)) {
            return 0;
      }
      if ((sr->options & STATS_ADMINONLY) && !HasMode(sptr, UMODE_ADMIN)) {
            return 0;
      }
      if ((sr->options & STATS_OPERONLY) && !HasMode(sptr, UMODE_OPER)) {
            return 0;
      }
      return 1;
}

/*
 * m_stats
 *    parv[0] = sender prefix
 *    parv[1] = stat
 *    parv[2] = server name
 */
int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
      static time_t last_used = 0L;
      StatsRequest *sr;
      char flag = (parc > 1 && !BadPtr(parv[1])) ? *parv[1] : '\0';
      char *para = (parc > 2 && !BadPtr(parv[2])) ? parv[2] : NULL;
      HookData hdata = HOOKDATA_INIT;

      if (parc < 2 || BadPtr(parv[1])) {
            send_me_numeric(sptr, ERR_NEEDMOREPARAMS, "STATS");
            return 0;
      }
      if (use_or_deliver(cptr, sptr, &CMD_STATS, "%s :%s", 2, parc, parv) != HUNTED_ISME) {
            return 0;
      }
      if (!MyClient(sptr) && GeneralConfig.ignore_remote_stats) {
            return 0;
      }

      for (sr = stats_table; sr->func != NULL && (flag != '\0'); sr++) {
            if ((sr->higher == flag) || (sr->lower == flag)) {
                  break;
            }
      }

      if (sr->func == NULL) {
            send_me_debugNA(sptr, "? :Flags   Details");

            for (sr = stats_table; sr->info != NULL; sr++) {
                  if (!has_access(sptr, sr)) {
                        continue;
                  }

                  if (sr->higher && sr->lower) {
                        send_me_debug(sptr, "? :%c %c     %s", sr->higher, sr->lower,
                              sr->info);
                  }
                  else {
                        send_me_debug(sptr, "? :%c       %s", sr->higher ? sr->higher : sr->lower,
                              sr->info);
                  }
            }

            send_me_numeric(sptr, RPL_ENDOFSTATS, flag);
            return 0;
      }
      
      hdata.cptr = cptr;
      hdata.sptr = sptr;
      hdata.v = (void *)sr;
      hdata.c = para;
      if (hook_run_until(h_stats, &hdata, FLUSH_BUFFER) == FLUSH_BUFFER) {
            return 0;
      }

      if (!HasMode(sptr, UMODE_OPER)) {
            time_t pace_wait = 0;

            if (sr->options & STATS_PACESIMPLE) {
                  pace_wait = FloodConfig.pace_wait_simple;
            }
            else if (sr->options & STATS_PACEINTENSE) {
                  pace_wait = FloodConfig.pace_wait_intense;
            }

            if (pace_wait && ((last_used + pace_wait) > timeofday)) {
                  send_me_numericNA(sptr, RPL_LOAD2HI);
                  return 0;
            }
            else {
                  last_used = timeofday;
            }

            if (GeneralConfig.spy_notices && IsPerson(sptr)) {
                  sendto_realops_lev(SPY_LEV, "STATS '%c' requested by %s (%s@%s) [%s]",
                        flag, sptr->name, sptr->username, MaskedHost(sptr),
                        sptr->user->server);
            }
      }

      if (!has_access(sptr, sr)) {
            send_me_numericNA(sptr, ERR_NOPRIVILEGES);
      }
      else {
            (*sr->func)(sptr, para);
      }

      send_me_numeric(sptr, RPL_ENDOFSTATS, flag);
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index