[Nagiosplug-devel] check_http patch

Jos Visser josv at osp.nl
Wed Sep 22 08:06:07 CEST 2004


Included in this patch are:

- Support for checking through HTTP proxies (-x/-y)
- Support for SSL client certificates (-i/-k)
- Support for HTTP HEAD (-D)
- Patch to include the port number in the Host: header

++Jos.nl

-- 
Handle nur nach derjenigen Maxime, durch die du zugleich wollen kannst, 
daß sie ein allgemeines Gesetz werde.
-- Immanuel Kant
-------------- next part --------------
--- check_http.c.orig	Mon Mar 22 08:19:58 2004
+++ check_http.c	Wed Sep 22 17:03:45 2004
@@ -113,6 +113,11 @@
 char *http_post_data;
 char *http_content_type;
 char buffer[MAX_INPUT_BUFFER];
+char *client_cert;
+char *client_privkey;
+char *proxy_host;
+int proxy_port=8080;
+
 
 int process_arguments (int, char **);
 static char *base64 (const char *bin, size_t len);
@@ -184,6 +189,14 @@
 }
 

 
+/* Check whether a file exists */
+void
+test_file(char *filename)
+{
+	if (access(filename,R_OK)==0)
+		return;
+	usage2 (_("file does not exist or is not readable"), optarg);
+}
 
 /* process command-line arguments */
 int
@@ -209,10 +222,15 @@
  		{"linespan", no_argument, 0, 'l'},
 		{"onredirect", required_argument, 0, 'f'},
 		{"certificate", required_argument, 0, 'C'},
+		{"client-cert", required_argument, 0, 'i'},
+		{"private-key", required_argument, 0, 'k'},
+		{"proxy", required_argument, 0, 'x'},
+		{"proxy-port", required_argument, 0, 'y'},
 		{"content-type", required_argument, 0, 'T'},
 		{"min", required_argument, 0, 'm'},
 		{"use-ipv4", no_argument, 0, '4'},
 		{"use-ipv6", no_argument, 0, '6'},
+		{"head", no_argument, 0, 'D'},
 		{0, 0, 0, 0}
 	};
 
@@ -233,7 +251,7 @@
 	}
 
 	while (1) {
-		c = getopt_long (argc, argv, "Vvh46t:c:w:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:", longopts, &option);
+		c = getopt_long (argc, argv, "Vvh46Dt:c:w:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:i:k:x:y:", longopts, &option);
 		if (c == -1 || c == EOF)
 			break;
 
@@ -297,6 +315,35 @@
 			usage (_("check_http: invalid option - SSL is not available\n"));
 #endif
 			break;
+		case 'i': /* Use SSL client certificate */
+#ifdef HAVE_SSL
+			use_ssl=TRUE;
+
+			if (specify_port == FALSE)
+				server_port = HTTPS_PORT;
+
+			client_cert=optarg;
+			test_file(client_cert);
+#else
+			usage (_("check_http: invalid option - SSL is not available\n"));
+#endif
+			break;
+		case 'k': /* SSL client certificate private key file*/
+#ifdef HAVE_SSL
+			client_privkey=optarg;
+			test_file(client_privkey);
+#else
+			usage (_("check_http: invalid option - SSL is not available\n"));
+#endif
+			break;
+		case 'x': /* Use proxy */
+			proxy_host=optarg;
+			break;
+		case 'y': /* Proxy port */
+			proxy_port=atoi(optarg);
+			if (proxy_port==0)
+				usage2(_("check_http: invalid proxy port number\n"), optarg);
+			break;
 		case 'f': /* onredirect */
 			if (!strcmp (optarg, "follow"))
 				onredirect = STATE_DEPENDENT;
@@ -339,6 +386,10 @@
 			http_method = strdup("POST");
 			http_post_data = strdup (optarg);
 			break;
+		case 'D': /* HTTP HEAD */
+			if (http_method) break;
+			http_method = strdup("HEAD");
+			break;
 		case 's': /* string or substring */
 			strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
 			string_expect[MAX_INPUT_BUFFER - 1] = 0;
@@ -408,6 +459,9 @@
 			server_address = strdup (host_name);
 	}
 
+	if (client_cert && !client_privkey) 
+			usage (_("check_http: if you use a client certificate you must also specify a private key file\n"));
+
 	if (check_critical_time && critical_time>(double)socket_timeout)
 		socket_timeout = (int)critical_time + 1;
 
@@ -505,17 +559,23 @@
 	}
 	else {
 #endif
-		if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
+		if (proxy_host) {
+			if (my_tcp_connect (proxy_host, proxy_port, &sd) != STATE_OK)
+				die (STATE_CRITICAL, _("Unable to open TCP socket to proxy\n"));
+		} else if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
 			die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
 #ifdef HAVE_SSL
 	}
 #endif
 
-	asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
+	if (proxy_host && !use_ssl)
+		asprintf (&buf, "%s http://%s%s HTTP/1.0\r\n%s\r\n", http_method, server_address, server_url, user_agent);
+	else
+		asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
 
 	/* optionally send the host header info */
 	if (host_name)
-		asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
+		asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
 
 	/* optionally send the authentication info */
 	if (strlen(user_auth)) {
@@ -918,6 +978,39 @@
 
 
 #ifdef HAVE_SSL
+int proxy_connect() 
+{
+	char *buf;
+	int n,i;
+
+	if (my_tcp_connect(proxy_host, proxy_port, &sd)!=STATE_OK)
+		return FALSE;
+
+	asprintf (&buf, "CONNECT %s:%d HTTP/1.0\r\n%s\r\n\r\n", server_address, server_port, user_agent);
+	send(sd,buf,strlen(buf),0);
+
+	use_ssl=FALSE; /* hack */
+	buf="";
+
+	while ((n=my_recv())>0) {
+		buffer[n]=0;
+		asprintf(&buf,"%s%s",buf,buffer);
+		i=strlen(buf);
+
+		if (strcmp(buf+i-4,"\r\n\r\n")==0)
+			break;
+	}
+
+	if (verbose)
+		printf("PROXY CONNECT: %s",buf);
+
+	if (!(strncmp(buf,"HTTP/1.",7)==0 & strncmp(buf+8," 200 ",5)==0))
+		return FALSE;
+
+	use_ssl=TRUE;
+	return 1;
+}
+
 int connect_SSL (void)
 {
 	SSL_METHOD *meth;
@@ -936,6 +1029,17 @@
 		return STATE_CRITICAL;
 	}
 
+	/* Set up the client certificate to be used (if so requested) */
+	if (client_cert) {
+		SSL_CTX_use_certificate_file(ctx,client_cert,SSL_FILETYPE_PEM);
+		SSL_CTX_use_PrivateKey_file(ctx,client_privkey,SSL_FILETYPE_PEM);
+
+		if (!SSL_CTX_check_private_key(ctx)) {
+			printf(_("CRITICAL - Private key does not seem to match certificate!\n"));
+			return STATE_CRITICAL;
+		}
+	}
+
 	/* Initialize alarm signal handling */
 	signal (SIGALRM, socket_timeout_alarm_handler);
 
@@ -946,7 +1050,7 @@
 	gettimeofday (&tv, NULL);
 
 	/* Make TCP connection */
-	if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
+	if ((proxy_host && proxy_connect()) || my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
 		/* Do the SSL handshake */
 		if ((ssl = SSL_new (ctx)) != NULL) {
 			SSL_set_cipher_list(ssl, "ALL");
@@ -1131,7 +1235,11 @@
  -I, --IP-address=ADDRESS\n\
    IP address or name (use numeric address if possible to bypass DNS lookup).\n\
  -p, --port=INTEGER\n\
-   Port number (default: %d)\n"), HTTP_PORT);
+   Port number (default: %d)\n\
+ -x, --proxy-host=ADDRESS\n\
+   Host name or IP address of HTTP proxy to be used\n\
+ -y, --proxy-port=INTEGER\n\
+   Port number of the HTTP proxy service\n"), HTTP_PORT);
 
 	printf (_(UT_IPv46));
 
@@ -1141,7 +1249,13 @@
     Connect via SSL\n\
  -C, --certificate=INTEGER\n\
     Minimum number of days a certificate has to be valid.\n\
-    (when this option is used the url is not checked.)\n"));
+    (when this option is used the url is not checked.)\n\
+ -i, --client-cert=FILE\n\
+    Name of file that contains the client certificate (PEM
+    format) to be used in establishing the SSL session.\n\
+ -k, --private-key=FILE\n\
+    Name of file containing the private key (PEM format)
+    matching the client certificate\n"));
 #endif
 
 	printf (_("\
@@ -1154,6 +1268,9 @@
    URL to GET or POST (default: /)\n\
  -P, --post=STRING\n\
    URL encoded http POST data\n\
+ -D, --head\n\
+   Use an HTTP HEAD request (actual data not transferred; more efficient than a\n\
+   GET)\n\
  -T, --content-type=STRING\n\
    specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
 
@@ -1223,9 +1340,10 @@
 {
 	printf (_("\
 Usage: %s (-H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
+  [-x <proxy-host>] [-y <proxy-port>]\n\
   [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
   [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
   [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
-  [-P string] [-m min_pg_size] [-4|-6]\n"), progname);
+  [-P string|-D] [-m min_pg_size] [-4|-6]\n"), progname);
 	printf (_(UT_HLP_VRS), progname, progname);
 }


More information about the Devel mailing list