int check_http(Socket_T socket) { Port_T P; char host[STRLEN]; char auth[STRLEN]= {0}; const char *request = NULL; const char *hostheader = NULL; ASSERT(socket); P = socket_get_Port(socket); ASSERT(P); request = P->request ? P->request : "/"; Util_getHTTPHostHeader(socket, host, STRLEN); hostheader = P->request_hostheader ? P->request_hostheader : host; if (socket_print(socket, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Accept: */*\r\n" "User-Agent: %s/%s\r\n" "%s\r\n", request, hostheader, prog, VERSION, get_auth_header(P, auth, STRLEN)) < 0) { socket_setError(socket, "HTTP: error sending data -- %s\n", STRERROR); return FALSE; } return check_request(socket, P); }
int check_http(Socket_T socket) { Port_T P; char host[STRLEN]; char auth[STRLEN] = {}; const char *request = NULL; const char *hostheader = NULL; ASSERT(socket); P = socket_get_Port(socket); ASSERT(P); request = P->request ? P->request : "/"; hostheader = _findHostHeaderIn(P->http_headers); hostheader = hostheader ? hostheader : P->request_hostheader ? P->request_hostheader : Util_getHTTPHostHeader(socket, host, STRLEN); // Otherwise use deprecated request_hostheader or default host StringBuffer_T sb = StringBuffer_create(168); StringBuffer_append(sb, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Accept: */*\r\n" "User-Agent: Monit/%s\r\n" "%s", request, hostheader, VERSION, get_auth_header(P, auth, STRLEN)); // Add headers if we have them if (P->http_headers) { for (list_t p = P->http_headers->head; p; p = p->next) { if (Str_startsWith(p->e, "Host")) // Already set contrived above continue; StringBuffer_append(sb, "%s\r\n", p->e); } } StringBuffer_append(sb, "\r\n"); int send_status = socket_write(socket, (void*)StringBuffer_toString(sb), StringBuffer_length(sb)); StringBuffer_free(&sb); if (send_status < 0) { socket_setError(socket, "HTTP: error sending data -- %s", STRERROR); return FALSE; } return check_request(socket, P); }
/** * Extract the Scoreboard line from the mod_status response. * Count the active apache child processes, and those which are * in other states. If each percentage exceeds the corresponding * limit, then return FALSE. * @param s A socket * @param limit The maximum percentage of logging processes * @return TRUE if logging is OK otherwise FALSE */ static int check_apache_stat(Socket_T socket) { int scored = 0; int errors = 0; char line[READ_SIZE]; char search_string[READ_SIZE + 1]; int loglimit= 0; int closelimit= 0; int dnslimit= 0; int keepalivelimit= 0; int replylimit= 0; int requestlimit= 0; int startlimit= 0; int waitlimit= 0; int gracefullimit= 0; int cleanuplimit= 0; int no_logging = 0; int no_close = 0; int no_dns = 0; int no_keepalive = 0; int no_reply = 0; int no_request = 0; int no_start = 0; int no_wait = 0; int no_graceful = 0; int no_cleanup = 0; int active_servers = 0; char *p; Port_T myPort= (Port_T)socket_get_Port(socket); ASSERT(myPort); loglimit= myPort->ApacheStatus.loglimit; closelimit= myPort->ApacheStatus.closelimit; dnslimit= myPort->ApacheStatus.dnslimit; keepalivelimit= myPort->ApacheStatus.keepalivelimit; replylimit= myPort->ApacheStatus.replylimit; requestlimit= myPort->ApacheStatus.requestlimit; startlimit= myPort->ApacheStatus.startlimit; waitlimit= myPort->ApacheStatus.waitlimit; gracefullimit= myPort->ApacheStatus.gracefullimit; cleanuplimit= myPort->ApacheStatus.cleanuplimit; while(NULL != socket_readln(socket, line, READ_SIZE)) { if(Str_startsWith(line, "Scoreboard")) { if(1 != sscanf(line, "%*s%*[: ]%1024s", search_string)) { Str_chomp(line); socket_setError(socket, "APACHE-STATUS error: parsing Apache status response '%s'\n", line); return FALSE; } else { scored = 1; } } } DEBUG("Scoreboard: %s\n", search_string); /* Check that some scoreboard line was found, if not return an error */ if(!scored){ socket_setError(socket, "APACHE-STATUS error: no scoreboard line returned by Apache\n"); return FALSE; } /* Total each of the status messages in the scoreboard */ for(p = search_string ; *p ; p++){ active_servers++; switch(*p){ case 'S': no_start++; break; case 'R': no_request++; break; case 'W': no_reply++; break; case 'K': no_keepalive++; break; case 'D': no_dns++; break; case 'C': no_close++; break; case 'L': no_logging++; break; case 'G': no_graceful++; break; case 'I': no_cleanup++; break; case '_': no_wait++; break; case '.': active_servers--; break; } } if(active_servers <= 0){ socket_setError(socket, "APACHE-STATUS warning: No idle server or threads found\n"); /* This is not really an error, only a very bussy server */ return TRUE; } /* * Conditions are only tested if the limit parameter is greater than zero. */ if(loglimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.loglimitOP, (100 * no_logging / active_servers), loglimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are logging\n", loglimit); errors++; } } if(startlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.startlimitOP, (100 * no_start / active_servers), startlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are starting\n", startlimit); errors++; } } if(requestlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.requestlimitOP, (100 * no_request / active_servers), requestlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are reading requests\n", requestlimit); errors++; } } if(replylimit > 0 ){ if(Util_evalQExpression(myPort->ApacheStatus.replylimitOP, (100 * no_reply / active_servers), replylimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are sending a reply\n", replylimit); errors++; } } if(keepalivelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.keepalivelimitOP, (100 * no_keepalive / active_servers), keepalivelimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are in keepalive\n", keepalivelimit); errors++; } } if(dnslimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.dnslimitOP, (100 * no_dns / active_servers), dnslimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are waiting for DNS\n", dnslimit); errors++; } } if(closelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.closelimitOP, (100 * no_close / active_servers), closelimit)){ socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are closing connections\n", closelimit); errors++; } } if(gracefullimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.gracefullimitOP, (100 * no_graceful / active_servers), gracefullimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are finishing gracefully\n", gracefullimit); errors++; } } if(cleanuplimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.cleanuplimitOP, (100 * no_cleanup / active_servers), cleanuplimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are in idle cleanup\n", cleanuplimit); errors++; } } if(waitlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.waitlimitOP, (100 * no_wait / active_servers), waitlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are waiting for a connection\n", waitlimit); errors++; } } return (errors==0); }
static int parse_scoreboard(Socket_T socket, char *scoreboard) { int logging = 0, close = 0, dns = 0, keepalive = 0, reply = 0, request = 0, start = 0, wait = 0, graceful = 0, cleanup = 0, open = 0; for (char *state = scoreboard; *state; state++) { switch (*state) { case 'S': start++; break; case 'R': request++; break; case 'W': reply++; break; case 'K': keepalive++; break; case 'D': dns++; break; case 'C': close++; break; case 'L': logging++; break; case 'G': graceful++; break; case 'I': cleanup++; break; case '_': wait++; break; case '.': open++; break; } } int total = logging + close + dns + keepalive + reply + request + start + wait + graceful + cleanup + open; if (! total) return TRUE; // Idle server int errors = 0; Port_T p = socket_get_Port(socket); ASSERT(p); //FIXME: socket_setError overrides previous => either stop on first error, or append errors and set error at the end (convert error buffer to stringbuffer?) if (p->ApacheStatus.loglimit > 0 && Util_evalQExpression(p->ApacheStatus.loglimitOP, (100 * logging / total), p->ApacheStatus.loglimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are logging", 100 * logging / total); errors++; } if (p->ApacheStatus.startlimit > 0 && Util_evalQExpression(p->ApacheStatus.startlimitOP, (100 * start / total), p->ApacheStatus.startlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are starting", 100 * start / total); errors++; } if (p->ApacheStatus.requestlimit > 0 && Util_evalQExpression(p->ApacheStatus.requestlimitOP, (100 * request / total), p->ApacheStatus.requestlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are reading requests", 100 * request / total); errors++; } if (p->ApacheStatus.replylimit > 0 && Util_evalQExpression(p->ApacheStatus.replylimitOP, (100 * reply / total), p->ApacheStatus.replylimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are sending a reply", 100 * reply / total); errors++; } if (p->ApacheStatus.keepalivelimit > 0 && Util_evalQExpression(p->ApacheStatus.keepalivelimitOP, (100 * keepalive / total), p->ApacheStatus.keepalivelimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are in keepalive", 100 * keepalive / total); errors++; } if (p->ApacheStatus.dnslimit > 0 && Util_evalQExpression(p->ApacheStatus.dnslimitOP, (100 * dns / total), p->ApacheStatus.dnslimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are waiting for DNS", 100 * dns / total); errors++; } if (p->ApacheStatus.closelimit > 0 && Util_evalQExpression(p->ApacheStatus.closelimitOP, (100 * close / total), p->ApacheStatus.closelimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are closing connections", 100 * close / total); errors++; } if (p->ApacheStatus.gracefullimit > 0 && Util_evalQExpression(p->ApacheStatus.gracefullimitOP, (100 * graceful / total), p->ApacheStatus.gracefullimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are finishing gracefully", 100 * graceful / total); errors++; } if (p->ApacheStatus.cleanuplimit > 0 && Util_evalQExpression(p->ApacheStatus.cleanuplimitOP, (100 * cleanup / total), p->ApacheStatus.cleanuplimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are in idle cleanup", 100 * cleanup / total); errors++; } if (p->ApacheStatus.waitlimit > 0 && Util_evalQExpression(p->ApacheStatus.waitlimitOP, (100 * wait / total), p->ApacheStatus.waitlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are waiting for a connection", 100 * wait / total); errors++; } return (errors == 0); }
/** * Generic service test. * * @file */ int check_generic(Socket_T socket) { Generic_T g = NULL; char *buf; #ifdef HAVE_REGEX_H int regex_return; #endif ASSERT(socket); if(socket_get_Port(socket)) g = ((Port_T)(socket_get_Port(socket)))->generic; buf = CALLOC(sizeof(char), Run.expectbuffer + 1); while (g != NULL) { if (g->send != NULL) { /* Unescape any \0x00 escaped chars in g's send string to allow sending a string containing \0 bytes also */ char *X = Str_dup(g->send); int l = Util_handle0Escapes(X); if(socket_write(socket, X, l) < 0) { socket_setError(socket, "GENERIC: error sending data -- %s", STRERROR); FREE(X); FREE(buf); return FALSE; } else DEBUG("GENERIC: successfully sent: '%s'\n", g->send); FREE(X); } else if (g->expect != NULL) { int n; /* Need read, not readln here */ if((n = socket_read(socket, buf, Run.expectbuffer)) < 0) { socket_setError(socket, "GENERIC: error receiving data -- %s", STRERROR); FREE(buf); return FALSE; } buf[n] = 0; if (n > 0) _escapeZeroInExpectBuffer(buf, n); #ifdef HAVE_REGEX_H regex_return = regexec(g->expect, buf, 0, NULL, 0); if (regex_return != 0) { char e[STRLEN]; regerror(regex_return, g->expect, e, STRLEN); socket_setError(socket, "GENERIC: receiving unexpected data [%s] -- %s", Str_trunc(buf, STRLEN - 4), e); FREE(buf); return FALSE; } else DEBUG("GENERIC: successfully received: '%s'\n", Str_trunc(buf, STRLEN - 4)); #else /* w/o regex support */ if (strncmp(buf, g->expect, strlen(g->expect)) != 0) { socket_setError(socket, "GENERIC: receiving unexpected data [%s]", Str_trunc(buf, STRLEN - 4)); FREE(buf); return FALSE; } else DEBUG("GENERIC: successfully received: '%s'\n", Str_trunc(buf, STRLEN - 4)); #endif } else { /* This should not happen */ socket_setError(socket, "GENERIC: unexpected strangeness"); FREE(buf); return FALSE; } g = g->next; } FREE(buf); return TRUE; }
int check_sip(Socket_T socket) { int status; char buf[STRLEN]; int port; char *transport; Port_T P; const char *request; const char *myip; char *rport= ""; char *proto; ASSERT(socket); P= socket_get_Port(socket); ASSERT(P); request= P->request?P->request:"*****@*****.**"; port = socket_get_local_port(socket); proto = socket_is_secure(socket) ? "sips" : "sip"; switch(socket_get_type(socket)) { case SOCK_DGRAM: { transport="UDP"; rport=";rport"; break; } case SOCK_STREAM: { transport="TCP"; break; } default: { socket_setError(socket, "Unsupported socket type, only TCP and UDP are supported\n"); return TRUE; } } myip= socket_get_local_host(socket); if(socket_print(socket, "OPTIONS %s:%s SIP/2.0\r\n" "Via: SIP/2.0/%s %s:%d;branch=z9hG4bKh%u%s\r\n" "Max-Forwards: %d\r\n" "To: <%s:%s>\r\n" "From: monit <%s:monit@%s>;tag=%d\r\n" "Call-ID: %u\r\n" "CSeq: 63104 OPTIONS\r\n" "Contact: <%s:%s:%d>\r\n" "Accept: application/sdp\r\n" "Content-Length: 0\r\n" "User-Agent: %s/%s\r\n\r\n", proto, // protocol request, // to transport, // via transport udp|tcp myip, // who its from port, // our port random(), // branch rport, // rport option P->maxforward, // maximum forwards proto, // protocol request, // to proto, // protocol myip, // from host random(), // tag random(), // call id proto, // protocol myip, // contact host port, // contact port prog, VERSION // user agent ) < 0) { socket_setError(socket, "SIP: error sending data -- %s\n", STRERROR); return FALSE; } if(! socket_readln(socket, buf, sizeof(buf))) { socket_setError(socket, "SIP: error receiving data -- %s\n", STRERROR); return FALSE; } Str_chomp(buf); DEBUG("Response from SIP server: %s\n", buf); if(! sscanf(buf, "%*s %d", &status)) { socket_setError(socket, "SIP error: cannot parse SIP status in response: %s\n", buf); return FALSE; } if(status >= 400) { socket_setError(socket, "SIP error: Server returned status %d\n", status); return FALSE; } if(status >= 300 && status < 400) { socket_setError(socket, "SIP info: Server redirection. Returned status %d\n", status); return FALSE; } if(status > 100 && status < 200) { socket_setError(socket, "SIP error: Provisional response . Returned status %d\n", status); return FALSE; } return TRUE; }
/** * Simple RADIUS test. * * We send a Status-Server packet, and expect an Access-Accept or Accounting-Response packet. * * */ int check_radius(Socket_T socket) { int i, length, left; int secret_len; Port_T P; md5_context_t ctx; char *secret; unsigned char *attr; unsigned char digest[16]; unsigned char response[STRLEN]; unsigned char request[38] = { /* Status-Server */ 0x0c, /* Code, we always use zero */ 0x00, /* Packet length */ 0x00, 0x26, /* Request Authenticator */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Message-Authenticator */ 0x50, /* Length */ 0x12, /* Contents of Message-Authenticator */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ASSERT(socket); if (socket_get_type(socket) != SOCK_DGRAM) { socket_setError(socket, "RADIUS: unsupported socket type -- protocol test skipped\n"); return TRUE; } P = socket_get_Port(socket); ASSERT(P); secret = P->request ? P->request : "testing123"; secret_len = (int)strlen(secret); /* get 16 bytes of random data */ for (i = 0; i < 16; i++) request[i + 4] = ((unsigned int)random()) & 0xff; /* sign the packet */ Util_hmacMD5(request, sizeof(request), (unsigned char *)secret, secret_len, request + 22); if (socket_write(socket, (unsigned char *)request, sizeof(request)) < 0) { socket_setError(socket, "RADIUS: error sending query -- %s\n", STRERROR); return FALSE; } /* the response should have at least 20 bytes */ if ((length = socket_read(socket, (unsigned char *)response, sizeof(response))) < 20) { socket_setError(socket, "RADIUS: error receiving response -- %s\n", STRERROR); return FALSE; } /* compare the response code (should be Access-Accept or Accounting-Response) */ if ((response[0] != 2) && (response[0] != 5)) { socket_setError(socket, "RADIUS: Invalid reply code -- error occured\n"); return FALSE; } /* compare the packet ID (it should be the same as in our request) */ if (response[1] != 0x00) { socket_setError(socket, "RADIUS: ID mismatch\n"); return FALSE; } /* check the length */ if (response[2] != 0) { socket_setError(socket, "RADIUS: message is too long\n"); return FALSE; } /* check length against packet data */ if (response[3] != length) { socket_setError(socket, "RADIUS: message has invalid length\n"); return FALSE; } /* validate that it is a well-formed packet */ attr = response + 20; left = length - 20; while (left > 0) { if (left < 2) { socket_setError(socket, "RADIUS: message is malformed\n"); return FALSE; } if (attr[1] < 2) { socket_setError(socket, "RADIUS: message has invalid attribute length\n"); return FALSE; } if (attr[1] > left) { socket_setError(socket, "RADIUS: message has attribute that is too long\n"); return FALSE; } /* validate Message-Authenticator, if found */ if (attr[0] == 0x50) { /* FIXME: validate it */ } left -= attr[1]; } /* save the reply authenticator, and copy the request authenticator over */ memcpy(digest, response + 4, 16); memcpy(response + 4, request + 4, 16); md5_init(&ctx); md5_append(&ctx, (const md5_byte_t *)response, length); md5_append(&ctx, (const md5_byte_t *)secret, secret_len); md5_finish(&ctx, response + 4); if (memcmp(digest, response + 4, 16) != 0) socket_setError(socket, "RADIUS: message fails authentication\n"); return TRUE; }