📄 main.c
字号:
/* GKrellM| Copyright (C) 1999-2006 Bill Wilson|| Author: Bill Wilson billw@gkrellm.net| Latest versions might be found at: http://gkrellm.net|| This program is free software which I release under the GNU General Public| License. You may redistribute and/or modify this program under the terms| of that 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. Version 2 is in the| COPYRIGHT file in the top level directory of this distribution.| | To get a copy of the GNU General Puplic License, write to the Free Software| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "gkrellmd.h"#include "gkrellmd-private.h"#include "../src/inet.h"#ifndef HAVE_GETADDRINFOstruct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ };#endif#if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY)#define IPV6_V6ONLY IPV6_BINDV6ONLY#endifstruct GkrellmdConfig _GK;GkrellmdTicks GK;GList *gkrellmd_client_list, *gkrellmd_plugin_config_list;static GList *allow_host_list;static gboolean detach_flag;#if !defined(WIN32)struct { uid_t uid; uid_t gid; } drop_privs = { 0, 0 };#endifstatic voidmake_pidfile(void) {#if !defined(WIN32) FILE *f; if (!_GK.pidfile) return; f = fopen(_GK.pidfile, "w"); if (f) { fprintf(f, "%d\n", getpid()); fclose(f); } else fprintf(stderr, "gkrellmd: Can't create pidfile %s\n", _GK.pidfile);#endif }static voidremove_pidfile(void) {#if !defined(WIN32) if (_GK.pidfile) unlink(_GK.pidfile);#endif }static voidcb_sigterm(gint sig) { remove_pidfile(); exit(0); }gintgkrellmd_send_to_client(GkrellmdClient *client, gchar *buf) { gint n; if (!client->alive) return 0;#if defined(MSG_NOSIGNAL) n = send(client->fd, buf, strlen(buf), MSG_NOSIGNAL);#else n = send(client->fd, buf, strlen(buf), 0);#endif if (n < 0 && errno == EPIPE) { if (_GK.verbose) printf("Write on closed pipe to host %s\n", client->hostname); client->alive = FALSE; } return n; }#if 0static gintgetline(gint fd, gchar *buf, gint len) { fd_set read_fds; struct timeval tv; gchar *s; gint result, n; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); tv.tv_usec = 0; tv.tv_sec = 15; s = buf; *s = '\0'; for (n = 0; n < len - 1; ++n) { result = select(fd + 1, &read_fds, NULL, NULL, &tv); if (result <= 0 || read(fd, s, 1) != 1) break; if (*s == '\n') { *s = '\0'; break; } *++s = '\0'; } return n; }#endif#ifdef HAVE_GETADDRINFOstatic gbooleanis_valid_reverse(char *addr, char *host, sa_family_t family) { struct addrinfo hints, *res, *r; int error, good; char addrbuf[NI_MAXHOST]; /* Reject numeric addresses */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(host, NULL, &hints, &res) == 0) { freeaddrinfo(res); return 0; } /* Check for spoof */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if (getaddrinfo(host, NULL, &hints, &res) != 0) return 0; good = 0; for (r = res; good == 0 && r; r = r->ai_next) { error = getnameinfo(r->ai_addr, r->ai_addrlen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); if (error == 0 && strcmp(addr, addrbuf) == 0) { good = 1; break; } } freeaddrinfo(res); return good; }#endif/* Check for CIDR match. */static gbooleancidr_match(struct sockaddr *sa, socklen_t salen, char *allowed){#ifdef HAVE_GETADDRINFO struct addrinfo hints, *res; struct sockaddr_storage ss; char *buf; char *p, *ep; guchar *addr, *pat; u_int32_t mask; int plen, i; gboolean result; buf = g_strdup(allowed); plen = -1; if ((p = strchr(buf, '/')) != NULL) { plen = strtoul(p + 1, &ep, 10); if (errno != 0 || ep == NULL || *ep != '\0' || plen < 0) { g_free(buf); return FALSE; } *p = '\0'; allowed = buf; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; result = getaddrinfo(allowed, NULL, &hints, &res); g_free(buf); if (result != 0) return FALSE; memcpy(&ss, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); if (sa->sa_family != ((struct sockaddr *)&ss)->sa_family) return FALSE; switch (sa->sa_family) {#if defined(INET6) case AF_INET6: if (plen < 0) plen = 128; if (plen > 128) return FALSE; if (((struct sockaddr_in6 *)&ss)->sin6_scope_id != 0 && ((struct sockaddr_in6 *)&ss)->sin6_scope_id != ((struct sockaddr_in6 *)sa)->sin6_scope_id) return FALSE; addr = (guchar *)&((struct sockaddr_in6 *)sa)->sin6_addr; pat = (guchar *)&((struct sockaddr_in6 *)&ss)->sin6_addr; i = 0; while (plen > 0) { if (plen < 32) { mask = htonl(~(0xffffffff >> plen)); if ((*(u_int32_t *)&addr[i] & mask) != (*(u_int32_t *)&pat[i] & mask)) return FALSE; break; } if (*(u_int32_t *)&addr[i] != *(u_int32_t *)&pat[i]) return FALSE; i += 4; plen -= 32; } break;#endif case AF_INET: if (plen < 0) plen = 32; if (plen > 32) return FALSE; addr = (guchar *)&((struct sockaddr_in *)sa)->sin_addr; pat = (guchar *)&((struct sockaddr_in *)&ss)->sin_addr; mask = htonl(~(0xffffffff >> plen)); if ((*(u_int32_t *)addr & mask) != (*(u_int32_t *)pat & mask)) return FALSE; break; default: return FALSE; } return TRUE;#else return FALSE;#endif}static gbooleanallow_host(GkrellmdClient *client, struct sockaddr *sa, socklen_t salen) { GList *list;#ifdef HAVE_GETADDRINFO int error; char hostbuf[NI_MAXHOST], addrbuf[NI_MAXHOST];#else struct hostent *hostent;#endif gchar buf[128]; gchar *hostname = NULL, *addr = NULL; gchar *s, *allowed;#ifdef HAVE_GETADDRINFO error = getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); if (error == 0) { addr = addrbuf; error = getnameinfo(sa, salen, hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD); if (error == 0 && is_valid_reverse(addrbuf, hostbuf, sa->sa_family)) hostname = hostbuf; }#else hostent = gethostbyaddr((gchar *)&((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr), AF_INET); if (hostent) hostname = hostent->h_name; addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);#endif client->hostname = g_strdup(hostname ? hostname : addr); if (!allow_host_list) return TRUE; for (list = allow_host_list; list; list = list->next) { allowed = (gchar *) list->data; if ( (hostname && !strcmp(hostname, allowed)) || (addr && !strcmp(addr, allowed)) || !strcmp("ALL", allowed) ) return TRUE; if (addr && cidr_match(sa, salen, allowed)) return TRUE; /* Check for simple IPv4 subnet match. Worry later about ranges and | other hosts_access type patterns. */ if ( addr && (s = strrchr(allowed, (int) '.')) != NULL && *(s + 1) == '*' && *(s + 2) == '\0' && !strncmp(addr, allowed, (gint) (s - allowed + 1)) ) return TRUE; } snprintf(buf, sizeof(buf), _("Connection not allowed from %s\n"), hostname ? hostname : addr); fprintf(stderr, "gkrellmd: %s", buf), gkrellmd_send_to_client(client, "<error>\n"); gkrellmd_send_to_client(client, buf); return FALSE; } /* client sends line: gkrellm x.y.z */static GkrellmdClient *accept_client(gint fd, struct sockaddr *sa, socklen_t salen) { GkrellmdClient *client; gchar buf[64], name[32]; gboolean client_limit; gint err; client = g_new0(GkrellmdClient, 1); client->fd = fd; client->alive = TRUE; client_limit = (g_list_length(gkrellmd_client_list) >= _GK.max_clients); if (!allow_host(client, sa, salen) || client_limit) { if (client_limit) { fprintf(stderr, _("gkrellmd: too many clients, rejecting %s\n"), client->hostname); gkrellmd_send_to_client(client, "<error>\nClient limit exceeded.\n"); } g_free(client->hostname); g_free(client); return NULL; } err = recv(fd, buf, sizeof(buf), 0); if (err > 0) buf[err] = '\0'; else buf[0] = '\0'; //getline(fd, buf, sizeof(buf)); if (_GK.verbose) printf(_("connect string from client: %s\n"), buf); if ( sscanf(buf, "%31s %d.%d.%d", name, &client->major_version, &client->minor_version, &client->rev_version) == 4 && !strcmp(name, "gkrellm") ) { gkrellmd_client_list = g_list_append(gkrellmd_client_list, client); return client; } fprintf(stderr, _("gkrellmd: bad connect line from %s: %s\n"), client->hostname, buf); gkrellmd_send_to_client(client, "<error>\nBad connect string!"); g_free(client->hostname); g_free(client); return NULL; }static voidremove_client(gint fd) { GList *list; GkrellmdClient *client; for (list = gkrellmd_client_list; list; list = list->next) { client = (GkrellmdClient *) list->data; if (client->fd == fd) { if (_GK.verbose) printf("Removing client %s\n", client->hostname); close(fd); g_free(client->hostname); g_free(client); gkrellmd_client_list = g_list_remove(gkrellmd_client_list, client); break; } } }static gintparse_config(gchar *config, gchar *arg) { if (!strcmp(config, "clear-hosts") || !strcmp(config, "c")) { gkrellm_free_glist_and_data(&allow_host_list); return 0; } if (!strcmp(config, "detach") || !strcmp(config, "d")) { detach_flag = TRUE; return 0; } if (!arg || !*arg) return -1; if (!strcmp(config, "update-hz") || !strcmp(config, "u")) _GK.update_HZ = atoi(arg); else if (!strcmp(config, "port") || !strcmp(config, "P")) _GK.server_port = atoi(arg); else if (!strcmp(config, "max-clients") || !strcmp(config, "m")) _GK.max_clients = atoi(arg); else if (!strcmp(config, "allow-host") || !strcmp(config, "a")) allow_host_list = g_list_append(allow_host_list, g_strdup(arg)); else if (!strcmp(config, "plugin-enable") || !strcmp(config, "pe")) gkrellmd_plugin_enable_list = g_list_append(gkrellmd_plugin_enable_list, g_strdup(arg)); else if (!strcmp(config, "plugin") || !strcmp(config, "p")) _GK.command_line_plugin = g_strdup(arg); else if (!strcmp(config, "io-timeout")) _GK.io_timeout = atoi(arg); else if (!strcmp(config, "reconnect-timeout")) _GK.reconnect_timeout = atoi(arg); else if (!strcmp(config, "fs-interval")) _GK.fs_interval = atoi(arg); else if (!strcmp(config, "nfs-interval")) _GK.nfs_interval = atoi(arg); else if (!strcmp(config, "inet-interval")) _GK.inet_interval = atoi(arg); else if (!strcmp(config, "mbmon-port")) _GK.mbmon_port = atoi(arg); else if (!strcmp(config, "net-timer")) _GK.net_timer = g_strdup(arg); else if (!strcmp(config, "debug-level") || !strcmp(config, "debug")) _GK.debug_level = (gint) strtoul(arg, NULL, 0);#if !defined(WIN32) else if (!strcmp(config, "pidfile")) _GK.pidfile = g_strdup(arg); else if (!strcmp(config, "mailbox")) gkrellmd_add_mailbox(arg); else if (!strcmp(config, "user") || !strcmp(config, "U")) { struct passwd *tmp; if ((tmp = getpwnam(arg)) != (struct passwd*) 0) drop_privs.uid = tmp->pw_uid; else return -1; } else if (!strcmp(config, "group") || !strcmp(config, "G")) { struct group *tmp; if ((tmp = getgrnam(arg)) != (struct group*) 0) drop_privs.gid = tmp->gr_gid; else return -1; }#endif else return -1; return 1; }static voidload_config(gchar *path) { FILE *f; PluginConfigRec *cfg; gchar buf[128], config[32], arg[128]; gchar *s, *plugin_config_block = NULL; f = fopen(path, "r"); if (!f) return; while (fgets(buf, sizeof(buf), f)) { if (!buf[0] || buf[0] == '#') continue; if (buf[0] == '[' || buf[0] == '<') { if (buf[1] == '/') { g_free(plugin_config_block); plugin_config_block = NULL; } else { if ( (s = strchr(buf, ']')) != NULL || (s = strchr(buf, '>')) != NULL ) *s = '\0'; plugin_config_block = g_strdup(&buf[1]); } continue; } if (plugin_config_block) { cfg = g_new0(PluginConfigRec, 1); cfg->name = g_strdup(plugin_config_block); if ((s = strchr(buf, '\n')) != NULL) *s = '\0'; cfg->line = g_strdup(buf); gkrellmd_plugin_config_list = g_list_append(gkrellmd_plugin_config_list, cfg); } else /* main gkrellmd config line */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -