Code

fc85a2467e35aa5594d3ab1eb03373e4a93e6abe
[nagiosplug.git] / plugins / netutils.c
1 /****************************************************************************
2 *
3 * Nagios plugins network utilities
4 *
5 * License: GPL
6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains commons functions used in many of the plugins.
13 *
14 * License Information:
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 ****************************************************************************/
32 #include "config.h"
33 #include "common.h"
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
37 extern int socket_timeout;
38 RETSIGTYPE socket_timeout_alarm_handler (int);
40 int process_tcp_request2 (char *, int, char *, char *, int);
41 int process_tcp_request (char *, int, char *, char *, int);
42 int process_udp_request (char *, int, char *, char *, int);
43 int process_request (char *, int, char *, char *, char *, int);
45 int my_tcp_connect (char *, int, int *);
46 int my_udp_connect (char *, int, int *);
47 int my_connect (char *, int, int *, char *);
49 int my_inet_aton (register const char *, struct in_addr *);
51 /* handles socket timeouts */
52 void
53 socket_timeout_alarm_handler (int sig)
54 {
56         printf ("Socket timeout after %d seconds\n", socket_timeout);
58         exit (STATE_CRITICAL);
59 }
62 /* connects to a host on a specified TCP port, sends a string,
63    and gets a response */
64 int
65 process_tcp_request (char *server_address,
66                                                                                  int server_port,
67                                                                                  char *send_buffer, char *recv_buffer, int recv_size)
68 {
69         int result;
70         char proto[4] = "tcp";
72         result = process_request (server_address,
73                                                                                                                 server_port,
74                                                                                                                 proto, send_buffer, recv_buffer, recv_size);
76         return result;
77 }
80 /* connects to a host on a specified UDP port, sends a string, and gets a
81     response */
82 int
83 process_udp_request (char *server_address,
84                                                                                  int server_port,
85                                                                                  char *send_buffer, char *recv_buffer, int recv_size)
86 {
87         int result;
88         char proto[4] = "udp";
90         result = process_request (server_address,
91                                                                                                                 server_port,
92                                                                                                                 proto, send_buffer, recv_buffer, recv_size);
94         return result;
95 }
99 /* connects to a host on a specified tcp port, sends a string, and gets a 
100          response. loops on select-recv until timeout or eof to get all of a 
101          multi-packet answer */
102 int
103 process_tcp_request2 (char *server_address,
104                                                                                         int server_port,
105                                                                                         char *send_buffer, char *recv_buffer, int recv_size)
108         int result;
109         int send_result;
110         int recv_result;
111         int sd;
112         struct timeval tv;
113         fd_set readfds;
114         int recv_length = 0;
116         result = my_connect (server_address, server_port, &sd, "tcp");
117         if (result != STATE_OK)
118                 return STATE_CRITICAL;
120         send_result = send (sd, send_buffer, strlen (send_buffer), 0);
121         if (send_result != strlen (send_buffer)) {
122                 printf ("send() failed\n");
123                 result = STATE_WARNING;
124         }
126         while (1) {
127                 /* wait up to the number of seconds for socket timeout
128                    minus one for data from the host */
129                 tv.tv_sec = socket_timeout - 1;
130                 tv.tv_usec = 0;
131                 FD_ZERO (&readfds);
132                 FD_SET (sd, &readfds);
133                 select (sd + 1, &readfds, NULL, NULL, &tv);
135                 /* make sure some data has arrived */
136                 if (!FD_ISSET (sd, &readfds)) { /* it hasn't */
137                         if (!recv_length) {
138                                 strcpy (recv_buffer, "");
139                                 printf ("No data was recieved from host!\n");
140                                 result = STATE_WARNING;
141                         }
142                         else {                                                                          /* this one failed, but previous ones worked */
143                                 recv_buffer[recv_length] = 0;
144                         }
145                         break;
146                 }
147                 else {                                                                                  /* it has */
148                         recv_result =
149                                 recv (sd, recv_buffer + recv_length, recv_size - recv_length - 1, 0);
150                         if (recv_result == -1) {        /* recv failed, bail out */
151                                 strcpy (recv_buffer + recv_length, "");
152                                 result = STATE_WARNING;
153                                 break;
154                         }
155                         else if (recv_result == 0) {    /* end of file ? */
156                                 recv_buffer[recv_length] = 0;
157                                 break;
158                         }
159                         else {                                                                          /* we got data! */
160                                 recv_length += recv_result;
161                                 if (recv_length >= recv_size - 1) {     /* buffer full, we're done */
162                                         recv_buffer[recv_size - 1] = 0;
163                                         break;
164                                 }
165                         }
166                 }                                                                                                               /* end if(!FD_ISSET(sd,&readfds)) */
167         }                                                                                                                       /* end while(1) */
169         close (sd);
170         return result;
173 /* connects to a host on a specified port, sends a string, and gets a 
174    response */
175 int
176 process_request (char *server_address,
177                                                                  int server_port,
178                                                                  char *proto,
179                                                                  char *send_buffer, char *recv_buffer, int recv_size)
181         int result;
182         int send_result;
183         int recv_result;
184         int sd;
185         struct timeval tv;
186         fd_set readfds;
188         result = STATE_OK;
190         result = my_connect (server_address, server_port, &sd, proto);
191         if (result != STATE_OK)
192                 return STATE_CRITICAL;
194         send_result = send (sd, send_buffer, strlen (send_buffer), 0);
195         if (send_result != strlen (send_buffer)) {
196                 printf ("send() failed\n");
197                 result = STATE_WARNING;
198         }
200         /* wait up to the number of seconds for socket timeout minus one 
201            for data from the host */
202         tv.tv_sec = socket_timeout - 1;
203         tv.tv_usec = 0;
204         FD_ZERO (&readfds);
205         FD_SET (sd, &readfds);
206         select (sd + 1, &readfds, NULL, NULL, &tv);
208         /* make sure some data has arrived */
209         if (!FD_ISSET (sd, &readfds)) {
210                 strcpy (recv_buffer, "");
211                 printf ("No data was recieved from host!\n");
212                 result = STATE_WARNING;
213         }
215         else {
216                 recv_result = recv (sd, recv_buffer, recv_size - 1, 0);
217                 if (recv_result == -1) {
218                         strcpy (recv_buffer, "");
219                         if (!strcmp (proto, "tcp"))
220                                 printf ("recv() failed\n");
221                         result = STATE_WARNING;
222                 }
223                 else
224                         recv_buffer[recv_result] = 0;
226                 /* terminate returned string */
227                 recv_buffer[recv_size - 1] = 0;
228         }
230         close (sd);
232         return result;
236 /* opens a connection to a remote host/tcp port */
237 int
238 my_tcp_connect (char *host_name, int port, int *sd)
240         int result;
241         char proto[4] = "tcp";
243         result = my_connect (host_name, port, sd, proto);
245         return result;
249 /* opens a connection to a remote host/udp port */
250 int
251 my_udp_connect (char *host_name, int port, int *sd)
253         int result;
254         char proto[4] = "udp";
256         result = my_connect (host_name, port, sd, proto);
258         return result;
262 /* opens a tcp or udp connection to a remote host */
263 int
264 my_connect (char *host_name, int port, int *sd, char *proto)
266         struct sockaddr_in servaddr;
267         struct hostent *hp;
268         struct protoent *ptrp;
269         int result;
271         bzero ((char *) &servaddr, sizeof (servaddr));
272         servaddr.sin_family = AF_INET;
273         servaddr.sin_port = htons (port);
275         /* try to bypass using a DNS lookup if this is just an IP address */
276         if (!my_inet_aton (host_name, &servaddr.sin_addr)) {
278                 /* else do a DNS lookup */
279                 hp = gethostbyname ((const char *) host_name);
280                 if (hp == NULL) {
281                         printf ("Invalid host name '%s'\n", host_name);
282                         return STATE_UNKNOWN;
283                 }
285                 memcpy (&servaddr.sin_addr, hp->h_addr, hp->h_length);
286         }
288         /* map transport protocol name to protocol number */
289         if ((ptrp = getprotobyname (proto)) == NULL) {
290                 printf ("Cannot map \"%s\" to protocol number\n", proto);
291                 return STATE_UNKNOWN;
292         }
294         /* create a socket */
295         *sd =
296                 socket (PF_INET, (!strcmp (proto, "udp")) ? SOCK_DGRAM : SOCK_STREAM,
297                                                 ptrp->p_proto);
298         if (*sd < 0) {
299                 printf ("Socket creation failed\n");
300                 return STATE_UNKNOWN;
301         }
303         /* open a connection */
304         result = connect (*sd, (struct sockaddr *) &servaddr, sizeof (servaddr));
305         if (result < 0) {
306                 switch (errno) {
307                 case ECONNREFUSED:
308                         printf ("Connection refused by host\n");
309                         break;
310                 case ETIMEDOUT:
311                         printf ("Timeout while attempting connection\n");
312                         break;
313                 case ENETUNREACH:
314                         printf ("Network is unreachable\n");
315                         break;
316                 default:
317                         printf ("Connection refused or timed out\n");
318                 }
320                 return STATE_CRITICAL;
321         }
323         return STATE_OK;
328 /* This code was taken from Fyodor's nmap utility, which was originally
329          taken from the GLIBC 2.0.6 libraries because Solaris doesn't contain
330          the inet_aton() funtion. */
331 int
332 my_inet_aton (register const char *cp, struct in_addr *addr)
334         register unsigned int val;              /* changed from u_long --david */
335         register int base, n;
336         register char c;
337         u_int parts[4];
338         register u_int *pp = parts;
340         c = *cp;
342         for (;;) {
344                 /*
345                  * Collect number up to ``.''.
346                  * Values are specified as for C:
347                  * 0x=hex, 0=octal, isdigit=decimal.
348                  */
349                 if (!isdigit ((int) c))
350                         return (0);
351                 val = 0;
352                 base = 10;
354                 if (c == '0') {
355                         c = *++cp;
356                         if (c == 'x' || c == 'X')
357                                 base = 16, c = *++cp;
358                         else
359                                 base = 8;
360                 }
362                 for (;;) {
363                         if (isascii ((int) c) && isdigit ((int) c)) {
364                                 val = (val * base) + (c - '0');
365                                 c = *++cp;
366                         }
367                         else if (base == 16 && isascii ((int) c) && isxdigit ((int) c)) {
368                                 val = (val << 4) | (c + 10 - (islower ((int) c) ? 'a' : 'A'));
369                                 c = *++cp;
370                         }
371                         else
372                                 break;
373                 }
375                 if (c == '.') {
377                         /*
378                          * Internet format:
379                          *  a.b.c.d
380                          *  a.b.c (with c treated as 16 bits)
381                          *  a.b (with b treated as 24 bits)
382                          */
383                         if (pp >= parts + 3)
384                                 return (0);
385                         *pp++ = val;
386                         c = *++cp;
387                 }
388                 else
389                         break;
390         }
392         /* Check for trailing characters */
393         if (c != '\0' && (!isascii ((int) c) || !isspace ((int) c)))
394                 return (0);
396         /* Concoct the address according to the number of parts specified */
397         n = pp - parts + 1;
398         switch (n) {
400         case 0:
401                 return (0);                                                                     /* initial nondigit */
403         case 1:                                                                                 /* a -- 32 bits */
404                 break;
406         case 2:                                                                                 /* a.b -- 8.24 bits */
407                 if (val > 0xffffff)
408                         return (0);
409                 val |= parts[0] << 24;
410                 break;
412         case 3:                                                                                 /* a.b.c -- 8.8.16 bits */
413                 if (val > 0xffff)
414                         return (0);
415                 val |= (parts[0] << 24) | (parts[1] << 16);
416                 break;
418         case 4:                                                                                 /* a.b.c.d -- 8.8.8.8 bits */
419                 if (val > 0xff)
420                         return (0);
421                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
422                 break;
423         }
425         if (addr)
426                 addr->s_addr = htonl (val);
428         return (1);