check_http.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. /******************************************************************************
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  13. ******************************************************************************/
  14. const char *progname = "check_http";
  15. const char *revision = "$Revision$";
  16. const char *copyright = "1999-2001";
  17. const char *email = "nagiosplug-devel@lists.sourceforge.net";
  18. #include "common.h"
  19. #include "netutils.h"
  20. #include "utils.h"
  21. #define HTTP_EXPECT "HTTP/1."
  22. enum {
  23. MAX_IPV4_HOSTLENGTH = 255,
  24. HTTP_PORT = 80,
  25. HTTPS_PORT = 443
  26. };
  27. #ifdef HAVE_SSL_H
  28. #include <rsa.h>
  29. #include <crypto.h>
  30. #include <x509.h>
  31. #include <pem.h>
  32. #include <ssl.h>
  33. #include <err.h>
  34. #include <rand.h>
  35. #else
  36. # ifdef HAVE_OPENSSL_SSL_H
  37. # include <openssl/rsa.h>
  38. # include <openssl/crypto.h>
  39. # include <openssl/x509.h>
  40. # include <openssl/pem.h>
  41. # include <openssl/ssl.h>
  42. # include <openssl/err.h>
  43. # include <openssl/rand.h>
  44. # endif
  45. #endif
  46. #ifdef HAVE_SSL
  47. int check_cert = FALSE;
  48. int days_till_exp;
  49. char *randbuff;
  50. SSL_CTX *ctx;
  51. SSL *ssl;
  52. X509 *server_cert;
  53. int connect_SSL (void);
  54. int check_certificate (X509 **);
  55. #endif
  56. #ifdef HAVE_REGEX_H
  57. enum {
  58. REGS = 2,
  59. MAX_RE_SIZE = 256
  60. };
  61. #include <regex.h>
  62. regex_t preg;
  63. regmatch_t pmatch[REGS];
  64. char regexp[MAX_RE_SIZE];
  65. char errbuf[MAX_INPUT_BUFFER];
  66. int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
  67. int errcode;
  68. #endif
  69. struct timeval tv;
  70. #define server_type_check(server_type) \
  71. (strcmp (server_type, "https") ? FALSE : TRUE)
  72. #define server_port_check(use_ssl) (use_ssl ? HTTPS_PORT : HTTP_PORT)
  73. #define HTTP_URL "/"
  74. #define CRLF "\r\n"
  75. char timestamp[17] = "";
  76. int specify_port = FALSE;
  77. int server_port = HTTP_PORT;
  78. char server_port_text[6] = "";
  79. char server_type[6] = "http";
  80. char *server_address;
  81. char *host_name;
  82. char *server_url;
  83. int server_url_length;
  84. int server_expect_yn = 0;
  85. char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
  86. char string_expect[MAX_INPUT_BUFFER] = "";
  87. double warning_time = 0;
  88. int check_warning_time = FALSE;
  89. double critical_time = 0;
  90. int check_critical_time = FALSE;
  91. char user_auth[MAX_INPUT_BUFFER] = "";
  92. int display_html = FALSE;
  93. int onredirect = STATE_OK;
  94. int use_ssl = FALSE;
  95. int verbose = FALSE;
  96. int sd;
  97. int min_page_len = 0;
  98. char *http_method;
  99. char *http_post_data;
  100. char buffer[MAX_INPUT_BUFFER];
  101. int process_arguments (int, char **);
  102. static char *base64 (char *bin, size_t len);
  103. int check_http (void);
  104. int my_recv (void);
  105. int my_close (void);
  106. void print_help (void);
  107. void print_usage (void);
  108. int
  109. main (int argc, char **argv)
  110. {
  111. int result = STATE_UNKNOWN;
  112. /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
  113. server_url = strdup(HTTP_URL);
  114. server_url_length = strlen(server_url);
  115. if (process_arguments (argc, argv) == ERROR)
  116. usage (_("check_http: could not parse arguments\n"));
  117. if (strstr (timestamp, ":")) {
  118. if (strstr (server_url, "?"))
  119. asprintf (&server_url, "%s&%s", server_url, timestamp);
  120. else
  121. asprintf (&server_url, "%s?%s", server_url, timestamp);
  122. }
  123. if (display_html == TRUE)
  124. printf ("<A HREF=\"http://%s:%d%s\" target=\"_blank\">",
  125. host_name, server_port, server_url);
  126. /* initialize alarm signal handling, set socket timeout, start timer */
  127. (void) signal (SIGALRM, socket_timeout_alarm_handler);
  128. (void) alarm (socket_timeout);
  129. gettimeofday (&tv, NULL);
  130. #ifdef HAVE_SSL
  131. if (use_ssl && check_cert == TRUE) {
  132. if (connect_SSL () != OK)
  133. die (STATE_CRITICAL, _("HTTP CRITICAL - Could not make SSL connection\n"));
  134. if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
  135. result = check_certificate (&server_cert);
  136. X509_free (server_cert);
  137. }
  138. else {
  139. printf (_("ERROR: Cannot retrieve server certificate.\n"));
  140. result = STATE_CRITICAL;
  141. }
  142. SSL_shutdown (ssl);
  143. SSL_free (ssl);
  144. SSL_CTX_free (ctx);
  145. close (sd);
  146. }
  147. else {
  148. result = check_http ();
  149. }
  150. #else
  151. result = check_http ();
  152. #endif
  153. return result;
  154. }
  155. /* process command-line arguments */
  156. int
  157. process_arguments (int argc, char **argv)
  158. {
  159. int c = 1;
  160. int option = 0;
  161. static struct option longopts[] = {
  162. STD_LONG_OPTS,
  163. {"file",required_argument,0,'F'},
  164. {"link", no_argument, 0, 'L'},
  165. {"nohtml", no_argument, 0, 'n'},
  166. {"ssl", no_argument, 0, 'S'},
  167. {"verbose", no_argument, 0, 'v'},
  168. {"post", required_argument, 0, 'P'},
  169. {"IP-address", required_argument, 0, 'I'},
  170. {"string", required_argument, 0, 's'},
  171. {"regex", required_argument, 0, 'r'},
  172. {"ereg", required_argument, 0, 'r'},
  173. {"eregi", required_argument, 0, 'R'},
  174. {"linespan", no_argument, 0, 'l'},
  175. {"onredirect", required_argument, 0, 'f'},
  176. {"certificate", required_argument, 0, 'C'},
  177. {"min", required_argument, 0, 'm'},
  178. {"use-ipv4", no_argument, 0, '4'},
  179. {"use-ipv6", no_argument, 0, '6'},
  180. {0, 0, 0, 0}
  181. };
  182. if (argc < 2)
  183. return ERROR;
  184. for (c = 1; c < argc; c++) {
  185. if (strcmp ("-to", argv[c]) == 0)
  186. strcpy (argv[c], "-t");
  187. if (strcmp ("-hn", argv[c]) == 0)
  188. strcpy (argv[c], "-H");
  189. if (strcmp ("-wt", argv[c]) == 0)
  190. strcpy (argv[c], "-w");
  191. if (strcmp ("-ct", argv[c]) == 0)
  192. strcpy (argv[c], "-c");
  193. if (strcmp ("-nohtml", argv[c]) == 0)
  194. strcpy (argv[c], "-n");
  195. }
  196. while (1) {
  197. c = getopt_long (argc, argv, "Vvh46t:c:w:H:P:I:a:e:p:s:R:r:u:f:C:nlLSm:", longopts, &option);
  198. if (c == -1 || c == EOF)
  199. break;
  200. switch (c) {
  201. case '?': /* usage */
  202. usage3 (_("unknown argument"), optopt);
  203. break;
  204. case 'h': /* help */
  205. print_help ();
  206. exit (STATE_OK);
  207. break;
  208. case 'V': /* version */
  209. print_revision (progname, revision);
  210. exit (STATE_OK);
  211. break;
  212. case 't': /* timeout period */
  213. if (!is_intnonneg (optarg))
  214. usage2 (_("timeout interval must be a non-negative integer"), optarg);
  215. else
  216. socket_timeout = atoi (optarg);
  217. break;
  218. case 'c': /* critical time threshold */
  219. if (!is_intnonneg (optarg))
  220. usage2 (_("invalid critical threshold"), optarg);
  221. else {
  222. critical_time = strtod (optarg, NULL);
  223. check_critical_time = TRUE;
  224. }
  225. break;
  226. case 'w': /* warning time threshold */
  227. if (!is_intnonneg (optarg))
  228. usage2 (_("invalid warning threshold"), optarg);
  229. else {
  230. warning_time = strtod (optarg, NULL);
  231. check_warning_time = TRUE;
  232. }
  233. break;
  234. case 'L': /* show html link */
  235. display_html = TRUE;
  236. break;
  237. case 'n': /* do not show html link */
  238. display_html = FALSE;
  239. break;
  240. case 'S': /* use SSL */
  241. #ifndef HAVE_SSL
  242. usage (_("check_http: invalid option - SSL is not available\n"));
  243. #endif
  244. use_ssl = TRUE;
  245. if (specify_port == FALSE)
  246. server_port = HTTPS_PORT;
  247. break;
  248. case 'C': /* Check SSL cert validity */
  249. #ifdef HAVE_SSL
  250. if (!is_intnonneg (optarg))
  251. usage2 (_("invalid certificate expiration period"), optarg);
  252. else {
  253. days_till_exp = atoi (optarg);
  254. check_cert = TRUE;
  255. }
  256. #else
  257. usage (_("check_http: invalid option - SSL is not available\n"));
  258. #endif
  259. break;
  260. case 'f': /* onredirect */
  261. if (!strcmp (optarg, "follow"))
  262. onredirect = STATE_DEPENDENT;
  263. if (!strcmp (optarg, "unknown"))
  264. onredirect = STATE_UNKNOWN;
  265. if (!strcmp (optarg, "ok"))
  266. onredirect = STATE_OK;
  267. if (!strcmp (optarg, "warning"))
  268. onredirect = STATE_WARNING;
  269. if (!strcmp (optarg, "critical"))
  270. onredirect = STATE_CRITICAL;
  271. if (verbose)
  272. printf(_("option f:%d \n"), onredirect);
  273. break;
  274. /* Note: H, I, and u must be malloc'd or will fail on redirects */
  275. case 'H': /* Host Name (virtual host) */
  276. host_name = strdup (optarg);
  277. break;
  278. case 'I': /* Server IP-address */
  279. server_address = strdup (optarg);
  280. break;
  281. case 'u': /* URL path */
  282. server_url = strdup (optarg);
  283. server_url_length = strlen (server_url);
  284. break;
  285. case 'p': /* Server port */
  286. if (!is_intnonneg (optarg))
  287. usage2 (_("invalid port number"), optarg);
  288. else {
  289. server_port = atoi (optarg);
  290. specify_port = TRUE;
  291. }
  292. break;
  293. case 'a': /* authorization info */
  294. strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
  295. user_auth[MAX_INPUT_BUFFER - 1] = 0;
  296. break;
  297. case 'P': /* HTTP POST data in URL encoded format */
  298. if (http_method || http_post_data) break;
  299. http_method = strdup("POST");
  300. http_post_data = strdup (optarg);
  301. break;
  302. case 's': /* string or substring */
  303. strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
  304. string_expect[MAX_INPUT_BUFFER - 1] = 0;
  305. break;
  306. case 'e': /* string or substring */
  307. strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
  308. server_expect[MAX_INPUT_BUFFER - 1] = 0;
  309. server_expect_yn = 1;
  310. break;
  311. #ifndef HAVE_REGEX_H
  312. case 'l': /* linespan */
  313. case 'r': /* linespan */
  314. case 'R': /* linespan */
  315. usage (_("check_http: call for regex which was not a compiled option\n"));
  316. break;
  317. #else
  318. case 'l': /* linespan */
  319. cflags &= ~REG_NEWLINE;
  320. break;
  321. case 'R': /* regex */
  322. cflags |= REG_ICASE;
  323. case 'r': /* regex */
  324. strncpy (regexp, optarg, MAX_RE_SIZE - 1);
  325. regexp[MAX_RE_SIZE - 1] = 0;
  326. errcode = regcomp (&preg, regexp, cflags);
  327. if (errcode != 0) {
  328. (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
  329. printf (_("Could Not Compile Regular Expression: %s"), errbuf);
  330. return ERROR;
  331. }
  332. break;
  333. #endif
  334. case '4':
  335. address_family = AF_INET;
  336. break;
  337. case '6':
  338. #ifdef USE_IPV6
  339. address_family = AF_INET6;
  340. #else
  341. usage (_("IPv6 support not available\n"));
  342. #endif
  343. break;
  344. case 'v': /* verbose */
  345. verbose = TRUE;
  346. break;
  347. case 'm': /* min_page_length */
  348. min_page_len = atoi (optarg);
  349. break;
  350. }
  351. }
  352. c = optind;
  353. if (server_address == NULL && c < argc)
  354. server_address = strdup (argv[c++]);
  355. if (host_name == NULL && c < argc)
  356. host_name = strdup (argv[c++]);
  357. if (server_address == NULL) {
  358. if (host_name == NULL)
  359. usage (_("check_http: you must specify a server address or host name\n"));
  360. else
  361. server_address = strdup (host_name);
  362. }
  363. if (check_critical_time && critical_time>(double)socket_timeout)
  364. socket_timeout = (int)critical_time + 1;
  365. if (http_method == NULL)
  366. http_method = strdup ("GET");
  367. return TRUE;
  368. }
  369. /* written by lauri alanko */
  370. static char *
  371. base64 (char *bin, size_t len)
  372. {
  373. char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
  374. size_t i = 0, j = 0;
  375. char BASE64_END = '=';
  376. char base64_table[64];
  377. strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
  378. while (j < len - 2) {
  379. buf[i++] = base64_table[bin[j] >> 2];
  380. buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
  381. buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
  382. buf[i++] = base64_table[bin[j + 2] & 63];
  383. j += 3;
  384. }
  385. switch (len - j) {
  386. case 1:
  387. buf[i++] = base64_table[bin[j] >> 2];
  388. buf[i++] = base64_table[(bin[j] & 3) << 4];
  389. buf[i++] = BASE64_END;
  390. buf[i++] = BASE64_END;
  391. break;
  392. case 2:
  393. buf[i++] = base64_table[bin[j] >> 2];
  394. buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
  395. buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
  396. buf[i++] = BASE64_END;
  397. break;
  398. case 0:
  399. break;
  400. }
  401. buf[i] = '\0';
  402. return buf;
  403. }
  404. /* per RFC 2396 */
  405. #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
  406. #define URI_HTTP "%[HTPShtps]://"
  407. #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
  408. #define URI_PORT ":%[0123456789]"
  409. #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
  410. #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
  411. #define HD2 URI_HTTP URI_HOST URI_PATH
  412. #define HD3 URI_HTTP URI_HOST URI_PORT
  413. #define HD4 URI_HTTP URI_HOST
  414. #define HD5 URI_PATH
  415. int
  416. check_http (void)
  417. {
  418. char *msg;
  419. char *status_line;
  420. char *header;
  421. char *page;
  422. char *auth;
  423. int i = 0;
  424. size_t pagesize = 0;
  425. char *full_page;
  426. char *buf;
  427. char *pos;
  428. char *x;
  429. char xx[2];
  430. char *orig_url;
  431. long microsec;
  432. double elapsed_time;
  433. int page_len = 0;
  434. #ifdef HAVE_SSL
  435. int sslerr;
  436. #endif
  437. /* try to connect to the host at the given port number */
  438. #ifdef HAVE_SSL
  439. if (use_ssl == TRUE) {
  440. if (connect_SSL () != OK) {
  441. die (STATE_CRITICAL, _("Unable to open TCP socket"));
  442. }
  443. if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
  444. X509_free (server_cert);
  445. }
  446. else {
  447. printf (_("ERROR: Cannot retrieve server certificate.\n"));
  448. return STATE_CRITICAL;
  449. }
  450. }
  451. else {
  452. #endif
  453. if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
  454. die (STATE_CRITICAL, _("Unable to open TCP socket"));
  455. #ifdef HAVE_SSL
  456. }
  457. #endif
  458. asprintf (&buf, "%s %s HTTP/1.0\r\n", http_method, server_url);
  459. /* optionally send the host header info (not clear if it's usable) */
  460. if (host_name)
  461. asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
  462. /* send user agent */
  463. asprintf (&buf, "%sUser-Agent: check_http/%s (nagios-plugins %s)\r\n",
  464. buf, clean_revstring (revision), VERSION);
  465. /* optionally send the authentication info */
  466. if (strlen(user_auth)) {
  467. auth = base64 (user_auth, strlen (user_auth));
  468. asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
  469. }
  470. /* either send http POST data */
  471. if (http_post_data) {
  472. asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
  473. asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, strlen (http_post_data));
  474. asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
  475. }
  476. else {
  477. /* or just a newline so the server knows we're done with the request */
  478. asprintf (&buf, "%s%s", buf, CRLF);
  479. }
  480. #ifdef HAVE_SSL
  481. if (use_ssl == TRUE) {
  482. if (SSL_write (ssl, buf, (int)strlen(buf)) == -1) {
  483. ERR_print_errors_fp (stderr);
  484. return STATE_CRITICAL;
  485. }
  486. }
  487. else {
  488. #endif
  489. send (sd, buf, strlen (buf), 0);
  490. #ifdef HAVE_SSL
  491. }
  492. #endif
  493. /* fetch the page */
  494. full_page = strdup("");
  495. while ((i = my_recv ()) > 0) {
  496. buffer[i] = '\0';
  497. asprintf (&full_page, "%s%s", full_page, buffer);
  498. pagesize += i;
  499. }
  500. if (i < 0 && errno != ECONNRESET) {
  501. #ifdef HAVE_SSL
  502. if (use_ssl) {
  503. sslerr=SSL_get_error(ssl, i);
  504. if ( sslerr == SSL_ERROR_SSL ) {
  505. die (STATE_WARNING, _("Client Certificate Required\n"));
  506. } else {
  507. die (STATE_CRITICAL, _("Error in recv()"));
  508. }
  509. }
  510. else {
  511. #endif
  512. die (STATE_CRITICAL, _("Error in recv()"));
  513. #ifdef HAVE_SSL
  514. }
  515. #endif
  516. }
  517. /* return a CRITICAL status if we couldn't read any data */
  518. if (pagesize == (size_t) 0)
  519. die (STATE_CRITICAL, _("No data received %s"), timestamp);
  520. /* close the connection */
  521. my_close ();
  522. /* reset the alarm */
  523. alarm (0);
  524. /* leave full_page untouched so we can free it later */
  525. page = full_page;
  526. if (verbose)
  527. printf ("%s://%s:%d%s is %d characters\n", server_type, server_address, server_port, server_url, pagesize);
  528. /* find status line and null-terminate it */
  529. status_line = page;
  530. page += (size_t) strcspn (page, "\r\n");
  531. pos = page;
  532. page += (size_t) strspn (page, "\r\n");
  533. status_line[strcspn(status_line, "\r\n")] = 0;
  534. strip (status_line);
  535. if (verbose)
  536. printf ("STATUS: %s\n", status_line);
  537. /* find header info and null-terminate it */
  538. header = page;
  539. while (strcspn (page, "\r\n") > 0) {
  540. page += (size_t) strcspn (page, "\r\n");
  541. pos = page;
  542. if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
  543. (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
  544. page += (size_t) 2;
  545. else
  546. page += (size_t) 1;
  547. }
  548. page += (size_t) strspn (page, "\r\n");
  549. header[pos - header] = 0;
  550. if (verbose)
  551. printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, page);
  552. /* make sure the status line matches the response we are looking for */
  553. if (!strstr (status_line, server_expect)) {
  554. if (server_port == HTTP_PORT)
  555. asprintf (&msg, _("Invalid HTTP response received from host\n"));
  556. else
  557. asprintf (&msg,
  558. _("Invalid HTTP response received from host on port %d\n"),
  559. server_port);
  560. die (STATE_CRITICAL, "%s", msg);
  561. }
  562. /* Exit here if server_expect was set by user and not default */
  563. if ( server_expect_yn ) {
  564. asprintf (&msg, _("HTTP OK: Status line output matched \"%s\"\n"),
  565. server_expect);
  566. if (verbose)
  567. printf ("%s\n",msg);
  568. }
  569. else {
  570. /* check the return code */
  571. /* server errors result in a critical state */
  572. if (strstr (status_line, "500") || strstr (status_line, "501") ||
  573. strstr (status_line, "502") || strstr (status_line, "503") ||
  574. strstr (status_line, "504") || strstr (status_line, "505")) {
  575. die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
  576. }
  577. /* client errors result in a warning state */
  578. if (strstr (status_line, "400") || strstr (status_line, "401") ||
  579. strstr (status_line, "402") || strstr (status_line, "403") ||
  580. strstr (status_line, "404") || strstr (status_line, "405") ||
  581. strstr (status_line, "406") || strstr (status_line, "407") ||
  582. strstr (status_line, "408") || strstr (status_line, "409") ||
  583. strstr (status_line, "410") || strstr (status_line, "411") ||
  584. strstr (status_line, "412") || strstr (status_line, "413") ||
  585. strstr (status_line, "414") || strstr (status_line, "415") ||
  586. strstr (status_line, "416") || strstr (status_line, "417")) {
  587. die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
  588. }
  589. /* check redirected page if specified */
  590. if (strstr (status_line, "300") || strstr (status_line, "301") ||
  591. strstr (status_line, "302") || strstr (status_line, "303") ||
  592. strstr (status_line, "304") || strstr (status_line, "305") ||
  593. strstr (status_line, "306")) {
  594. if (onredirect == STATE_DEPENDENT) {
  595. server_address = realloc (server_address, MAX_IPV4_HOSTLENGTH + 1);
  596. if (server_address == NULL)
  597. die (STATE_UNKNOWN,_("ERROR: could not allocate server_address"));
  598. asprintf (&orig_url, "%s", server_url);
  599. if (strcspn (pos, "\r\n") > (size_t)server_url_length) {
  600. server_url = realloc (server_url, strcspn (pos, "\r\n"));
  601. if (server_url == NULL)
  602. die (STATE_UNKNOWN, _("ERROR: could not allocate server_url"));
  603. server_url_length = strcspn (pos, "\r\n");
  604. }
  605. pos = header;
  606. while (pos) {
  607. if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) > 0) {
  608. pos += i;
  609. pos += strspn (pos, " \t\r\n");
  610. } else {
  611. pos += (size_t) strcspn (pos, "\r\n");
  612. pos += (size_t) strspn (pos, "\r\n");
  613. continue;
  614. }
  615. /* HDR_LOCATION, URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
  616. if (sscanf (pos, HD1, server_type, server_address, server_port_text, server_url) == 4) {
  617. if (host_name != NULL) free(host_name);
  618. host_name = strdup(server_address);
  619. use_ssl = server_type_check (server_type);
  620. server_port = atoi (server_port_text);
  621. check_http ();
  622. }
  623. /* HDR_LOCATION URI_HTTP URI_HOST URI_PATH */
  624. else if (sscanf (pos, HD2, server_type, server_address, server_url) == 3 ) {
  625. if (host_name != NULL) free(host_name);
  626. host_name = strdup(server_address);
  627. use_ssl = server_type_check (server_type);
  628. server_port = server_port_check (use_ssl);
  629. check_http ();
  630. }
  631. /* HDR_LOCATION URI_HTTP URI_HOST URI_PORT */
  632. else if(sscanf (pos, HD3, server_type, server_address, server_port_text) == 3) {
  633. if (host_name != NULL) free(host_name);
  634. host_name = strdup(server_address);
  635. strcpy (server_url, "/");
  636. use_ssl = server_type_check (server_type);
  637. server_port = atoi (server_port_text);
  638. check_http ();
  639. }
  640. /* HDR_LOCATION URI_HTTP URI_HOST */
  641. else if(sscanf (pos, HD4, server_type, server_address) == 2) {
  642. if (host_name != NULL) free(host_name);
  643. host_name = strdup(server_address);
  644. strcpy (server_url, "/");
  645. use_ssl = server_type_check (server_type);
  646. server_port = server_port_check (use_ssl);
  647. check_http ();
  648. }
  649. /* HDR_LOCATION URI_PATH */
  650. else if (sscanf (pos, HD5, server_url) == 1) {
  651. if ((server_url[0] != '/') && (x = strrchr(orig_url, '/'))) {
  652. *x = '\0';
  653. asprintf (&server_url, "%s/%s", orig_url, server_url);
  654. }
  655. check_http ();
  656. }
  657. } /* end while (pos) */
  658. printf (_("UNKNOWN - Could not find redirect location - %s%s"),
  659. status_line, (display_html ? "</A>" : ""));
  660. exit (STATE_UNKNOWN);
  661. } /* end if (onredirect == STATE_DEPENDENT) */
  662. else if (onredirect == STATE_UNKNOWN)
  663. printf (_("UNKNOWN"));
  664. else if (onredirect == STATE_OK)
  665. printf (_("OK"));
  666. else if (onredirect == STATE_WARNING)
  667. printf (_("WARNING"));
  668. else if (onredirect == STATE_CRITICAL)
  669. printf (_("CRITICAL"));
  670. microsec = deltime (tv);
  671. elapsed_time = (double)microsec / 1.0e6;
  672. asprintf (&msg, _(" - %s - %.3f second response time %s%s|time=%ldus size=%dB\n"),
  673. status_line, elapsed_time, timestamp,
  674. (display_html ? "</A>" : ""), microsec, pagesize);
  675. die (onredirect, "%s", msg);
  676. } /* end if (strstr (status_line, "30[0-4]") */
  677. } /* end else (server_expect_yn) */
  678. /* check elapsed time */
  679. microsec = deltime (tv);
  680. elapsed_time = (double)microsec / 1.0e6;
  681. asprintf (&msg, _("HTTP problem: %s - %.3f second response time %s%s|time=%ldus size=%dB\n"),
  682. status_line, elapsed_time, timestamp,
  683. (display_html ? "</A>" : ""), microsec, pagesize);
  684. if (check_critical_time == TRUE && elapsed_time > critical_time)
  685. die (STATE_CRITICAL, "%s", msg);
  686. if (check_warning_time == TRUE && elapsed_time > warning_time)
  687. die (STATE_WARNING, "%s", msg);
  688. /* Page and Header content checks go here */
  689. /* these checks should be last */
  690. if (strlen (string_expect)) {
  691. if (strstr (page, string_expect)) {
  692. printf (_("HTTP OK %s - %.3f second response time %s%s|time=%ldus size=%dB\n"),
  693. status_line, elapsed_time,
  694. timestamp, (display_html ? "</A>" : ""), microsec, pagesize);
  695. exit (STATE_OK);
  696. }
  697. else {
  698. printf (_("CRITICAL - string not found%s|time=%ldus\n size=%dB"),
  699. (display_html ? "</A>" : ""), microsec, pagesize);
  700. exit (STATE_CRITICAL);
  701. }
  702. }
  703. #ifdef HAVE_REGEX_H
  704. if (strlen (regexp)) {
  705. errcode = regexec (&preg, page, REGS, pmatch, 0);
  706. if (errcode == 0) {
  707. printf (_("HTTP OK %s - %.3f second response time %s%s|time=%ldus size=%dB\n"),
  708. status_line, elapsed_time,
  709. timestamp, (display_html ? "</A>" : ""), microsec, pagesize);
  710. exit (STATE_OK);
  711. }
  712. else {
  713. if (errcode == REG_NOMATCH) {
  714. printf (_("CRITICAL - pattern not found%s|time=%ldus size=%dB\n"),
  715. (display_html ? "</A>" : ""), microsec, pagesize);
  716. exit (STATE_CRITICAL);
  717. }
  718. else {
  719. regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
  720. printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
  721. exit (STATE_CRITICAL);
  722. }
  723. }
  724. }
  725. #endif
  726. /* make sure the page is of an appropriate size */
  727. page_len = strlen (page);
  728. if ((min_page_len > 0) && (page_len < min_page_len)) {
  729. printf (_("HTTP WARNING: page size too small%s|size=%i\n"),
  730. (display_html ? "</A>" : ""), page_len );
  731. exit (STATE_WARNING);
  732. }
  733. /* We only get here if all tests have been passed */
  734. asprintf (&msg, _("HTTP OK %s - %.3f second response time %s%s|time=%ldus size=%dB\n"),
  735. status_line, elapsed_time,
  736. timestamp, (display_html ? "</A>" : ""), microsec, pagesize);
  737. die (STATE_OK, "%s", msg);
  738. return STATE_UNKNOWN;
  739. }
  740. #ifdef HAVE_SSL
  741. int connect_SSL (void)
  742. {
  743. SSL_METHOD *meth;
  744. asprintf (&randbuff, "%s", "qwertyuiopasdfghjklqwertyuiopasdfghjkl");
  745. RAND_seed (randbuff, (int)strlen(randbuff));
  746. if (verbose)
  747. printf(_("SSL seeding: %s\n"), (RAND_status()==1 ? _("OK") : _("Failed")) );
  748. /* Initialize SSL context */
  749. SSLeay_add_ssl_algorithms ();
  750. meth = SSLv23_client_method ();
  751. SSL_load_error_strings ();
  752. if ((ctx = SSL_CTX_new (meth)) == NULL) {
  753. printf (_("CRITICAL - Cannot create SSL context.\n"));
  754. return STATE_CRITICAL;
  755. }
  756. /* Initialize alarm signal handling */
  757. signal (SIGALRM, socket_timeout_alarm_handler);
  758. /* Set socket timeout */
  759. alarm (socket_timeout);
  760. /* Save start time */
  761. gettimeofday (&tv, NULL);
  762. /* Make TCP connection */
  763. if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
  764. /* Do the SSL handshake */
  765. if ((ssl = SSL_new (ctx)) != NULL) {
  766. SSL_set_cipher_list(ssl, "ALL");
  767. SSL_set_fd (ssl, sd);
  768. if (SSL_connect (ssl) != -1)
  769. return OK;
  770. ERR_print_errors_fp (stderr);
  771. }
  772. else {
  773. printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
  774. }
  775. SSL_free (ssl);
  776. }
  777. SSL_CTX_free (ctx);
  778. close (sd);
  779. return STATE_CRITICAL;
  780. }
  781. #endif
  782. #ifdef HAVE_SSL
  783. int
  784. check_certificate (X509 ** certificate)
  785. {
  786. ASN1_STRING *tm;
  787. int offset;
  788. struct tm stamp;
  789. int days_left;
  790. /* Retrieve timestamp of certificate */
  791. tm = X509_get_notAfter (*certificate);
  792. /* Generate tm structure to process timestamp */
  793. if (tm->type == V_ASN1_UTCTIME) {
  794. if (tm->length < 10) {
  795. printf (_("CRITICAL - Wrong time format in certificate.\n"));
  796. return STATE_CRITICAL;
  797. }
  798. else {
  799. stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
  800. if (stamp.tm_year < 50)
  801. stamp.tm_year += 100;
  802. offset = 0;
  803. }
  804. }
  805. else {
  806. if (tm->length < 12) {
  807. printf (_("CRITICAL - Wrong time format in certificate.\n"));
  808. return STATE_CRITICAL;
  809. }
  810. else {
  811. stamp.tm_year =
  812. (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
  813. (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
  814. stamp.tm_year -= 1900;
  815. offset = 2;
  816. }
  817. }
  818. stamp.tm_mon =
  819. (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
  820. stamp.tm_mday =
  821. (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
  822. stamp.tm_hour =
  823. (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
  824. stamp.tm_min =
  825. (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
  826. stamp.tm_sec = 0;
  827. stamp.tm_isdst = -1;
  828. days_left = (mktime (&stamp) - time (NULL)) / 86400;
  829. snprintf
  830. (timestamp, 16, "%02d/%02d/%04d %02d:%02d",
  831. stamp.tm_mon + 1,
  832. stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
  833. if (days_left > 0 && days_left <= days_till_exp) {
  834. printf (_("WARNING - Certificate expires in %d day(s) (%s).\n"), days_left, timestamp);
  835. return STATE_WARNING;
  836. }
  837. if (days_left < 0) {
  838. printf (_("CRITICAL - Certificate expired on %s.\n"), timestamp);
  839. return STATE_CRITICAL;
  840. }
  841. if (days_left == 0) {
  842. printf (_("WARNING - Certificate expires today (%s).\n"), timestamp);
  843. return STATE_WARNING;
  844. }
  845. printf (_("OK - Certificate will expire on %s.\n"), timestamp);
  846. return STATE_OK;
  847. }
  848. #endif
  849. int
  850. my_recv (void)
  851. {
  852. int i;
  853. #ifdef HAVE_SSL
  854. if (use_ssl) {
  855. i = SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1);
  856. }
  857. else {
  858. i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
  859. }
  860. #else
  861. i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
  862. #endif
  863. return i;
  864. }
  865. int
  866. my_close (void)
  867. {
  868. #ifdef HAVE_SSL
  869. if (use_ssl == TRUE) {
  870. SSL_shutdown (ssl);
  871. SSL_free (ssl);
  872. SSL_CTX_free (ctx);
  873. return 0;
  874. }
  875. else {
  876. #endif
  877. return close (sd);
  878. #ifdef HAVE_SSL
  879. }
  880. #endif
  881. }
  882. void
  883. print_help (void)
  884. {
  885. print_revision (progname, revision);
  886. printf (_("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"));
  887. printf (_(COPYRIGHT), copyright, email);
  888. printf (_("\
  889. This plugin tests the HTTP service on the specified host. It can test\n\
  890. normal (http) and secure (https) servers, follow redirects, search for\n\
  891. strings and regular expressions, check connection times, and report on\n\
  892. certificate expiration times.\n"));
  893. print_usage ();
  894. printf (_("NOTE: One or both of -H and -I must be specified\n"));
  895. printf (_(UT_HELP_VRSN));
  896. printf (_("\
  897. -H, --hostname=ADDRESS\n\
  898. Host name argument for servers using host headers (virtual host)\n\
  899. -I, --IP-address=ADDRESS\n\
  900. IP address or name (use numeric address if possible to bypass DNS lookup).\n\
  901. -p, --port=INTEGER\n\
  902. Port number (default: %d)\n"), HTTP_PORT);
  903. printf (_(UT_IPv46));
  904. #ifdef HAVE_SSL
  905. printf (_("\
  906. -S, --ssl\n\
  907. Connect via SSL\n\
  908. -C, --certificate=INTEGER\n\
  909. Minimum number of days a certificate has to be valid.\n\
  910. (when this option is used the url is not checked.)\n"));
  911. #endif
  912. printf (_("\
  913. -e, --expect=STRING\n\
  914. String to expect in first (status) line of server response (default: %s)\n\
  915. If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
  916. -s, --string=STRING\n\
  917. String to expect in the content\n\
  918. -u, --url=PATH\n\
  919. URL to GET or POST (default: /)\n\
  920. -P, --post=STRING\n\
  921. URL encoded http POST data\n"), HTTP_EXPECT);
  922. #ifdef HAVE_REGEX_H
  923. printf (_("\
  924. -l, --linespan\n\
  925. Allow regex to span newlines (must precede -r or -R)\n\
  926. -r, --regex, --ereg=STRING\n\
  927. Search page for regex STRING\n\
  928. -R, --eregi=STRING\n\
  929. Search page for case-insensitive regex STRING\n"));
  930. #endif
  931. printf (_("\
  932. -a, --authorization=AUTH_PAIR\n\
  933. Username:password on sites with basic authentication\n\
  934. -L, --link=URL\n\
  935. Wrap output in HTML link (obsoleted by urlize)\n\
  936. -f, --onredirect=<ok|warning|critical|follow>\n\
  937. How to handle redirected pages\n\
  938. -m, --min=INTEGER\n\
  939. Minimum page size required (bytes)\n"));
  940. printf (_(UT_WARN_CRIT));
  941. printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
  942. printf (_(UT_VERBOSE));
  943. printf (_("\
  944. This plugin will attempt to open an HTTP connection with the host. Successful\n\
  945. connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
  946. errors return STATE_UNKNOWN. Successful connects, but incorrect reponse\n\
  947. messages from the host result in STATE_WARNING return values. If you are\n\
  948. checking a virtual server that uses 'host headers' you must supply the FQDN\n\
  949. (fully qualified domain name) as the [host_name] argument.\n"));
  950. #ifdef HAVE_SSL
  951. printf (_("\n\
  952. This plugin can also check whether an SSL enabled web server is able to\n\
  953. serve content (optionally within a specified time) or whether the X509 \n\
  954. certificate is still valid for the specified number of days.\n"));
  955. printf (_("\n\
  956. CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
  957. When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
  958. STATE_OK will be returned. When the server returns its content but exceeds\n\
  959. the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
  960. a STATE_CRITICAL will be returned.\n\n"));
  961. printf (_("\
  962. CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
  963. When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
  964. STATE_OK is returned. When the certificate is still valid, but for less than\n\
  965. 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
  966. the certificate is expired.\n"));
  967. #endif
  968. printf (_(UT_SUPPORT));
  969. }
  970. void
  971. print_usage (void)
  972. {
  973. printf (_("\
  974. Usage: %s (-H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
  975. [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
  976. [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
  977. [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
  978. [-P string] [-m min_pg_size] [-4|-6]\n"), progname);
  979. printf (_(UT_HLP_VRS), progname, progname);
  980. }