check_http.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341
  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. $Id$
  14. ******************************************************************************/
  15. /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
  16. const char *progname = "check_http";
  17. const char *revision = "$Revision$";
  18. const char *copyright = "1999-2005";
  19. const char *email = "nagiosplug-devel@lists.sourceforge.net";
  20. #include "common.h"
  21. #include "netutils.h"
  22. #include "utils.h"
  23. #define INPUT_DELIMITER ";"
  24. #define HTTP_EXPECT "HTTP/1."
  25. enum {
  26. MAX_IPV4_HOSTLENGTH = 255,
  27. HTTP_PORT = 80,
  28. HTTPS_PORT = 443
  29. };
  30. #ifdef HAVE_SSL
  31. int check_cert = FALSE;
  32. int days_till_exp;
  33. char *randbuff;
  34. X509 *server_cert;
  35. # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
  36. # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
  37. #else /* ifndef HAVE_SSL */
  38. # define my_recv(buf, len) read(sd, buf, len)
  39. # define my_send(buf, len) send(sd, buf, len, 0)
  40. #endif /* HAVE_SSL */
  41. int no_body = FALSE;
  42. int maximum_age = -1;
  43. #ifdef HAVE_REGEX_H
  44. enum {
  45. REGS = 2,
  46. MAX_RE_SIZE = 256
  47. };
  48. #include <regex.h>
  49. regex_t preg;
  50. regmatch_t pmatch[REGS];
  51. char regexp[MAX_RE_SIZE];
  52. char errbuf[MAX_INPUT_BUFFER];
  53. int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
  54. int errcode;
  55. #endif
  56. struct timeval tv;
  57. #define HTTP_URL "/"
  58. #define CRLF "\r\n"
  59. char timestamp[17] = "";
  60. int specify_port = FALSE;
  61. int server_port = HTTP_PORT;
  62. char server_port_text[6] = "";
  63. char server_type[6] = "http";
  64. char *server_address;
  65. char *host_name;
  66. char *server_url;
  67. char *user_agent;
  68. int server_url_length;
  69. int server_expect_yn = 0;
  70. char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
  71. char string_expect[MAX_INPUT_BUFFER] = "";
  72. double warning_time = 0;
  73. int check_warning_time = FALSE;
  74. double critical_time = 0;
  75. int check_critical_time = FALSE;
  76. char user_auth[MAX_INPUT_BUFFER] = "";
  77. int display_html = FALSE;
  78. char *http_opt_headers;
  79. int onredirect = STATE_OK;
  80. int use_ssl = FALSE;
  81. int verbose = FALSE;
  82. int sd;
  83. int min_page_len = 0;
  84. int max_page_len = 0;
  85. int redir_depth = 0;
  86. int max_depth = 15;
  87. char *http_method;
  88. char *http_post_data;
  89. char *http_content_type;
  90. char buffer[MAX_INPUT_BUFFER];
  91. int process_arguments (int, char **);
  92. static char *base64 (const char *bin, size_t len);
  93. int check_http (void);
  94. void redir (char *pos, char *status_line);
  95. int server_type_check(const char *type);
  96. int server_port_check(int ssl_flag);
  97. char *perfd_time (double microsec);
  98. char *perfd_size (int page_len);
  99. void print_help (void);
  100. void print_usage (void);
  101. int
  102. main (int argc, char **argv)
  103. {
  104. int result = STATE_UNKNOWN;
  105. /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
  106. server_url = strdup(HTTP_URL);
  107. server_url_length = strlen(server_url);
  108. asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
  109. clean_revstring (revision), VERSION);
  110. if (process_arguments (argc, argv) == ERROR)
  111. usage4 (_("Could not parse arguments"));
  112. if (strstr (timestamp, ":")) {
  113. if (strstr (server_url, "?"))
  114. asprintf (&server_url, "%s&%s", server_url, timestamp);
  115. else
  116. asprintf (&server_url, "%s?%s", server_url, timestamp);
  117. }
  118. if (display_html == TRUE)
  119. printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
  120. use_ssl ? "https" : "http", host_name,
  121. server_port, server_url);
  122. /* initialize alarm signal handling, set socket timeout, start timer */
  123. (void) signal (SIGALRM, socket_timeout_alarm_handler);
  124. (void) alarm (socket_timeout);
  125. gettimeofday (&tv, NULL);
  126. result = check_http ();
  127. return result;
  128. }
  129. /* process command-line arguments */
  130. int
  131. process_arguments (int argc, char **argv)
  132. {
  133. int c = 1;
  134. int option = 0;
  135. static struct option longopts[] = {
  136. STD_LONG_OPTS,
  137. {"file",required_argument,0,'F'},
  138. {"link", no_argument, 0, 'L'},
  139. {"nohtml", no_argument, 0, 'n'},
  140. {"ssl", no_argument, 0, 'S'},
  141. {"verbose", no_argument, 0, 'v'},
  142. {"post", required_argument, 0, 'P'},
  143. {"IP-address", required_argument, 0, 'I'},
  144. {"url", required_argument, 0, 'u'},
  145. {"string", required_argument, 0, 's'},
  146. {"regex", required_argument, 0, 'r'},
  147. {"ereg", required_argument, 0, 'r'},
  148. {"eregi", required_argument, 0, 'R'},
  149. {"linespan", no_argument, 0, 'l'},
  150. {"onredirect", required_argument, 0, 'f'},
  151. {"certificate", required_argument, 0, 'C'},
  152. {"useragent", required_argument, 0, 'A'},
  153. {"header", required_argument, 0, 'k'},
  154. {"no-body", no_argument, 0, 'N'},
  155. {"max-age", required_argument, 0, 'M'},
  156. {"content-type", required_argument, 0, 'T'},
  157. {"pagesize", required_argument, 0, 'm'},
  158. {"use-ipv4", no_argument, 0, '4'},
  159. {"use-ipv6", no_argument, 0, '6'},
  160. {0, 0, 0, 0}
  161. };
  162. if (argc < 2)
  163. return ERROR;
  164. for (c = 1; c < argc; c++) {
  165. if (strcmp ("-to", argv[c]) == 0)
  166. strcpy (argv[c], "-t");
  167. if (strcmp ("-hn", argv[c]) == 0)
  168. strcpy (argv[c], "-H");
  169. if (strcmp ("-wt", argv[c]) == 0)
  170. strcpy (argv[c], "-w");
  171. if (strcmp ("-ct", argv[c]) == 0)
  172. strcpy (argv[c], "-c");
  173. if (strcmp ("-nohtml", argv[c]) == 0)
  174. strcpy (argv[c], "-n");
  175. }
  176. while (1) {
  177. c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option);
  178. if (c == -1 || c == EOF)
  179. break;
  180. switch (c) {
  181. case '?': /* usage */
  182. usage2 (_("Unknown argument"), optarg);
  183. break;
  184. case 'h': /* help */
  185. print_help ();
  186. exit (STATE_OK);
  187. break;
  188. case 'V': /* version */
  189. print_revision (progname, revision);
  190. exit (STATE_OK);
  191. break;
  192. case 't': /* timeout period */
  193. if (!is_intnonneg (optarg))
  194. usage2 (_("Timeout interval must be a positive integer"), optarg);
  195. else
  196. socket_timeout = atoi (optarg);
  197. break;
  198. case 'c': /* critical time threshold */
  199. if (!is_nonnegative (optarg))
  200. usage2 (_("Critical threshold must be integer"), optarg);
  201. else {
  202. critical_time = strtod (optarg, NULL);
  203. check_critical_time = TRUE;
  204. }
  205. break;
  206. case 'w': /* warning time threshold */
  207. if (!is_nonnegative (optarg))
  208. usage2 (_("Warning threshold must be integer"), optarg);
  209. else {
  210. warning_time = strtod (optarg, NULL);
  211. check_warning_time = TRUE;
  212. }
  213. break;
  214. case 'A': /* User Agent String */
  215. asprintf (&user_agent, "User-Agent: %s", optarg);
  216. break;
  217. case 'k': /* Additional headers */
  218. asprintf (&http_opt_headers, "%s", optarg);
  219. break;
  220. case 'L': /* show html link */
  221. display_html = TRUE;
  222. break;
  223. case 'n': /* do not show html link */
  224. display_html = FALSE;
  225. break;
  226. case 'S': /* use SSL */
  227. #ifndef HAVE_SSL
  228. usage4 (_("Invalid option - SSL is not available"));
  229. #endif
  230. use_ssl = TRUE;
  231. if (specify_port == FALSE)
  232. server_port = HTTPS_PORT;
  233. break;
  234. case 'C': /* Check SSL cert validity */
  235. #ifdef USE_OPENSSL
  236. if (!is_intnonneg (optarg))
  237. usage2 (_("Invalid certificate expiration period"), optarg);
  238. else {
  239. days_till_exp = atoi (optarg);
  240. check_cert = TRUE;
  241. }
  242. #else
  243. usage4 (_("Invalid option - SSL is not available"));
  244. #endif
  245. break;
  246. case 'f': /* onredirect */
  247. if (!strcmp (optarg, "follow"))
  248. onredirect = STATE_DEPENDENT;
  249. if (!strcmp (optarg, "unknown"))
  250. onredirect = STATE_UNKNOWN;
  251. if (!strcmp (optarg, "ok"))
  252. onredirect = STATE_OK;
  253. if (!strcmp (optarg, "warning"))
  254. onredirect = STATE_WARNING;
  255. if (!strcmp (optarg, "critical"))
  256. onredirect = STATE_CRITICAL;
  257. if (verbose)
  258. printf(_("option f:%d \n"), onredirect);
  259. break;
  260. /* Note: H, I, and u must be malloc'd or will fail on redirects */
  261. case 'H': /* Host Name (virtual host) */
  262. host_name = strdup (optarg);
  263. if (strstr (optarg, ":"))
  264. sscanf (optarg, "%*[^:]:%d", &server_port);
  265. break;
  266. case 'I': /* Server IP-address */
  267. server_address = strdup (optarg);
  268. break;
  269. case 'u': /* URL path */
  270. server_url = strdup (optarg);
  271. server_url_length = strlen (server_url);
  272. break;
  273. case 'p': /* Server port */
  274. if (!is_intnonneg (optarg))
  275. usage2 (_("Invalid port number"), optarg);
  276. else {
  277. server_port = atoi (optarg);
  278. specify_port = TRUE;
  279. }
  280. break;
  281. case 'a': /* authorization info */
  282. strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
  283. user_auth[MAX_INPUT_BUFFER - 1] = 0;
  284. break;
  285. case 'P': /* HTTP POST data in URL encoded format */
  286. if (http_method || http_post_data) break;
  287. http_method = strdup("POST");
  288. http_post_data = strdup (optarg);
  289. break;
  290. case 's': /* string or substring */
  291. strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
  292. string_expect[MAX_INPUT_BUFFER - 1] = 0;
  293. break;
  294. case 'e': /* string or substring */
  295. strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
  296. server_expect[MAX_INPUT_BUFFER - 1] = 0;
  297. server_expect_yn = 1;
  298. break;
  299. case 'T': /* Content-type */
  300. asprintf (&http_content_type, "%s", optarg);
  301. break;
  302. #ifndef HAVE_REGEX_H
  303. case 'l': /* linespan */
  304. case 'r': /* linespan */
  305. case 'R': /* linespan */
  306. usage4 (_("Call for regex which was not a compiled option"));
  307. break;
  308. #else
  309. case 'l': /* linespan */
  310. cflags &= ~REG_NEWLINE;
  311. break;
  312. case 'R': /* regex */
  313. cflags |= REG_ICASE;
  314. case 'r': /* regex */
  315. strncpy (regexp, optarg, MAX_RE_SIZE - 1);
  316. regexp[MAX_RE_SIZE - 1] = 0;
  317. errcode = regcomp (&preg, regexp, cflags);
  318. if (errcode != 0) {
  319. (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
  320. printf (_("Could Not Compile Regular Expression: %s"), errbuf);
  321. return ERROR;
  322. }
  323. break;
  324. #endif
  325. case '4':
  326. address_family = AF_INET;
  327. break;
  328. case '6':
  329. #ifdef USE_IPV6
  330. address_family = AF_INET6;
  331. #else
  332. usage4 (_("IPv6 support not available"));
  333. #endif
  334. break;
  335. case 'v': /* verbose */
  336. verbose = TRUE;
  337. break;
  338. case 'm': /* min_page_length */
  339. {
  340. char *tmp;
  341. if (strchr(optarg, ':') != (char *)NULL) {
  342. /* range, so get two values, min:max */
  343. tmp = strtok(optarg, ":");
  344. if (tmp == NULL) {
  345. printf("Bad format: try \"-m min:max\"\n");
  346. exit (STATE_WARNING);
  347. } else
  348. min_page_len = atoi(tmp);
  349. tmp = strtok(NULL, ":");
  350. if (tmp == NULL) {
  351. printf("Bad format: try \"-m min:max\"\n");
  352. exit (STATE_WARNING);
  353. } else
  354. max_page_len = atoi(tmp);
  355. } else
  356. min_page_len = atoi (optarg);
  357. break;
  358. }
  359. case 'N': /* no-body */
  360. no_body = TRUE;
  361. break;
  362. case 'M': /* max-age */
  363. {
  364. int L = strlen(optarg);
  365. if (L && optarg[L-1] == 'm')
  366. maximum_age = atoi (optarg) * 60;
  367. else if (L && optarg[L-1] == 'h')
  368. maximum_age = atoi (optarg) * 60 * 60;
  369. else if (L && optarg[L-1] == 'd')
  370. maximum_age = atoi (optarg) * 60 * 60 * 24;
  371. else if (L && (optarg[L-1] == 's' ||
  372. isdigit (optarg[L-1])))
  373. maximum_age = atoi (optarg);
  374. else {
  375. fprintf (stderr, "unparsable max-age: %s\n", optarg);
  376. exit (STATE_WARNING);
  377. }
  378. }
  379. break;
  380. }
  381. }
  382. c = optind;
  383. if (server_address == NULL && c < argc)
  384. server_address = strdup (argv[c++]);
  385. if (host_name == NULL && c < argc)
  386. host_name = strdup (argv[c++]);
  387. if (server_address == NULL) {
  388. if (host_name == NULL)
  389. usage4 (_("You must specify a server address or host name"));
  390. else
  391. server_address = strdup (host_name);
  392. }
  393. if (check_critical_time && critical_time>(double)socket_timeout)
  394. socket_timeout = (int)critical_time + 1;
  395. if (http_method == NULL)
  396. http_method = strdup ("GET");
  397. return TRUE;
  398. }
  399. /* written by lauri alanko */
  400. static char *
  401. base64 (const char *bin, size_t len)
  402. {
  403. char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
  404. size_t i = 0, j = 0;
  405. char BASE64_END = '=';
  406. char base64_table[64];
  407. strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
  408. while (j < len - 2) {
  409. buf[i++] = base64_table[bin[j] >> 2];
  410. buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
  411. buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
  412. buf[i++] = base64_table[bin[j + 2] & 63];
  413. j += 3;
  414. }
  415. switch (len - j) {
  416. case 1:
  417. buf[i++] = base64_table[bin[j] >> 2];
  418. buf[i++] = base64_table[(bin[j] & 3) << 4];
  419. buf[i++] = BASE64_END;
  420. buf[i++] = BASE64_END;
  421. break;
  422. case 2:
  423. buf[i++] = base64_table[bin[j] >> 2];
  424. buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
  425. buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
  426. buf[i++] = BASE64_END;
  427. break;
  428. case 0:
  429. break;
  430. }
  431. buf[i] = '\0';
  432. return buf;
  433. }
  434. /* Returns 1 if we're done processing the document body; 0 to keep going */
  435. static int
  436. document_headers_done (char *full_page)
  437. {
  438. const char *body;
  439. for (body = full_page; *body; body++) {
  440. if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
  441. break;
  442. }
  443. if (!*body)
  444. return 0; /* haven't read end of headers yet */
  445. full_page[body - full_page] = 0;
  446. return 1;
  447. }
  448. static time_t
  449. parse_time_string (const char *string)
  450. {
  451. struct tm tm;
  452. time_t t;
  453. memset (&tm, 0, sizeof(tm));
  454. /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
  455. if (isupper (string[0]) && /* Tue */
  456. islower (string[1]) &&
  457. islower (string[2]) &&
  458. ',' == string[3] &&
  459. ' ' == string[4] &&
  460. (isdigit(string[5]) || string[5] == ' ') && /* 25 */
  461. isdigit (string[6]) &&
  462. ' ' == string[7] &&
  463. isupper (string[8]) && /* Dec */
  464. islower (string[9]) &&
  465. islower (string[10]) &&
  466. ' ' == string[11] &&
  467. isdigit (string[12]) && /* 2001 */
  468. isdigit (string[13]) &&
  469. isdigit (string[14]) &&
  470. isdigit (string[15]) &&
  471. ' ' == string[16] &&
  472. isdigit (string[17]) && /* 02: */
  473. isdigit (string[18]) &&
  474. ':' == string[19] &&
  475. isdigit (string[20]) && /* 59: */
  476. isdigit (string[21]) &&
  477. ':' == string[22] &&
  478. isdigit (string[23]) && /* 03 */
  479. isdigit (string[24]) &&
  480. ' ' == string[25] &&
  481. 'G' == string[26] && /* GMT */
  482. 'M' == string[27] && /* GMT */
  483. 'T' == string[28]) {
  484. tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
  485. tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
  486. tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
  487. tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
  488. tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
  489. !strncmp (string+8, "Feb", 3) ? 1 :
  490. !strncmp (string+8, "Mar", 3) ? 2 :
  491. !strncmp (string+8, "Apr", 3) ? 3 :
  492. !strncmp (string+8, "May", 3) ? 4 :
  493. !strncmp (string+8, "Jun", 3) ? 5 :
  494. !strncmp (string+8, "Jul", 3) ? 6 :
  495. !strncmp (string+8, "Aug", 3) ? 7 :
  496. !strncmp (string+8, "Sep", 3) ? 8 :
  497. !strncmp (string+8, "Oct", 3) ? 9 :
  498. !strncmp (string+8, "Nov", 3) ? 10 :
  499. !strncmp (string+8, "Dec", 3) ? 11 :
  500. -1);
  501. tm.tm_year = ((1000 * (string[12]-'0') +
  502. 100 * (string[13]-'0') +
  503. 10 * (string[14]-'0') +
  504. (string[15]-'0'))
  505. - 1900);
  506. tm.tm_isdst = 0; /* GMT is never in DST, right? */
  507. if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
  508. return 0;
  509. /*
  510. This is actually wrong: we need to subtract the local timezone
  511. offset from GMT from this value. But, that's ok in this usage,
  512. because we only comparing these two GMT dates against each other,
  513. so it doesn't matter what time zone we parse them in.
  514. */
  515. t = mktime (&tm);
  516. if (t == (time_t) -1) t = 0;
  517. if (verbose) {
  518. const char *s = string;
  519. while (*s && *s != '\r' && *s != '\n')
  520. fputc (*s++, stdout);
  521. printf (" ==> %lu\n", (unsigned long) t);
  522. }
  523. return t;
  524. } else {
  525. return 0;
  526. }
  527. }
  528. static void
  529. check_document_dates (const char *headers)
  530. {
  531. const char *s;
  532. char *server_date = 0;
  533. char *document_date = 0;
  534. s = headers;
  535. while (*s) {
  536. const char *field = s;
  537. const char *value = 0;
  538. /* Find the end of the header field */
  539. while (*s && !isspace(*s) && *s != ':')
  540. s++;
  541. /* Remember the header value, if any. */
  542. if (*s == ':')
  543. value = ++s;
  544. /* Skip to the end of the header, including continuation lines. */
  545. while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
  546. s++;
  547. s++;
  548. /* Process this header. */
  549. if (value && value > field+2) {
  550. char *ff = (char *) malloc (value-field);
  551. char *ss = ff;
  552. while (field < value-1)
  553. *ss++ = tolower(*field++);
  554. *ss++ = 0;
  555. if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
  556. const char *e;
  557. while (*value && isspace (*value))
  558. value++;
  559. for (e = value; *e && *e != '\r' && *e != '\n'; e++)
  560. ;
  561. ss = (char *) malloc (e - value + 1);
  562. strncpy (ss, value, e - value);
  563. ss[e - value] = 0;
  564. if (!strcmp (ff, "date")) {
  565. if (server_date) free (server_date);
  566. server_date = ss;
  567. } else {
  568. if (document_date) free (document_date);
  569. document_date = ss;
  570. }
  571. }
  572. free (ff);
  573. }
  574. }
  575. /* Done parsing the body. Now check the dates we (hopefully) parsed. */
  576. if (!server_date || !*server_date) {
  577. die (STATE_UNKNOWN, _("Server date unknown\n"));
  578. } else if (!document_date || !*document_date) {
  579. die (STATE_CRITICAL, _("Document modification date unknown\n"));
  580. } else {
  581. time_t srv_data = parse_time_string (server_date);
  582. time_t doc_data = parse_time_string (document_date);
  583. if (srv_data <= 0) {
  584. die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
  585. } else if (doc_data <= 0) {
  586. die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
  587. } else if (doc_data > srv_data + 30) {
  588. die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
  589. } else if (doc_data < srv_data - maximum_age) {
  590. int n = (srv_data - doc_data);
  591. if (n > (60 * 60 * 24 * 2))
  592. die (STATE_CRITICAL,
  593. _("CRITICAL - Last modified %.1f days ago\n"),
  594. ((float) n) / (60 * 60 * 24));
  595. else
  596. die (STATE_CRITICAL,
  597. _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
  598. n / (60 * 60), (n / 60) % 60, n % 60);
  599. }
  600. free (server_date);
  601. free (document_date);
  602. }
  603. }
  604. int
  605. get_content_length (const char *headers)
  606. {
  607. const char *s;
  608. int content_length = 0;
  609. s = headers;
  610. while (*s) {
  611. const char *field = s;
  612. const char *value = 0;
  613. /* Find the end of the header field */
  614. while (*s && !isspace(*s) && *s != ':')
  615. s++;
  616. /* Remember the header value, if any. */
  617. if (*s == ':')
  618. value = ++s;
  619. /* Skip to the end of the header, including continuation lines. */
  620. while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
  621. s++;
  622. s++;
  623. /* Process this header. */
  624. if (value && value > field+2) {
  625. char *ff = (char *) malloc (value-field);
  626. char *ss = ff;
  627. while (field < value-1)
  628. *ss++ = tolower(*field++);
  629. *ss++ = 0;
  630. if (!strcmp (ff, "content-length")) {
  631. const char *e;
  632. while (*value && isspace (*value))
  633. value++;
  634. for (e = value; *e && *e != '\r' && *e != '\n'; e++)
  635. ;
  636. ss = (char *) malloc (e - value + 1);
  637. strncpy (ss, value, e - value);
  638. ss[e - value] = 0;
  639. content_length = atoi(ss);
  640. free (ss);
  641. }
  642. free (ff);
  643. }
  644. }
  645. return (content_length);
  646. }
  647. int
  648. check_http (void)
  649. {
  650. char *msg;
  651. char *status_line;
  652. char *status_code;
  653. char *header;
  654. char *page;
  655. char *auth;
  656. int http_status;
  657. int i = 0;
  658. size_t pagesize = 0;
  659. char *full_page;
  660. char *buf;
  661. char *pos;
  662. long microsec;
  663. double elapsed_time;
  664. int page_len = 0;
  665. int result = STATE_UNKNOWN;
  666. /* try to connect to the host at the given port number */
  667. if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
  668. die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
  669. #ifdef HAVE_SSL
  670. if (use_ssl == TRUE) {
  671. np_net_ssl_init(sd);
  672. if (check_cert == TRUE) {
  673. result = np_net_ssl_check_cert(days_till_exp);
  674. if(result != STATE_OK){
  675. np_net_ssl_cleanup();
  676. if(sd) close(sd);
  677. return result;
  678. }
  679. }
  680. }
  681. #endif /* HAVE_SSL */
  682. asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
  683. /* optionally send the host header info */
  684. if (host_name)
  685. asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
  686. /* optionally send any other header tag */
  687. if (http_opt_headers) {
  688. for ((pos = strtok(http_opt_headers, INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
  689. asprintf (&buf, "%s%s\r\n", buf, pos);
  690. }
  691. /* optionally send the authentication info */
  692. if (strlen(user_auth)) {
  693. auth = base64 (user_auth, strlen (user_auth));
  694. asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
  695. }
  696. /* either send http POST data */
  697. if (http_post_data) {
  698. if (http_content_type) {
  699. asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
  700. } else {
  701. asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
  702. }
  703. asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
  704. asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
  705. }
  706. else {
  707. /* or just a newline so the server knows we're done with the request */
  708. asprintf (&buf, "%s%s", buf, CRLF);
  709. }
  710. if (verbose) printf ("%s\n", buf);
  711. my_send (buf, strlen (buf));
  712. /* fetch the page */
  713. full_page = strdup("");
  714. while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
  715. buffer[i] = '\0';
  716. asprintf (&full_page, "%s%s", full_page, buffer);
  717. pagesize += i;
  718. if (no_body && document_headers_done (full_page)) {
  719. i = 0;
  720. break;
  721. }
  722. }
  723. if (i < 0 && errno != ECONNRESET) {
  724. #ifdef HAVE_SSL
  725. /*
  726. if (use_ssl) {
  727. sslerr=SSL_get_error(ssl, i);
  728. if ( sslerr == SSL_ERROR_SSL ) {
  729. die (STATE_WARNING, _("Client Certificate Required\n"));
  730. } else {
  731. die (STATE_CRITICAL, _("Error on receive\n"));
  732. }
  733. }
  734. else {
  735. */
  736. #endif
  737. die (STATE_CRITICAL, _("Error on receive\n"));
  738. #ifdef HAVE_SSL
  739. /* XXX
  740. }
  741. */
  742. #endif
  743. }
  744. /* return a CRITICAL status if we couldn't read any data */
  745. if (pagesize == (size_t) 0)
  746. die (STATE_CRITICAL, _("No data received %s\n"), timestamp);
  747. /* close the connection */
  748. #ifdef HAVE_SSL
  749. np_net_ssl_cleanup();
  750. #endif
  751. if(sd) close(sd);
  752. /* reset the alarm */
  753. alarm (0);
  754. /* leave full_page untouched so we can free it later */
  755. page = full_page;
  756. if (verbose)
  757. printf ("%s://%s:%d%s is %d characters\n",
  758. use_ssl ? "https" : "http", server_address,
  759. server_port, server_url, (int)pagesize);
  760. /* find status line and null-terminate it */
  761. status_line = page;
  762. page += (size_t) strcspn (page, "\r\n");
  763. pos = page;
  764. page += (size_t) strspn (page, "\r\n");
  765. status_line[strcspn(status_line, "\r\n")] = 0;
  766. strip (status_line);
  767. if (verbose)
  768. printf ("STATUS: %s\n", status_line);
  769. /* find header info and null-terminate it */
  770. header = page;
  771. while (strcspn (page, "\r\n") > 0) {
  772. page += (size_t) strcspn (page, "\r\n");
  773. pos = page;
  774. if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
  775. (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
  776. page += (size_t) 2;
  777. else
  778. page += (size_t) 1;
  779. }
  780. page += (size_t) strspn (page, "\r\n");
  781. header[pos - header] = 0;
  782. if (verbose)
  783. printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
  784. (no_body ? " [[ skipped ]]" : page));
  785. /* make sure the status line matches the response we are looking for */
  786. if (!strstr (status_line, server_expect)) {
  787. if (server_port == HTTP_PORT)
  788. asprintf (&msg,
  789. _("Invalid HTTP response received from host\n"));
  790. else
  791. asprintf (&msg,
  792. _("Invalid HTTP response received from host on port %d\n"),
  793. server_port);
  794. die (STATE_CRITICAL, "%s", msg);
  795. }
  796. /* Exit here if server_expect was set by user and not default */
  797. if ( server_expect_yn ) {
  798. asprintf (&msg,
  799. _("HTTP OK: Status line output matched \"%s\"\n"),
  800. server_expect);
  801. if (verbose)
  802. printf ("%s\n",msg);
  803. }
  804. else {
  805. /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
  806. /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
  807. /* Status-Code = 3 DIGITS */
  808. status_code = strchr (status_line, ' ') + sizeof (char);
  809. if (strspn (status_code, "1234567890") != 3)
  810. die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
  811. http_status = atoi (status_code);
  812. /* check the return code */
  813. if (http_status >= 600 || http_status < 100)
  814. die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
  815. /* server errors result in a critical state */
  816. else if (http_status >= 500)
  817. die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
  818. /* client errors result in a warning state */
  819. else if (http_status >= 400)
  820. die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
  821. /* check redirected page if specified */
  822. else if (http_status >= 300) {
  823. if (onredirect == STATE_DEPENDENT)
  824. redir (header, status_line);
  825. else if (onredirect == STATE_UNKNOWN)
  826. printf (_("UNKNOWN"));
  827. else if (onredirect == STATE_OK)
  828. printf (_("OK"));
  829. else if (onredirect == STATE_WARNING)
  830. printf (_("WARNING"));
  831. else if (onredirect == STATE_CRITICAL)
  832. printf (_("CRITICAL"));
  833. microsec = deltime (tv);
  834. elapsed_time = (double)microsec / 1.0e6;
  835. die (onredirect,
  836. _(" - %s - %.3f second response time %s%s|%s %s\n"),
  837. status_line, elapsed_time, timestamp,
  838. (display_html ? "</A>" : ""),
  839. perfd_time (elapsed_time), perfd_size (pagesize));
  840. } /* end if (http_status >= 300) */
  841. } /* end else (server_expect_yn) */
  842. if (maximum_age >= 0) {
  843. check_document_dates (header);
  844. }
  845. /* check elapsed time */
  846. microsec = deltime (tv);
  847. elapsed_time = (double)microsec / 1.0e6;
  848. asprintf (&msg,
  849. _("HTTP WARNING: %s - %.3f second response time %s%s|%s %s\n"),
  850. status_line, elapsed_time, timestamp,
  851. (display_html ? "</A>" : ""),
  852. perfd_time (elapsed_time), perfd_size (pagesize));
  853. if (check_critical_time == TRUE && elapsed_time > critical_time)
  854. die (STATE_CRITICAL, "%s", msg);
  855. if (check_warning_time == TRUE && elapsed_time > warning_time)
  856. die (STATE_WARNING, "%s", msg);
  857. /* Page and Header content checks go here */
  858. /* these checks should be last */
  859. if (strlen (string_expect)) {
  860. if (strstr (page, string_expect)) {
  861. printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
  862. status_line, elapsed_time,
  863. timestamp, (display_html ? "</A>" : ""),
  864. perfd_time (elapsed_time), perfd_size (pagesize));
  865. exit (STATE_OK);
  866. }
  867. else {
  868. printf (_("CRITICAL - string not found%s|%s %s\n"),
  869. (display_html ? "</A>" : ""),
  870. perfd_time (elapsed_time), perfd_size (pagesize));
  871. exit (STATE_CRITICAL);
  872. }
  873. }
  874. #ifdef HAVE_REGEX_H
  875. if (strlen (regexp)) {
  876. errcode = regexec (&preg, page, REGS, pmatch, 0);
  877. if (errcode == 0) {
  878. printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
  879. status_line, elapsed_time,
  880. timestamp, (display_html ? "</A>" : ""),
  881. perfd_time (elapsed_time), perfd_size (pagesize));
  882. exit (STATE_OK);
  883. }
  884. else {
  885. if (errcode == REG_NOMATCH) {
  886. printf (_("CRITICAL - pattern not found%s|%s %s\n"),
  887. (display_html ? "</A>" : ""),
  888. perfd_time (elapsed_time), perfd_size (pagesize));
  889. exit (STATE_CRITICAL);
  890. }
  891. else {
  892. regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
  893. printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
  894. exit (STATE_CRITICAL);
  895. }
  896. }
  897. }
  898. #endif
  899. /* make sure the page is of an appropriate size */
  900. /* page_len = get_content_length(header); */
  901. page_len = pagesize;
  902. if ((max_page_len > 0) && (page_len > max_page_len)) {
  903. printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
  904. page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
  905. exit (STATE_WARNING);
  906. } else if ((min_page_len > 0) && (page_len < min_page_len)) {
  907. printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
  908. page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
  909. exit (STATE_WARNING);
  910. }
  911. /* We only get here if all tests have been passed */
  912. asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s%s|%s %s\n"),
  913. status_line, page_len, elapsed_time,
  914. timestamp, (display_html ? "</A>" : ""),
  915. perfd_time (elapsed_time), perfd_size (page_len));
  916. die (STATE_OK, "%s", msg);
  917. return STATE_UNKNOWN;
  918. }
  919. /* per RFC 2396 */
  920. #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
  921. #define URI_HTTP "%[HTPShtps]://"
  922. #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
  923. #define URI_PORT ":%[0123456789]"
  924. #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
  925. #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
  926. #define HD2 URI_HTTP URI_HOST URI_PATH
  927. #define HD3 URI_HTTP URI_HOST URI_PORT
  928. #define HD4 URI_HTTP URI_HOST
  929. #define HD5 URI_PATH
  930. void
  931. redir (char *pos, char *status_line)
  932. {
  933. int i = 0;
  934. char *x;
  935. char xx[2];
  936. char type[6];
  937. char *addr;
  938. char port[6];
  939. char *url;
  940. addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
  941. if (addr == NULL)
  942. die (STATE_UNKNOWN, _("Could not allocate addr\n"));
  943. url = malloc (strcspn (pos, "\r\n"));
  944. if (url == NULL)
  945. die (STATE_UNKNOWN, _("Could not allocate url\n"));
  946. while (pos) {
  947. if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) < 1) {
  948. pos += (size_t) strcspn (pos, "\r\n");
  949. pos += (size_t) strspn (pos, "\r\n");
  950. if (strlen(pos) == 0)
  951. die (STATE_UNKNOWN,
  952. _("UNKNOWN - Could not find redirect location - %s%s\n"),
  953. status_line, (display_html ? "</A>" : ""));
  954. continue;
  955. }
  956. pos += i;
  957. pos += strspn (pos, " \t\r\n");
  958. url = realloc (url, strcspn (pos, "\r\n"));
  959. if (url == NULL)
  960. die (STATE_UNKNOWN, _("could not allocate url\n"));
  961. /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
  962. if (sscanf (pos, HD1, type, addr, port, url) == 4) {
  963. use_ssl = server_type_check (type);
  964. i = atoi (port);
  965. }
  966. /* URI_HTTP URI_HOST URI_PATH */
  967. else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
  968. use_ssl = server_type_check (type);
  969. i = server_port_check (use_ssl);
  970. }
  971. /* URI_HTTP URI_HOST URI_PORT */
  972. else if(sscanf (pos, HD3, type, addr, port) == 3) {
  973. strcpy (url, HTTP_URL);
  974. use_ssl = server_type_check (type);
  975. i = atoi (port);
  976. }
  977. /* URI_HTTP URI_HOST */
  978. else if(sscanf (pos, HD4, type, addr) == 2) {
  979. strcpy (url, HTTP_URL);
  980. use_ssl = server_type_check (type);
  981. i = server_port_check (use_ssl);
  982. }
  983. /* URI_PATH */
  984. else if (sscanf (pos, HD5, url) == 1) {
  985. /* relative url */
  986. if ((url[0] != '/')) {
  987. if ((x = strrchr(server_url, '/')))
  988. *x = '\0';
  989. asprintf (&url, "%s/%s", server_url, url);
  990. }
  991. i = server_port;
  992. strcpy (type, server_type);
  993. strcpy (addr, host_name);
  994. }
  995. else {
  996. die (STATE_UNKNOWN,
  997. _("UNKNOWN - Could not parse redirect location - %s%s\n"),
  998. pos, (display_html ? "</A>" : ""));
  999. }
  1000. break;
  1001. } /* end while (pos) */
  1002. if (++redir_depth > max_depth)
  1003. die (STATE_WARNING,
  1004. _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
  1005. max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
  1006. if (server_port==i &&
  1007. !strcmp(server_address, addr) &&
  1008. (host_name && !strcmp(host_name, addr)) &&
  1009. !strcmp(server_url, url))
  1010. die (STATE_WARNING,
  1011. _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
  1012. type, addr, i, url, (display_html ? "</A>" : ""));
  1013. server_port = i;
  1014. strcpy (server_type, type);
  1015. free (host_name);
  1016. host_name = strdup (addr);
  1017. free (server_address);
  1018. server_address = strdup (addr);
  1019. free (server_url);
  1020. server_url = strdup (url);
  1021. check_http ();
  1022. }
  1023. int
  1024. server_type_check (const char *type)
  1025. {
  1026. if (strcmp (type, "https"))
  1027. return FALSE;
  1028. else
  1029. return TRUE;
  1030. }
  1031. int
  1032. server_port_check (int ssl_flag)
  1033. {
  1034. if (ssl_flag)
  1035. return HTTPS_PORT;
  1036. else
  1037. return HTTP_PORT;
  1038. }
  1039. char *perfd_time (double elapsed_time)
  1040. {
  1041. return fperfdata ("time", elapsed_time, "s",
  1042. check_warning_time, warning_time,
  1043. check_critical_time, critical_time,
  1044. TRUE, 0, FALSE, 0);
  1045. }
  1046. char *perfd_size (int page_len)
  1047. {
  1048. return perfdata ("size", page_len, "B",
  1049. (min_page_len>0?TRUE:FALSE), min_page_len,
  1050. (min_page_len>0?TRUE:FALSE), 0,
  1051. TRUE, 0, FALSE, 0);
  1052. }
  1053. void
  1054. print_help (void)
  1055. {
  1056. print_revision (progname, revision);
  1057. printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
  1058. printf (COPYRIGHT, copyright, email);
  1059. printf (_("\
  1060. This plugin tests the HTTP service on the specified host. It can test\n\
  1061. normal (http) and secure (https) servers, follow redirects, search for\n\
  1062. strings and regular expressions, check connection times, and report on\n\
  1063. certificate expiration times."));
  1064. printf ("\n\n");
  1065. print_usage ();
  1066. printf (_("NOTE: One or both of -H and -I must be specified"));
  1067. printf ("\n");
  1068. printf (_(UT_HELP_VRSN));
  1069. printf (_("\
  1070. -H, --hostname=ADDRESS\n\
  1071. Host name argument for servers using host headers (virtual host)\n\
  1072. Append a port to include it in the header (eg: example.com:5000)\n\
  1073. -I, --IP-address=ADDRESS\n\
  1074. IP address or name (use numeric address if possible to bypass DNS lookup).\n\
  1075. -p, --port=INTEGER\n\
  1076. Port number (default: %d)\n"), HTTP_PORT);
  1077. printf (_(UT_IPv46));
  1078. #ifdef HAVE_SSL
  1079. printf (_("\
  1080. -S, --ssl\n\
  1081. Connect via SSL\n\
  1082. -C, --certificate=INTEGER\n\
  1083. Minimum number of days a certificate has to be valid.\n\
  1084. (when this option is used the url is not checked.)\n"));
  1085. #endif
  1086. printf (_("\
  1087. -e, --expect=STRING\n\
  1088. String to expect in first (status) line of server response (default: %s)\n\
  1089. If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
  1090. -s, --string=STRING\n\
  1091. String to expect in the content\n\
  1092. -u, --url=PATH\n\
  1093. URL to GET or POST (default: /)\n\
  1094. -P, --post=STRING\n\
  1095. URL encoded http POST data\n\
  1096. -N, --no-body\n\
  1097. Don't wait for document body: stop reading after headers.\n\
  1098. (Note that this still does an HTTP GET or POST, not a HEAD.)\n\
  1099. -M, --max-age=SECONDS\n\
  1100. Warn if document is more than SECONDS old. the number can also be of \n\
  1101. the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\
  1102. -T, --content-type=STRING\n\
  1103. specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
  1104. #ifdef HAVE_REGEX_H
  1105. printf (_("\
  1106. -l, --linespan\n\
  1107. Allow regex to span newlines (must precede -r or -R)\n\
  1108. -r, --regex, --ereg=STRING\n\
  1109. Search page for regex STRING\n\
  1110. -R, --eregi=STRING\n\
  1111. Search page for case-insensitive regex STRING\n"));
  1112. #endif
  1113. printf (_("\
  1114. -a, --authorization=AUTH_PAIR\n\
  1115. Username:password on sites with basic authentication\n\
  1116. -A, --useragent=STRING\n\
  1117. String to be sent in http header as \"User Agent\"\n\
  1118. -k, --header=STRING\n\
  1119. Any other tags to be sent in http header, separated by semicolon\n\
  1120. -L, --link=URL\n\
  1121. Wrap output in HTML link (obsoleted by urlize)\n\
  1122. -f, --onredirect=<ok|warning|critical|follow>\n\
  1123. How to handle redirected pages\n\
  1124. -m, --pagesize=INTEGER<:INTEGER>\n\
  1125. Minimum page size required (bytes) : Maximum page size required (bytes)\n"));
  1126. printf (_(UT_WARN_CRIT));
  1127. printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
  1128. printf (_(UT_VERBOSE));
  1129. printf (_("\
  1130. This plugin will attempt to open an HTTP connection with the host. Successful\n\
  1131. connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
  1132. errors return STATE_UNKNOWN. Successful connects, but incorrect reponse\n\
  1133. messages from the host result in STATE_WARNING return values. If you are\n\
  1134. checking a virtual server that uses 'host headers' you must supply the FQDN\n\
  1135. (fully qualified domain name) as the [host_name] argument.\n"));
  1136. #ifdef HAVE_SSL
  1137. printf (_("\n\
  1138. This plugin can also check whether an SSL enabled web server is able to\n\
  1139. serve content (optionally within a specified time) or whether the X509 \n\
  1140. certificate is still valid for the specified number of days.\n"));
  1141. printf (_("\n\
  1142. CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
  1143. When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
  1144. STATE_OK will be returned. When the server returns its content but exceeds\n\
  1145. the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
  1146. a STATE_CRITICAL will be returned.\n\n"));
  1147. printf (_("\
  1148. CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
  1149. When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
  1150. STATE_OK is returned. When the certificate is still valid, but for less than\n\
  1151. 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
  1152. the certificate is expired.\n"));
  1153. #endif
  1154. printf (_(UT_SUPPORT));
  1155. }
  1156. void
  1157. print_usage (void)
  1158. {
  1159. printf (_("Usage:"));
  1160. printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
  1161. printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
  1162. printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
  1163. printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
  1164. printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string] [-k string]\n");
  1165. }