netutils.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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. ****************************************************************************/
  31. #include "config.h"
  32. #include "common.h"
  33. #include <sys/socket.h>
  34. #include <netinet/in.h>
  35. #include <arpa/inet.h>
  36. #include <netdb.h>
  37. extern int socket_timeout;
  38. RETSIGTYPE socket_timeout_alarm_handler (int);
  39. int process_tcp_request2 (char *, int, char *, char *, int);
  40. int process_tcp_request (char *, int, char *, char *, int);
  41. int process_udp_request (char *, int, char *, char *, int);
  42. int process_request (char *, int, char *, char *, char *, int);
  43. int my_tcp_connect (char *, int, int *);
  44. int my_udp_connect (char *, int, int *);
  45. int my_connect (char *, int, int *, char *);
  46. int my_inet_aton (register const char *, struct in_addr *);
  47. /* handles socket timeouts */
  48. void
  49. socket_timeout_alarm_handler (int sig)
  50. {
  51. printf ("Socket timeout after %d seconds\n", socket_timeout);
  52. exit (STATE_CRITICAL);
  53. }
  54. /* connects to a host on a specified TCP port, sends a string,
  55. and gets a response */
  56. int
  57. process_tcp_request (char *server_address,
  58. int server_port,
  59. char *send_buffer, char *recv_buffer, int recv_size)
  60. {
  61. int result;
  62. char proto[4] = "tcp";
  63. result = process_request (server_address,
  64. server_port,
  65. proto, send_buffer, recv_buffer, recv_size);
  66. return result;
  67. }
  68. /* connects to a host on a specified UDP port, sends a string, and gets a
  69. response */
  70. int
  71. process_udp_request (char *server_address,
  72. int server_port,
  73. char *send_buffer, char *recv_buffer, int recv_size)
  74. {
  75. int result;
  76. char proto[4] = "udp";
  77. result = process_request (server_address,
  78. server_port,
  79. proto, send_buffer, recv_buffer, recv_size);
  80. return result;
  81. }
  82. /* connects to a host on a specified tcp port, sends a string, and gets a
  83. response. loops on select-recv until timeout or eof to get all of a
  84. multi-packet answer */
  85. int
  86. process_tcp_request2 (char *server_address,
  87. int server_port,
  88. char *send_buffer, char *recv_buffer, int recv_size)
  89. {
  90. int result;
  91. int send_result;
  92. int recv_result;
  93. int sd;
  94. struct timeval tv;
  95. fd_set readfds;
  96. int recv_length = 0;
  97. result = my_connect (server_address, server_port, &sd, "tcp");
  98. if (result != STATE_OK)
  99. return STATE_CRITICAL;
  100. send_result = send (sd, send_buffer, strlen (send_buffer), 0);
  101. if (send_result != strlen (send_buffer)) {
  102. printf ("send() failed\n");
  103. result = STATE_WARNING;
  104. }
  105. while (1) {
  106. /* wait up to the number of seconds for socket timeout
  107. minus one for data from the host */
  108. tv.tv_sec = socket_timeout - 1;
  109. tv.tv_usec = 0;
  110. FD_ZERO (&readfds);
  111. FD_SET (sd, &readfds);
  112. select (sd + 1, &readfds, NULL, NULL, &tv);
  113. /* make sure some data has arrived */
  114. if (!FD_ISSET (sd, &readfds)) { /* it hasn't */
  115. if (!recv_length) {
  116. strcpy (recv_buffer, "");
  117. printf ("No data was recieved from host!\n");
  118. result = STATE_WARNING;
  119. }
  120. else { /* this one failed, but previous ones worked */
  121. recv_buffer[recv_length] = 0;
  122. }
  123. break;
  124. }
  125. else { /* it has */
  126. recv_result =
  127. recv (sd, recv_buffer + recv_length, recv_size - recv_length - 1, 0);
  128. if (recv_result == -1) { /* recv failed, bail out */
  129. strcpy (recv_buffer + recv_length, "");
  130. result = STATE_WARNING;
  131. break;
  132. }
  133. else if (recv_result == 0) { /* end of file ? */
  134. recv_buffer[recv_length] = 0;
  135. break;
  136. }
  137. else { /* we got data! */
  138. recv_length += recv_result;
  139. if (recv_length >= recv_size - 1) { /* buffer full, we're done */
  140. recv_buffer[recv_size - 1] = 0;
  141. break;
  142. }
  143. }
  144. } /* end if(!FD_ISSET(sd,&readfds)) */
  145. } /* end while(1) */
  146. close (sd);
  147. return result;
  148. }
  149. /* connects to a host on a specified port, sends a string, and gets a
  150. response */
  151. int
  152. process_request (char *server_address,
  153. int server_port,
  154. char *proto,
  155. char *send_buffer, char *recv_buffer, int recv_size)
  156. {
  157. int result;
  158. int send_result;
  159. int recv_result;
  160. int sd;
  161. struct timeval tv;
  162. fd_set readfds;
  163. result = STATE_OK;
  164. result = my_connect (server_address, server_port, &sd, proto);
  165. if (result != STATE_OK)
  166. return STATE_CRITICAL;
  167. send_result = send (sd, send_buffer, strlen (send_buffer), 0);
  168. if (send_result != strlen (send_buffer)) {
  169. printf ("send() failed\n");
  170. result = STATE_WARNING;
  171. }
  172. /* wait up to the number of seconds for socket timeout minus one
  173. for data from the host */
  174. tv.tv_sec = socket_timeout - 1;
  175. tv.tv_usec = 0;
  176. FD_ZERO (&readfds);
  177. FD_SET (sd, &readfds);
  178. select (sd + 1, &readfds, NULL, NULL, &tv);
  179. /* make sure some data has arrived */
  180. if (!FD_ISSET (sd, &readfds)) {
  181. strcpy (recv_buffer, "");
  182. printf ("No data was recieved from host!\n");
  183. result = STATE_WARNING;
  184. }
  185. else {
  186. recv_result = recv (sd, recv_buffer, recv_size - 1, 0);
  187. if (recv_result == -1) {
  188. strcpy (recv_buffer, "");
  189. if (!strcmp (proto, "tcp"))
  190. printf ("recv() failed\n");
  191. result = STATE_WARNING;
  192. }
  193. else
  194. recv_buffer[recv_result] = 0;
  195. /* terminate returned string */
  196. recv_buffer[recv_size - 1] = 0;
  197. }
  198. close (sd);
  199. return result;
  200. }
  201. /* opens a connection to a remote host/tcp port */
  202. int
  203. my_tcp_connect (char *host_name, int port, int *sd)
  204. {
  205. int result;
  206. char proto[4] = "tcp";
  207. result = my_connect (host_name, port, sd, proto);
  208. return result;
  209. }
  210. /* opens a connection to a remote host/udp port */
  211. int
  212. my_udp_connect (char *host_name, int port, int *sd)
  213. {
  214. int result;
  215. char proto[4] = "udp";
  216. result = my_connect (host_name, port, sd, proto);
  217. return result;
  218. }
  219. /* opens a tcp or udp connection to a remote host */
  220. int
  221. my_connect (char *host_name, int port, int *sd, char *proto)
  222. {
  223. struct sockaddr_in servaddr;
  224. struct hostent *hp;
  225. struct protoent *ptrp;
  226. int result;
  227. bzero ((char *) &servaddr, sizeof (servaddr));
  228. servaddr.sin_family = AF_INET;
  229. servaddr.sin_port = htons (port);
  230. /* try to bypass using a DNS lookup if this is just an IP address */
  231. if (!my_inet_aton (host_name, &servaddr.sin_addr)) {
  232. /* else do a DNS lookup */
  233. hp = gethostbyname ((const char *) host_name);
  234. if (hp == NULL) {
  235. printf ("Invalid host name '%s'\n", host_name);
  236. return STATE_UNKNOWN;
  237. }
  238. memcpy (&servaddr.sin_addr, hp->h_addr, hp->h_length);
  239. }
  240. /* map transport protocol name to protocol number */
  241. if ((ptrp = getprotobyname (proto)) == NULL) {
  242. printf ("Cannot map \"%s\" to protocol number\n", proto);
  243. return STATE_UNKNOWN;
  244. }
  245. /* create a socket */
  246. *sd =
  247. socket (PF_INET, (!strcmp (proto, "udp")) ? SOCK_DGRAM : SOCK_STREAM,
  248. ptrp->p_proto);
  249. if (*sd < 0) {
  250. printf ("Socket creation failed\n");
  251. return STATE_UNKNOWN;
  252. }
  253. /* open a connection */
  254. result = connect (*sd, (struct sockaddr *) &servaddr, sizeof (servaddr));
  255. if (result < 0) {
  256. switch (errno) {
  257. case ECONNREFUSED:
  258. printf ("Connection refused by host\n");
  259. break;
  260. case ETIMEDOUT:
  261. printf ("Timeout while attempting connection\n");
  262. break;
  263. case ENETUNREACH:
  264. printf ("Network is unreachable\n");
  265. break;
  266. default:
  267. printf ("Connection refused or timed out\n");
  268. }
  269. return STATE_CRITICAL;
  270. }
  271. return STATE_OK;
  272. }
  273. /* This code was taken from Fyodor's nmap utility, which was originally
  274. taken from the GLIBC 2.0.6 libraries because Solaris doesn't contain
  275. the inet_aton() funtion. */
  276. int
  277. my_inet_aton (register const char *cp, struct in_addr *addr)
  278. {
  279. register unsigned int val; /* changed from u_long --david */
  280. register int base, n;
  281. register char c;
  282. u_int parts[4];
  283. register u_int *pp = parts;
  284. c = *cp;
  285. for (;;) {
  286. /*
  287. * Collect number up to ``.''.
  288. * Values are specified as for C:
  289. * 0x=hex, 0=octal, isdigit=decimal.
  290. */
  291. if (!isdigit ((int) c))
  292. return (0);
  293. val = 0;
  294. base = 10;
  295. if (c == '0') {
  296. c = *++cp;
  297. if (c == 'x' || c == 'X')
  298. base = 16, c = *++cp;
  299. else
  300. base = 8;
  301. }
  302. for (;;) {
  303. if (isascii ((int) c) && isdigit ((int) c)) {
  304. val = (val * base) + (c - '0');
  305. c = *++cp;
  306. }
  307. else if (base == 16 && isascii ((int) c) && isxdigit ((int) c)) {
  308. val = (val << 4) | (c + 10 - (islower ((int) c) ? 'a' : 'A'));
  309. c = *++cp;
  310. }
  311. else
  312. break;
  313. }
  314. if (c == '.') {
  315. /*
  316. * Internet format:
  317. * a.b.c.d
  318. * a.b.c (with c treated as 16 bits)
  319. * a.b (with b treated as 24 bits)
  320. */
  321. if (pp >= parts + 3)
  322. return (0);
  323. *pp++ = val;
  324. c = *++cp;
  325. }
  326. else
  327. break;
  328. }
  329. /* Check for trailing characters */
  330. if (c != '\0' && (!isascii ((int) c) || !isspace ((int) c)))
  331. return (0);
  332. /* Concoct the address according to the number of parts specified */
  333. n = pp - parts + 1;
  334. switch (n) {
  335. case 0:
  336. return (0); /* initial nondigit */
  337. case 1: /* a -- 32 bits */
  338. break;
  339. case 2: /* a.b -- 8.24 bits */
  340. if (val > 0xffffff)
  341. return (0);
  342. val |= parts[0] << 24;
  343. break;
  344. case 3: /* a.b.c -- 8.8.16 bits */
  345. if (val > 0xffff)
  346. return (0);
  347. val |= (parts[0] << 24) | (parts[1] << 16);
  348. break;
  349. case 4: /* a.b.c.d -- 8.8.8.8 bits */
  350. if (val > 0xff)
  351. return (0);
  352. val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
  353. break;
  354. }
  355. if (addr)
  356. addr->s_addr = htonl (val);
  357. return (1);
  358. }