check_http.c 46 KB

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