diff options
author | Ton Voon <tonvoon@users.sourceforge.net> | 2004-11-17 23:22:54 +0000 |
---|---|---|
committer | Ton Voon <tonvoon@users.sourceforge.net> | 2004-11-17 23:22:54 +0000 |
commit | d56c17f1bedf5564ce7f13993ec026617fbaf51e (patch) | |
tree | fcff414d5af571b335c7847ad41bdb6c83a3bc9b /plugins/check_http.c | |
parent | 25c81fa8f39c1bffdf5ac69b4a5dfdb7cfd01ae8 (diff) | |
download | monitoring-plugins-d56c17f1bedf5564ce7f13993ec026617fbaf51e.tar.gz |
--no-body and --max-age options (949521 - Jamie Zawinski)
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@898 f882894a-f735-0410-b71e-b25c423dba1c
Diffstat (limited to 'plugins/check_http.c')
-rw-r--r-- | plugins/check_http.c | 246 |
1 files changed, 243 insertions, 3 deletions
diff --git a/plugins/check_http.c b/plugins/check_http.c index 840ba879..2281786e 100644 --- a/plugins/check_http.c +++ b/plugins/check_http.c @@ -63,6 +63,8 @@ X509 *server_cert; int connect_SSL (void); int check_certificate (X509 **); #endif +int no_body = FALSE; +int maximum_age = -1; #ifdef HAVE_REGEX_H enum { @@ -209,6 +211,8 @@ process_arguments (int argc, char **argv) {"linespan", no_argument, 0, 'l'}, {"onredirect", required_argument, 0, 'f'}, {"certificate", required_argument, 0, 'C'}, + {"no-body", no_argument, 0, 'N'}, + {"max-age", required_argument, 0, 'M'}, {"content-type", required_argument, 0, 'T'}, {"min", required_argument, 0, 'm'}, {"use-ipv4", no_argument, 0, '4'}, @@ -233,7 +237,7 @@ process_arguments (int argc, char **argv) } while (1) { - c = getopt_long (argc, argv, "Vvh46t:c:w:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:", longopts, &option); + c = getopt_long (argc, argv, "Vvh46t:c:w:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option); if (c == -1 || c == EOF) break; @@ -390,6 +394,27 @@ process_arguments (int argc, char **argv) case 'm': /* min_page_length */ min_page_len = atoi (optarg); break; + case 'N': /* no-body */ + no_body = TRUE; + break; + case 'M': /* max-age */ + { + int L = strlen(optarg); + if (L && optarg[L-1] == 'm') + maximum_age = atoi (optarg) * 60; + else if (L && optarg[L-1] == 'h') + maximum_age = atoi (optarg) * 60 * 60; + else if (L && optarg[L-1] == 'd') + maximum_age = atoi (optarg) * 60 * 60 * 24; + else if (L && (optarg[L-1] == 's' || + isdigit (optarg[L-1]))) + maximum_age = atoi (optarg); + else { + fprintf (stderr, "unparsable max-age: %s\n", optarg); + exit (1); + } + } + break; } } @@ -464,6 +489,205 @@ base64 (const char *bin, size_t len) +/* Returns 1 if we're done processing the document body; 0 to keep going */ +static int +document_headers_done (char *full_page) +{ + const char *body, *s; + const char *end; + + for (body = full_page; *body; body++) { + if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3)) + break; + } + + if (!*body) + return 0; /* haven't read end of headers yet */ + + full_page[body - full_page] = 0; + return 1; +} + +static time_t +parse_time_string (const char *string) +{ + struct tm tm; + time_t t; + memset (&tm, 0, sizeof(tm)); + + /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */ + + if (isupper (string[0]) && /* Tue */ + islower (string[1]) && + islower (string[2]) && + ',' == string[3] && + ' ' == string[4] && + (isdigit(string[5]) || string[5] == ' ') && /* 25 */ + isdigit (string[6]) && + ' ' == string[7] && + isupper (string[8]) && /* Dec */ + islower (string[9]) && + islower (string[10]) && + ' ' == string[11] && + isdigit (string[12]) && /* 2001 */ + isdigit (string[13]) && + isdigit (string[14]) && + isdigit (string[15]) && + ' ' == string[16] && + isdigit (string[17]) && /* 02: */ + isdigit (string[18]) && + ':' == string[19] && + isdigit (string[20]) && /* 59: */ + isdigit (string[21]) && + ':' == string[22] && + isdigit (string[23]) && /* 03 */ + isdigit (string[24]) && + ' ' == string[25] && + 'G' == string[26] && /* GMT */ + 'M' == string[27] && /* GMT */ + 'T' == string[28]) { + + tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0'); + tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0'); + tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0'); + tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0'); + tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 : + !strncmp (string+8, "Feb", 3) ? 1 : + !strncmp (string+8, "Mar", 3) ? 2 : + !strncmp (string+8, "Apr", 3) ? 3 : + !strncmp (string+8, "May", 3) ? 4 : + !strncmp (string+8, "Jun", 3) ? 5 : + !strncmp (string+8, "Jul", 3) ? 6 : + !strncmp (string+8, "Aug", 3) ? 7 : + !strncmp (string+8, "Sep", 3) ? 8 : + !strncmp (string+8, "Oct", 3) ? 9 : + !strncmp (string+8, "Nov", 3) ? 10 : + !strncmp (string+8, "Dec", 3) ? 11 : + -1); + tm.tm_year = ((1000 * (string[12]-'0') + + 100 * (string[13]-'0') + + 10 * (string[14]-'0') + + (string[15]-'0')) + - 1900); + + tm.tm_isdst = 0; /* GMT is never in DST, right? */ + + if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) + return 0; + + /* + This is actually wrong: we need to subtract the local timezone + offset from GMT from this value. But, that's ok in this usage, + because we only comparing these two GMT dates against each other, + so it doesn't matter what time zone we parse them in. + */ + + t = mktime (&tm); + if (t == (time_t) -1) t = 0; + + if (verbose) { + const char *s = string; + while (*s && *s != '\r' && *s != '\n') + fputc (*s++, stdout); + printf (" ==> %lu\n", (unsigned long) t); + } + + return t; + + } else { + return 0; + } +} + + +static void +check_document_dates (const char *headers) +{ + const char *s; + char *server_date = 0; + char *document_date = 0; + + s = headers; + while (*s) { + const char *field = s; + const char *value = 0; + + /* Find the end of the header field */ + while (*s && !isspace(*s) && *s != ':') + s++; + + /* Remember the header value, if any. */ + if (*s == ':') + value = ++s; + + /* Skip to the end of the header, including continuation lines. */ + while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) + s++; + s++; + + /* Process this header. */ + if (value && value > field+2) { + char *ff = (char *) malloc (value-field); + char *ss = ff; + while (field < value-1) + *ss++ = tolower(*field++); + *ss++ = 0; + + if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) { + const char *e; + while (*value && isspace (*value)) + value++; + for (e = value; *e && *e != '\r' && *e != '\n'; e++) + ; + ss = (char *) malloc (e - value + 1); + strncpy (ss, value, e - value); + ss[e - value] = 0; + if (!strcmp (ff, "date")) { + if (server_date) free (server_date); + server_date = ss; + } else { + if (document_date) free (document_date); + document_date = ss; + } + } + free (ff); + } + } + + /* Done parsing the body. Now check the dates we (hopefully) parsed. */ + if (!server_date || !*server_date) { + die (STATE_UNKNOWN, _("Server date unknown\n")); + } else if (!document_date || !*document_date) { + die (STATE_CRITICAL, _("Document modification date unknown\n")); + } else { + time_t sd = parse_time_string (server_date); + time_t dd = parse_time_string (document_date); + + if (sd <= 0) { + die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date); + } else if (dd <= 0) { + die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date); + } else if (dd > sd + 30) { + die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), dd - sd); + } else if (dd < sd - maximum_age) { + int n = (sd - dd); + if (n > (60 * 60 * 24 * 2)) + die (STATE_CRITICAL, + _("CRITICAL - Last modified %.1f days ago\n"), + ((float) n) / (60 * 60 * 24)); + else + die (STATE_CRITICAL, + _("CRITICAL - Last modified %d:%02d:%02d ago\n"), + n / (60 * 60), (n / 60) % 60, n % 60); + } + + free (server_date); + free (document_date); + } +} + + + int check_http (void) { @@ -561,6 +785,11 @@ check_http (void) buffer[i] = '\0'; asprintf (&full_page, "%s%s", full_page, buffer); pagesize += i; + + if (no_body && document_headers_done (full_page)) { + i = 0; + break; + } } if (i < 0 && errno != ECONNRESET) { @@ -621,7 +850,8 @@ check_http (void) page += (size_t) strspn (page, "\r\n"); header[pos - header] = 0; if (verbose) - printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, page); + printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, + (no_body ? " [[ skipped ]]" : page)); /* make sure the status line matches the response we are looking for */ if (!strstr (status_line, server_expect)) { @@ -691,6 +921,10 @@ check_http (void) } /* end else (server_expect_yn) */ + if (maximum_age >= 0) { + check_document_dates (header); + } + /* check elapsed time */ microsec = deltime (tv); elapsed_time = (double)microsec / 1.0e6; @@ -1154,6 +1388,12 @@ certificate expiration times.\n")); URL to GET or POST (default: /)\n\ -P, --post=STRING\n\ URL encoded http POST data\n\ + -N, --no-body\n\ + Don't wait for document body: stop reading after headers.\n\ + (Note that this still does an HTTP GET or POST, not a HEAD.)\n\ + -M, --max-age=SECONDS\n\ + Warn if document is more than SECONDS old. the number can also be of \n\ + the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\ -T, --content-type=STRING\n\ specify Content-Type header media type when POSTing\n"), HTTP_EXPECT); @@ -1226,6 +1466,6 @@ Usage: %s (-H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\ [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\ [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\ [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\ - [-P string] [-m min_pg_size] [-4|-6]\n"), progname); + [-P string] [-m min_pg_size] [-4|-6] [-N] [-M <age>]\n"), progname); printf (_(UT_HLP_VRS), progname, progname); } |