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 * $Id$
31 *
32 ****************************************************************************/
34 #include "common.h"
35 #include "netutils.h"
37 unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
38 int econn_refuse_state = STATE_CRITICAL;
39 int was_refused = FALSE;
40 int address_family = AF_UNSPEC;
42 static int my_connect(const char *address, int port, int *sd, int proto);
43 /* handles socket timeouts */
44 void
45 socket_timeout_alarm_handler (int sig)
46 {
47 if (sig == SIGALRM)
48 printf ("CRITICAL - Socket timeout after %d seconds\n", socket_timeout);
49 else
50 printf ("CRITICAL - Abnormal timeout after %d seconds\n", socket_timeout);
52 exit (STATE_CRITICAL);
53 }
56 /* connects to a host on a specified TCP port, sends a string,
57 and gets a response */
58 int
59 process_tcp_request (const char *server_address, int server_port,
60 const char *send_buffer, char *recv_buffer, int recv_size)
61 {
62 int result;
64 result = process_request (server_address, server_port,
65 IPPROTO_TCP, send_buffer, recv_buffer, recv_size);
67 return result;
68 }
71 /* connects to a host on a specified UDP port, sends a string, and gets a
72 response */
73 int
74 process_udp_request (const char *server_address, int server_port,
75 const char *send_buffer, char *recv_buffer, int recv_size)
76 {
77 int result;
79 result = process_request (server_address, server_port,
80 IPPROTO_UDP, send_buffer, recv_buffer, recv_size);
82 return result;
83 }
87 /* connects to a host on a specified tcp port, sends a string, and gets a
88 response. loops on select-recv until timeout or eof to get all of a
89 multi-packet answer */
90 int
91 process_tcp_request2 (const char *server_address, int server_port,
92 const char *send_buffer, char *recv_buffer, int recv_size)
93 {
95 int result;
96 int send_result;
97 int recv_result;
98 int sd;
99 struct timeval tv;
100 fd_set readfds;
101 int recv_length = 0;
103 result = my_connect (server_address, server_port, &sd, IPPROTO_TCP);
104 if (result != STATE_OK)
105 return STATE_CRITICAL;
107 send_result = send (sd, send_buffer, strlen (send_buffer), 0);
108 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
109 printf ("Send failed\n");
110 result = STATE_WARNING;
111 }
113 while (1) {
114 /* wait up to the number of seconds for socket timeout
115 minus one for data from the host */
116 tv.tv_sec = socket_timeout - 1;
117 tv.tv_usec = 0;
118 FD_ZERO (&readfds);
119 FD_SET (sd, &readfds);
120 select (sd + 1, &readfds, NULL, NULL, &tv);
122 /* make sure some data has arrived */
123 if (!FD_ISSET (sd, &readfds)) { /* it hasn't */
124 if (!recv_length) {
125 strcpy (recv_buffer, "");
126 printf ("No data was received from host!\n");
127 result = STATE_WARNING;
128 }
129 else { /* this one failed, but previous ones worked */
130 recv_buffer[recv_length] = 0;
131 }
132 break;
133 }
134 else { /* it has */
135 recv_result =
136 recv (sd, recv_buffer + recv_length,
137 (size_t)recv_size - recv_length - 1, 0);
138 if (recv_result == -1) {
139 /* recv failed, bail out */
140 strcpy (recv_buffer + recv_length, "");
141 result = STATE_WARNING;
142 break;
143 }
144 else if (recv_result == 0) {
145 /* end of file ? */
146 recv_buffer[recv_length] = 0;
147 break;
148 }
149 else { /* we got data! */
150 recv_length += recv_result;
151 if (recv_length >= recv_size - 1) {
152 /* buffer full, we're done */
153 recv_buffer[recv_size - 1] = 0;
154 break;
155 }
156 }
157 }
158 /* end if(!FD_ISSET(sd,&readfds)) */
159 }
160 /* end while(1) */
162 close (sd);
163 return result;
164 }
166 /* connects to a host on a specified port, sends a string, and gets a
167 response */
168 int
169 process_request (const char *server_address, int server_port, int proto,
170 const char *send_buffer, char *recv_buffer, int recv_size)
171 {
172 int result;
173 int sd;
175 result = STATE_OK;
177 result = my_connect (server_address, server_port, &sd, proto);
178 if (result != STATE_OK)
179 return STATE_CRITICAL;
181 result = send_request (sd, proto, send_buffer, recv_buffer, recv_size);
183 close (sd);
185 return result;
186 }
189 /* opens a connection to a remote host/tcp port */
190 int
191 my_tcp_connect (const char *host_name, int port, int *sd)
192 {
193 int result;
195 result = my_connect (host_name, port, sd, IPPROTO_TCP);
197 return result;
198 }
201 /* opens a connection to a remote host/udp port */
202 int
203 my_udp_connect (const char *host_name, int port, int *sd)
204 {
205 int result;
207 result = my_connect (host_name, port, sd, IPPROTO_UDP);
209 return result;
210 }
213 /* opens a tcp or udp connection to a remote host */
214 static int
215 my_connect (const char *host_name, int port, int *sd, int proto)
216 {
217 struct addrinfo hints;
218 struct addrinfo *res, *res0;
219 char port_str[6];
220 int result;
222 memset (&hints, 0, sizeof (hints));
223 hints.ai_family = address_family;
224 hints.ai_protocol = proto;
225 hints.ai_socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
227 snprintf (port_str, sizeof (port_str), "%d", port);
228 result = getaddrinfo (host_name, port_str, &hints, &res0);
230 if (result != 0) {
231 printf ("%s\n", gai_strerror (result));
232 return STATE_UNKNOWN;
233 }
234 else {
235 res = res0;
236 while (res) {
237 /* attempt to create a socket */
238 *sd = socket (res->ai_family, (proto == IPPROTO_UDP) ?
239 SOCK_DGRAM : SOCK_STREAM, res->ai_protocol);
241 if (*sd < 0) {
242 printf ("Socket creation failed\n");
243 freeaddrinfo (res);
244 return STATE_UNKNOWN;
245 }
247 /* attempt to open a connection */
248 result = connect (*sd, res->ai_addr, res->ai_addrlen);
250 if (result == 0) {
251 was_refused = FALSE;
252 break;
253 }
255 if (result < 0) {
256 switch (errno) {
257 case ECONNREFUSED:
258 was_refused = TRUE;
259 break;
260 }
261 }
263 close (*sd);
264 res = res->ai_next;
265 }
266 freeaddrinfo (res0);
267 }
269 if (result == 0)
270 return STATE_OK;
271 else if (was_refused) {
272 switch (econn_refuse_state) { /* a user-defined expected outcome */
273 case STATE_OK:
274 case STATE_WARNING: /* user wants WARN or OK on refusal */
275 return econn_refuse_state;
276 break;
277 case STATE_CRITICAL: /* user did not set econn_refuse_state */
278 printf ("%s\n", strerror(errno));
279 return econn_refuse_state;
280 break;
281 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
282 return STATE_UNKNOWN;
283 break;
284 }
285 }
286 else {
287 printf ("%s\n", strerror(errno));
288 return STATE_CRITICAL;
289 }
290 }
293 int
294 send_tcp_request (int sd, const char *send_buffer, char *recv_buffer, int recv_size)
295 {
296 return send_request (sd, IPPROTO_TCP, send_buffer, recv_buffer, recv_size);
297 }
300 int
301 send_udp_request (int sd, const char *send_buffer, char *recv_buffer, int recv_size)
302 {
303 return send_request (sd, IPPROTO_UDP, send_buffer, recv_buffer, recv_size);
304 }
307 int
308 send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size)
309 {
310 int result = STATE_OK;
311 int send_result;
312 int recv_result;
313 struct timeval tv;
314 fd_set readfds;
316 send_result = send (sd, send_buffer, strlen (send_buffer), 0);
317 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
318 printf ("Send failed\n");
319 result = STATE_WARNING;
320 }
322 /* wait up to the number of seconds for socket timeout minus one
323 for data from the host */
324 tv.tv_sec = socket_timeout - 1;
325 tv.tv_usec = 0;
326 FD_ZERO (&readfds);
327 FD_SET (sd, &readfds);
328 select (sd + 1, &readfds, NULL, NULL, &tv);
330 /* make sure some data has arrived */
331 if (!FD_ISSET (sd, &readfds)) {
332 strcpy (recv_buffer, "");
333 printf ("No data was received from host!\n");
334 result = STATE_WARNING;
335 }
337 else {
338 recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0);
339 if (recv_result == -1) {
340 strcpy (recv_buffer, "");
341 if (proto != IPPROTO_TCP)
342 printf ("Receive failed\n");
343 result = STATE_WARNING;
344 }
345 else
346 recv_buffer[recv_result] = 0;
348 /* die returned string */
349 recv_buffer[recv_size - 1] = 0;
350 }
351 return result;
352 }
355 int
356 is_host (const char *address)
357 {
358 if (is_addr (address) || is_hostname (address))
359 return (TRUE);
361 return (FALSE);
362 }
364 int
365 is_addr (const char *address)
366 {
367 #ifdef USE_IPV6
368 if (is_inet_addr (address) && address_family != AF_INET6)
369 #else
370 if (is_inet_addr (address))
371 #endif
372 return (TRUE);
374 #ifdef USE_IPV6
375 if (is_inet6_addr (address) && address_family != AF_INET)
376 return (TRUE);
377 #endif
379 return (FALSE);
380 }
382 int
383 resolve_host_or_addr (const char *address, int family)
384 {
385 struct addrinfo hints;
386 struct addrinfo *res;
387 int retval;
389 memset (&hints, 0, sizeof (hints));
390 hints.ai_family = family;
391 retval = getaddrinfo (address, NULL, &hints, &res);
393 if (retval != 0)
394 return FALSE;
395 else {
396 freeaddrinfo (res);
397 return TRUE;
398 }
399 }
401 int
402 is_inet_addr (const char *address)
403 {
404 return resolve_host_or_addr (address, AF_INET);
405 }
407 #ifdef USE_IPV6
408 int
409 is_inet6_addr (const char *address)
410 {
411 return resolve_host_or_addr (address, AF_INET6);
412 }
413 #endif
415 int
416 is_hostname (const char *s1)
417 {
418 #ifdef USE_IPV6
419 return resolve_host_or_addr (s1, address_family);
420 #else
421 return resolve_host_or_addr (s1, AF_INET);
422 #endif
423 }