Code

Some HTTP server applications/configurations cause trouble if the port is
[nagiosplug.git] / plugins / check_http.c
index 82cd1d9c7ec703d5f6b3413ade492321000627ee..69ed2fa91031f0bf89eccd15734661e69cba45da 100644 (file)
@@ -147,6 +147,9 @@ main (int argc, char **argv)
   asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
             clean_revstring (revision), VERSION);
 
+       /* Parse extra opts if any */
+       argv=np_extra_opts (&argc, argv, progname);
+
   if (process_arguments (argc, argv) == ERROR)
     usage4 (_("Could not parse arguments"));
 
@@ -570,7 +573,25 @@ parse_time_string (const char *string)
   }
 }
 
+/* Checks if the server 'reply' is one of the expected 'statuscodes' */
+static int
+expected_statuscode (const char *reply, const char *statuscodes)
+{
+  char *expected, *code;
+  int result = 0;
+
+  if ((expected = strdup (statuscodes)) == NULL)
+    die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
 
+  for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
+    if (strstr (reply, code) != NULL) {
+      result = 1;
+      break;
+    }
+
+  free (expected);
+  return result;
+}
 
 static void
 check_document_dates (const char *headers)
@@ -595,7 +616,10 @@ check_document_dates (const char *headers)
     /* Skip to the end of the header, including continuation lines. */
     while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
       s++;
-    s++;
+
+    /* Avoid stepping over end-of-string marker */
+    if (*s)
+      s++;
 
     /* Process this header. */
     if (value && value > field+2) {
@@ -708,6 +732,22 @@ get_content_length (const char *headers)
   return (content_length);
 }
 
+char *
+prepend_slash (char *path)
+{
+  char *newpath;
+
+  if (path[0] == '/')
+    return path;
+
+  if ((newpath = malloc (strlen(path) + 2)) == NULL)
+    die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
+  newpath[0] = '/';
+  strcpy (newpath + 1, path);
+  free (path);
+  return newpath;
+}
+
 int
 check_http (void)
 {
@@ -737,7 +777,7 @@ check_http (void)
     if (check_cert == TRUE) {
       result = np_net_ssl_check_cert(days_till_exp);
       np_net_ssl_cleanup();
-      if(sd) close(sd);
+      if (sd) close(sd);
       return result;
     }
   }
@@ -749,8 +789,18 @@ check_http (void)
   asprintf (&buf, "%sConnection: close\r\n", buf);
 
   /* optionally send the host header info */
-  if (host_name)
-    asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
+  if (host_name) {
+    /*
+     * Specify the port only if we're using a non-default port (see RFC 2616,
+     * 14.23).  Some server applications/configurations cause trouble if the
+     * (default) port is explicitly specified in the "Host:" header line.
+     */
+    if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
+        (use_ssl == TRUE && server_port == HTTPS_PORT))
+      asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
+    else
+      asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
+  }
 
   /* optionally send any other header tag */
   if (http_opt_headers_count) {
@@ -774,7 +824,7 @@ check_http (void)
     } else {
       asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
     }
-    
+
     asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
     asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
   }
@@ -829,7 +879,7 @@ check_http (void)
 #ifdef HAVE_SSL
   np_net_ssl_cleanup();
 #endif
-  if(sd) close(sd);
+  if (sd) close(sd);
 
   /* reset the alarm */
   alarm (0);
@@ -870,14 +920,15 @@ check_http (void)
                 (no_body ? "  [[ skipped ]]" : page));
 
   /* make sure the status line matches the response we are looking for */
-  if (!strstr (status_line, server_expect)) {
+  if (!expected_statuscode (status_line, server_expect)) {
     if (server_port == HTTP_PORT)
       asprintf (&msg,
-                _("Invalid HTTP response received from host\n"));
+                _("Invalid HTTP response received from host: %s\n"),
+                status_line);
     else
       asprintf (&msg,
-                _("Invalid HTTP response received from host on port %d\n"),
-                server_port);
+                _("Invalid HTTP response received from host on port %d: %s\n"),
+                server_port, status_line);
     die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
   }
 
@@ -936,7 +987,7 @@ check_http (void)
     } /* end if (http_status >= 300) */
 
   } /* end else (server_expect_yn)  */
-    
+
         if (maximum_age >= 0) {
           check_document_dates (header);
         }
@@ -1048,7 +1099,7 @@ redir (char *pos, char *status_line)
   addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
   if (addr == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
-  
+
   url = malloc (strcspn (pos, "\r\n"));
   if (url == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
@@ -1085,23 +1136,26 @@ redir (char *pos, char *status_line)
       die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
 
     /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
-    if (sscanf (pos, HD1, type, addr, &i, url) == 4)
+    if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
+      url = prepend_slash (url);
       use_ssl = server_type_check (type);
+    }
 
     /* URI_HTTP URI_HOST URI_PATH */
     else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
+      url = prepend_slash (url);
       use_ssl = server_type_check (type);
       i = server_port_check (use_ssl);
     }
 
     /* URI_HTTP URI_HOST URI_PORT */
-    else if(sscanf (pos, HD3, type, addr, &i) == 3) {
+    else if (sscanf (pos, HD3, type, addr, &i) == 3) {
       strcpy (url, HTTP_URL);
       use_ssl = server_type_check (type);
     }
 
     /* URI_HTTP URI_HOST */
-    else if(sscanf (pos, HD4, type, addr) == 2) {
+    else if (sscanf (pos, HD4, type, addr) == 2) {
       strcpy (url, HTTP_URL);
       use_ssl = server_type_check (type);
       i = server_port_check (use_ssl);
@@ -1152,12 +1206,7 @@ redir (char *pos, char *status_line)
   server_address = strdup (addr);
 
   free (server_url);
-  if ((url[0] == '/'))
-    server_url = strdup (url);
-  else if (asprintf(&server_url, "/%s", url) == -1)
-    die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate server_url%s\n"),
-         display_html ? "</A>" : "");
-  free(url);
+  server_url = url;
 
   if ((server_port = i) > MAX_PORT)
     die (STATE_UNKNOWN,
@@ -1232,6 +1281,7 @@ print_help (void)
   printf ("\n");
 
   printf (_(UT_HELP_VRSN));
+  printf (_(UT_EXTRA_OPTS));
 
   printf (" %s\n", "-H, --hostname=ADDRESS");
   printf ("    %s\n", _("Host name argument for servers using host headers (virtual host)"));
@@ -1253,7 +1303,8 @@ print_help (void)
 #endif
 
   printf (" %s\n", "-e, --expect=STRING");
-  printf ("    %s\n", _("String to expect in first (status) line of server response (default: "));
+  printf ("    %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
+  printf ("    %s", _("the first (status) line of the server response (default: "));
   printf ("%s)\n", HTTP_EXPECT);
   printf ("    %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
   printf (" %s\n", "-s, --string=STRING");
@@ -1299,19 +1350,24 @@ print_help (void)
 
   printf (_(UT_VERBOSE));
 
-  printf (_("Notes:"));
+  printf ("\n");
+  printf ("%s\n", _("Notes:"));
   printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
   printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
   printf (" %s\n", _("other errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse"));
   printf (" %s\n", _("messages from the host result in STATE_WARNING return values.  If you are"));
   printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
   printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
+  printf ("\n");
+  printf (_(UT_EXTRA_OPTS_NOTES));
 
 #ifdef HAVE_SSL
+  printf ("\n");
   printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
   printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
   printf (" %s\n", _("certificate is still valid for the specified number of days."));
-  printf (_("Examples:"));
+  printf ("\n");
+  printf ("%s\n", _("Examples:"));
   printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
   printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
   printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
@@ -1322,7 +1378,7 @@ print_help (void)
   printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
   printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
   printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
-  printf (" %s\n\n", _("the certificate is expired."));
+  printf (" %s\n", _("the certificate is expired."));
 #endif
 
   printf (_(UT_SUPPORT));