[Nagiosplug-devel] check_http patch for proxy and SSL client_cert support

Jos Visser josv at osp.nl
Wed Sep 15 04:17:01 CEST 2004


Hi all,

The accompanying patch adds support for HTTP proxies and SSL client
certificates to the check_http plug-in.

It adds four new command line options:

	-i, --client_cert	Filename of the client certificate (PEM)
	-k, --private_key	Filename of the private key file (PEM)
	-x, --proxy-host	HTTP proxy hostname or IP address
	-y, --proxy-port	port of the HTTP proxy

(proxying works for SSL and non-SSL; proxy authentication not yet
supported...)

Use of -i automatically enables -S (--use-ssl).

The patch is against the check_http.c that I checked out this very
morning...

Samples:

$ ./check_http -H www.josvisser.nl -x localhost -y 3128
HTTP OK HTTP/1.0 200 OK - 4887 bytes in 1.730 seconds |time=1.729544s;;;0.000000 size=4887B;;;0

$ ./check_http -H rours.org -i cert.pem -k key.pem -x localhost -y 3128
HTTP WARNING: HTTP/1.1 403 Forbidden

Share and enjoy!

++Jos.es

-- 
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	Wed Sep 15 13:04:21 2004
+++ check_http.c	Wed Sep 15 13:04:21 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,6 +222,10 @@
  		{"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'},
@@ -233,7 +250,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, "Vvh46t: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 +314,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;
@@ -408,6 +454,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,13 +554,18 @@
 	}
 	else {
 #endif
-		if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
+		if (proxy_host && 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 %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)
@@ -918,6 +972,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 +1023,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 +1044,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 +1229,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 +1243,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 (_("\
@@ -1223,6 +1331,7 @@
 {
 	printf (_("\
 Usage: %s (-H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
+  [-x <proxy>] [-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\


More information about the Devel mailing list