/* * Copyright (c) 2002 Erik Fears * Copyright (c) 2014-2021 ircd-hybrid development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "setup.h" #include #include #include #include #include #include #include /* getrlimit */ #include #include "irc.h" #include "log.h" #include "misc.h" #include "config.h" #include "stats.h" #include "opm_types.h" #include "opm_gettime.h" static time_t STATS_UPTIME; static unsigned int STATS_CONNECTIONS; static unsigned int STATS_DNSBLSENT; static struct StatsHash STATS_PROXIES[] = { { .type = OPM_TYPE_HTTP, .name = "HTTP" }, { .type = OPM_TYPE_HTTPPOST, .name = "HTTPPOST" }, { .type = OPM_TYPE_HTTPS, .name = "HTTPS" }, { .type = OPM_TYPE_HTTPSPOST, .name = "HTTPSPOST" }, { .type = OPM_TYPE_SOCKS4, .name = "SOCKS4" }, { .type = OPM_TYPE_SOCKS5, .name = "SOCKS5" }, { .type = OPM_TYPE_ROUTER, .name = "ROUTER" }, { .type = OPM_TYPE_WINGATE, .name = "WINGATE" }, { .type = OPM_TYPE_DREAMBOX, .name = "DREAMBOX" }, { .type = OPM_TYPE_SSH, .name = "SSH" }, { .type = 0 } }; /* stats_init * * Perform initialization of HOPM stats * * Parameters: NONE * Return: NONE * */ void stats_init(void) { STATS_UPTIME = opm_gettime(); } /* stats_openproxy * * Record open proxy. * * * Parameters: NONE * Return: NONE * */ void stats_openproxy(unsigned int type) { for (struct StatsHash *tab = STATS_PROXIES; tab->name; ++tab) { if (tab->type == type) { ++tab->count; break; } } } /* stats_connect * * Record IRC connect. * * * Parameters: NONE * Return: NONE * */ void stats_connect(void) { ++STATS_CONNECTIONS; } /* stats_dnsblrecv * * Record that a user was found in the blacklist. * * Parameters: BlacklistConf structure * Return: NONE * */ void stats_dnsblrecv(struct BlacklistConf *bl) { ++bl->stats_recv; } /* stats_dnsblsend * * Record a sent report * * Parameters: NONE * Return: NONE * */ void stats_dnsblsend(void) { ++STATS_DNSBLSENT; } /* stats_output * * Output stats to target via privmsg * * * Parameters: NONE * Return: NONE * */ void stats_output(const char *target) { time_t uptime = opm_gettime() - STATS_UPTIME; node_t *p; irc_send("PRIVMSG %s :Uptime: %s", target, time_dissect(uptime)); LIST_FOREACH(p, OpmItem.blacklists.head) { const struct BlacklistConf *bl = p->data; if (bl->stats_recv) irc_send("PRIVMSG %s :DNSBL: %u successful lookups from %s", target, bl->stats_recv, bl->name); } if (STATS_DNSBLSENT) irc_send("PRIVMSG %s :DNSBL: %u reports sent", target, STATS_DNSBLSENT); for (const struct StatsHash *tab = STATS_PROXIES; tab->name; ++tab) if (tab->count) irc_send("PRIVMSG %s :Found %u (%s) open.", target, tab->count, tab->name); irc_send("PRIVMSG %s :Number of connects: %u (%.2f/minute)", target, STATS_CONNECTIONS, STATS_CONNECTIONS ? (float)STATS_CONNECTIONS / ((float)uptime / 60.0) : 0.0); } /* fdstats_output * * Output file descriptor stats to target via privmsg * * * Parameters: NONE * Return: NONE * */ void fdstats_output(const char *target) { struct rlimit rlim; unsigned int total_fd_use = 0; /* Get file descriptor ceiling */ if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) { log_printf("FDSTAT -> getrlimit() error retrieving RLIMIT_NOFILE (%s)", strerror(errno)); irc_send("PRIVMSG %s :FDSTAT -> getrlimit() error retrieving RLIMIT_NOFILE (%s)", target, strerror(errno)); return; } /* * Check which file descriptors are active, based on suggestions from: * http://groups.google.com/groups?th=a48b9fe8ca43947c&rnum=1 */ for (unsigned int i = 0; i < rlim.rlim_cur; ++i) { int newfd = dup(i); if (newfd > -1) { ++total_fd_use; close(newfd); } else { switch (errno) { case EMFILE: /* * We ran out of FDs whilst trying to dup an existing one, * so all fds are open and we can stop checking here. */ i = total_fd_use = rlim.rlim_cur; break; case EBADF: /* Not an FD in use. */ break; case EINTR: /* Try again. */ --i; break; default: /* We don't expect any other errors. */ log_printf("fd %u errno = %u (%s)", i, errno, strerror(errno)); break; } } } irc_send("PRIVMSG %s :Total open FD: %u/%d", target, total_fd_use, rlim.rlim_cur); }