[Nagiosplug-devel] check_dns

Awais Ahmad awais at eurobell.net
Mon Feb 23 04:49:45 CET 2004


I have done this with the stable version of check_dns.c but never had
the time to carry the changes across to HEAD. The patch is attached.

Although the main resolver lib functions are available, via
GLIBC/LIBC,the response parsing routines (ns_parserr and friends) are
only visible to the resolver lib functions themselves. 
I've had to roll my own. 

I've tested on Debian GNU/Linux, Redhat GNU/Linux, FreeBSD current/4.X
and Solaris 7.


Awais Ahmad






On Fri, 2004-02-20 at 03:52, Karl DeBisschop wrote:
> On Thu, 2004-02-19 at 22:34, Ton Voon wrote:
> 
> > I'll have a go at this change, but only after I can get check_dns to 
> > use the resolver routines instead of nslookup first. Most of 
> > check_dns.c looks like it is parsing for error messages in nslookup!
> 
> Makes sense to me. That was the direction we wanted to go anyway, to use
> the resolver instead of parsing scripts.
> 
> IIRC, the resolver is covered by POSIX, so we should have much less
> platform-specific cruft once we do that.
> 
> --
> Karl
> 
> 
> 
> -------------------------------------------------------
> SF.Net is sponsored by: Speed Start Your Linux Apps Now.
> Build and deploy apps & Web services for Linux with
> a free DVD software kit from IBM. Click Now!
> http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click
> _______________________________________________
> Nagiosplug-devel mailing list
> Nagiosplug-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/nagiosplug-devel
> ::: Please include plugins version (-v) and OS when reporting any issue. 
> ::: Messages without supporting info will risk being sent to /dev/null
> 
-------------- next part --------------
--- check_dns.c	Sat Nov 15 23:24:22 2003
+++ check_dns.c.current	Mon Feb 23 12:38:28 2004
@@ -6,11 +6,12 @@
  * License: GPL
  * Copyright (c) 1999 Ethan Galstad (nagios at nagios.org)
  *
- * Last Modified: $Date: 2003/02/21 21:46:27 $
+ * Last Modified: $Date: 2003/05/31 14:39:33 $
  *
  * Notes:
  *  - Safe popen added by Karl DeBisschop 9-11-99
  *  - expected-address parameter added by Alex Chaffee - 7 Oct 2002
+ *  - modified to use resolver libs by Awais Ahmad - 14/11/2003
  *
  * Command line: (see print_usage)
  *
@@ -44,19 +45,21 @@
  *
  *****************************************************************************/
 
+#include <resolv.h>
+#include <arpa/nameser.h>
+#include <netinet/in.h>
 #include "common.h"
-#include "popen.h"
 #include "utils.h"
 
+
 const char *progname = "check_dns";
-#define REVISION "$Revision: 1.8 $"
+#define REVISION "$Revision: 1.8.2.3 $"
 #define COPYRIGHT "2000-2002"
 
 int process_arguments (int, char **);
 int validate_arguments (void);
 void print_usage (void);
 void print_help (void);
-int error_scan (char *);
 
 #define ADDRESS_LENGTH 256
 char query_address[ADDRESS_LENGTH] = "";
@@ -75,186 +78,59 @@
 	char *address = NULL;
 	char *temp_buffer = NULL;
 	int result = STATE_UNKNOWN;
+	char queryresult[ADDRESS_LENGTH];
+	
 
-	/* Set signal handling and alarm */
-	if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
-		printf ("Cannot catch SIGALRM");
-		return STATE_UNKNOWN;
-	}
 
 	if (process_arguments (argc, argv) != OK) {
 		print_usage ();
 		return STATE_UNKNOWN;
 	}
 
-	/* get the command to run */
-	asprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND,	query_address, dns_server);
+	/* Set signal handling and alarm */
+        if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+                printf ("Cannot catch SIGALRM");
+                return STATE_UNKNOWN;
+        } 
 
 	alarm (timeout_interval);
 	time (&start_time);
 
-	if (verbose)
-		printf ("%s\n", command_line);
-	/* run the command */
-	child_process = spopen (command_line);
-	if (child_process == NULL) {
-		printf ("Could not open pipe: %s\n", command_line);
-		return STATE_UNKNOWN;
-	}
+	if (verbose) 
+		printf("Query address:%s DNS server:%s\n", query_address, dns_server);
 
-	child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
-	if (child_stderr == NULL)
-		printf ("Could not open stderr for %s\n", command_line);
-
-	/* scan stdout */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
-
-		if (verbose)
-			printf ("%s\n", input_buffer);
-
-		if (strstr (input_buffer, ".in-addr.arpa")) {
-			if ((temp_buffer = strstr (input_buffer, "name = ")))
-				address = strscpy (address, temp_buffer + 7);
-			else {
-				output = strscpy (output, "Unknown error (plugin)");
-				result = STATE_WARNING;
-			}
-		}
+	result = nslookup(dns_server, query_address, &queryresult, verbose);
+
+	(void) time (&end_time);
 
-		/* the server is responding, we just got the host name... */
-		if (strstr (input_buffer, "Name:")) {
+	if (result == STATE_CRITICAL) {
 
-			/* get the host address */
-			if (!fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
-				break;
-
-			if (verbose)
-				printf ("%s\n", input_buffer);
-
-			if ((temp_buffer = index (input_buffer, ':'))) {
-				temp_buffer++;
-				/* Strip leading spaces */
-				for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++)
-					/* NOOP */;
-				address = strscpy (address, temp_buffer);
-				strip (address);
-				result = STATE_OK;
-			}
-			else {
-				output = strscpy (output, "Unknown error (plugin)");
-				result = STATE_WARNING;
-			}
+		 terminate (STATE_CRITICAL,
+                           "DNS CRITICAL - '%s'\n", strerror(errno));
 
-			break;
-		}
+	}else if (result == STATE_WARNING) {
 
-		result = error_scan (input_buffer);
-		if (result != STATE_OK) {
-			output = strscpy (output, 1 + index (input_buffer, ':'));
-			break;
-		}
+		 /* query succeeded with no result */
+                printf("DNS WARNING - Server has no records for %s\n", query_address);
 
-	}
+	/* compare to expected address */
+	}else if (match_expected_address && strcmp(queryresult, expected_address)) {
 
-	/* scan stderr */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
-		if (error_scan (input_buffer) != STATE_OK) {
-			result = max_state (result, error_scan (input_buffer));
-			output = strscpy (output, 1 + index (input_buffer, ':'));
-		}
-	}
+		result = STATE_CRITICAL;
+                printf("DNS CRITICAL - expected %s but got %s\n", expected_address, queryresult);
 
-	/* close stderr */
-	(void) fclose (child_stderr);
+	}else if (result == STATE_OK) {
 
-	/* close stdout */
-	if (spclose (child_process)) {
-		result = max_state (result, STATE_WARNING);
-		if (!strcmp (output, ""))
-			output = strscpy (output, "nslookup returned error status");
+  		printf ("DNS ok - %d seconds response time, Address is %s\n",
+                         (int) (end_time - start_time), queryresult);
 	}
 
-	/* compare to expected address */
-	if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) {
-	        result = STATE_CRITICAL;
-	        asprintf(&output, "expected %s but got %s", expected_address, address);
-		}
-	
-	(void) time (&end_time);
+		
 
-	if (result == STATE_OK)
-		printf ("DNS ok - %d seconds response time, Address(es) is/are %s\n",
-						(int) (end_time - start_time), address);
-	else if (result == STATE_WARNING)
-		printf ("DNS WARNING - %s\n",
-			!strcmp (output, "") ? " Probably a non-existent host/domain" : output);
-	else if (result == STATE_CRITICAL)
-		printf ("DNS CRITICAL - %s\n",
-			!strcmp (output, "") ? " Probably a non-existent host/domain" : output);
-	else
-		printf ("DNS problem - %s\n",
-			!strcmp (output, "") ? " Probably a non-existent host/domain" : output);
 
 	return result;
 }
 
-int
-error_scan (char *input_buffer)
-{
-
-	/* the DNS lookup timed out */
-	if (strstr (input_buffer,
-	     "Note:  nslookup is deprecated and may be removed from future releases.")
-	    || strstr (input_buffer,
-	     "Consider using the `dig' or `host' programs instead.  Run nslookup with")
-	    || strstr (input_buffer,
-	     "the `-sil[ent]' option to prevent this message from appearing."))
-		return STATE_OK;
-
-	/* the DNS lookup timed out */
-	else if (strstr (input_buffer, "Timed out"))
-		return STATE_WARNING;
-
-	/* DNS server is not running... */
-	else if (strstr (input_buffer, "No response from server"))
-		return STATE_CRITICAL;
-
-	/* Host name is valid, but server doesn't have records... */
-	else if (strstr (input_buffer, "No records"))
-		return STATE_WARNING;
-
-	/* Host or domain name does not exist */
-	else if (strstr (input_buffer, "Non-existent"))
-		return STATE_CRITICAL;
-	else if (strstr (input_buffer, "** server can't find"))
-		return STATE_CRITICAL;
-	else if(strstr(input_buffer,"NXDOMAIN")) /* 9.x */
-		return STATE_CRITICAL;
-
-	/* Connection was refused */
-	else if (strstr (input_buffer, "Connection refused"))
-		return STATE_CRITICAL;
-
-	/* Network is unreachable */
-	else if (strstr (input_buffer, "Network is unreachable"))
-		return STATE_CRITICAL;
-
-	/* Internal server failure */
-	else if (strstr (input_buffer, "Server failure"))
-		return STATE_CRITICAL;
-
-	/* DNS server refused to service request */
-	else if (strstr (input_buffer, "Refused"))
-		return STATE_CRITICAL;
-
-	/* Request error */
-	else if (strstr (input_buffer, "Format error"))
-		return STATE_WARNING;
-
-	else
-		return STATE_OK;
-
-}
 
 /* process command-line arguments */
 int
@@ -421,3 +297,106 @@
 		 "be specified.  If no DNS server is specified, the default server(s)\n"
 		 "specified in /etc/resolv.conf will be used.\n", DEFAULT_SOCKET_TIMEOUT);
 }
+
+
+
+
+int nslookup(char *target, char *question, char *result, int verbose) {
+
+        char replybuffer[ADDRESS_LENGTH*4];
+        char *eom;
+        char *pos;
+        char tmp[1024]="";
+        char name[ADDRESS_LENGTH]="";
+        char cname[ADDRESS_LENGTH]="";
+        int totalcount, count, offset, rrtype;
+        u_int16_t type;
+        u_int16_t class;
+        u_int16_t rdlength;
+        u_int32_t ttl;
+        struct in_addr target_in_addr, ipaddr, t_ipaddr;
+	
+        if (res_init() != 0) {
+
+           if (verbose)  printf("Call to res_init(3) failed:%s\n",
+                                (char *)strerror(errno));
+           return STATE_CRITICAL;
+
+        }
+
+        inet_aton(target, &target_in_addr.s_addr);
+        /* change _res to only contain our target name server */
+        _res.nscount = 1;
+        _res.nsaddr_list[0].sin_addr = target_in_addr;
+
+        if (inet_aton(question, &ipaddr.s_addr) == 0) {
+                rrtype = T_A;
+        }else{
+                /* if this is an IP, then type is T_PTR */
+                rrtype = T_PTR;
+                /* reverse the octets */
+                t_ipaddr.s_addr  = ipaddr.s_addr >> 24;
+                t_ipaddr.s_addr += (((ipaddr.s_addr >> 16) & 0xff) << 8);
+                t_ipaddr.s_addr += (((ipaddr.s_addr >> 8) & 0xff) << 16);
+                t_ipaddr.s_addr += ((ipaddr.s_addr & 0xff) << 24);
+
+                strcpy(tmp, (char *)inet_ntoa(t_ipaddr.s_addr));
+                strncat(tmp, ".in-addr.arpa", 13);
+                question=tmp;
+        }
+
+        /* zero out buffer */
+        bzero(replybuffer, sizeof(replybuffer));
+        totalcount = res_query(question, C_IN, rrtype, replybuffer,
+                               sizeof(replybuffer));
+
+        if ( totalcount == -1 ) {
+                if (errno == 0 ) {
+                        /* query succeeded with no result */
+                        if (verbose) printf("Server has no records for %s\n", question);
+                        return STATE_WARNING;
+                }
+                if (verbose) printf("Call to res_query(3) failed:%s\n",
+                                   (char *)strerror(errno));
+                return STATE_CRITICAL;
+
+        }
+        eom = replybuffer + totalcount;
+        count = dn_expand(replybuffer, eom,
+                          replybuffer + 12, tmp, 1024);
+        offset = count + 16;
+        /* this gets us to the start of the reply */
+        count = dn_expand(replybuffer, eom,
+                          replybuffer + offset, name, 1024);
+        offset += count;
+        pos = offset + replybuffer;
+        /* we are at type now*/
+        NS_GET16(type, pos);
+        NS_GET16(class, pos);
+        NS_GET32(ttl, pos);
+        NS_GET16(rdlength, pos);
+
+        if (type == T_CNAME) {
+                /* another lookup is required */
+                count = dn_expand(replybuffer, eom,
+                                  pos, cname, 1024);
+                return nslookup(target, cname, result, verbose);
+        }
+
+        if (type == T_PTR) {
+                count = dn_expand(replybuffer, eom,
+                                  pos, result, 1024);
+        }else{
+                memcpy(&t_ipaddr, (int *)pos, 4);
+                strcpy(result, (char *)inet_ntoa(t_ipaddr));
+        }
+        if (verbose) {
+
+                printf("\nName:	%s\n", name);
+                printf("Type:	%hu\n", type);
+                printf("TTL:	%u\n", ttl);
+                printf("IP:	%s\n\n", result);
+        }
+        return STATE_OK;
+}
+


More information about the Devel mailing list