4
0

netutils.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*****************************************************************************
  2. *
  3. * Nagios plugins network utilities
  4. *
  5. * License: GPL
  6. * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
  7. * Copyright (c) 2003-2008 Nagios Plugins Development Team
  8. *
  9. * Last Modified: $Date$
  10. *
  11. * Description:
  12. *
  13. * This file contains commons functions used in many of the plugins.
  14. *
  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 3 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, see <http://www.gnu.org/licenses/>.
  28. *
  29. * $Id$
  30. *
  31. *****************************************************************************/
  32. #define LOCAL_TIMEOUT_ALARM_HANDLER
  33. #include "common.h"
  34. #include "netutils.h"
  35. unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
  36. int econn_refuse_state = STATE_CRITICAL;
  37. int was_refused = FALSE;
  38. #if USE_IPV6
  39. int address_family = AF_UNSPEC;
  40. #else
  41. int address_family = AF_INET;
  42. #endif
  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);
  51. exit (STATE_CRITICAL);
  52. }
  53. /* connects to a host on a specified tcp port, sends a string, and gets a
  54. response. loops on select-recv until timeout or eof to get all of a
  55. multi-packet answer */
  56. int
  57. process_tcp_request2 (const char *server_address, int server_port,
  58. const char *send_buffer, char *recv_buffer, int recv_size)
  59. {
  60. int result;
  61. int send_result;
  62. int recv_result;
  63. int sd;
  64. struct timeval tv;
  65. fd_set readfds;
  66. int recv_length = 0;
  67. result = np_net_connect (server_address, server_port, &sd, IPPROTO_TCP);
  68. if (result != STATE_OK)
  69. return STATE_CRITICAL;
  70. send_result = send (sd, send_buffer, strlen (send_buffer), 0);
  71. if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
  72. printf ("%s\n", _("Send failed"));
  73. result = STATE_WARNING;
  74. }
  75. while (1) {
  76. /* wait up to the number of seconds for socket timeout
  77. minus one for data from the host */
  78. tv.tv_sec = socket_timeout - 1;
  79. tv.tv_usec = 0;
  80. FD_ZERO (&readfds);
  81. FD_SET (sd, &readfds);
  82. select (sd + 1, &readfds, NULL, NULL, &tv);
  83. /* make sure some data has arrived */
  84. if (!FD_ISSET (sd, &readfds)) { /* it hasn't */
  85. if (!recv_length) {
  86. strcpy (recv_buffer, "");
  87. printf ("%s\n", _("No data was received from host!"));
  88. result = STATE_WARNING;
  89. }
  90. else { /* this one failed, but previous ones worked */
  91. recv_buffer[recv_length] = 0;
  92. }
  93. break;
  94. }
  95. else { /* it has */
  96. recv_result =
  97. recv (sd, recv_buffer + recv_length,
  98. (size_t)recv_size - recv_length - 1, 0);
  99. if (recv_result == -1) {
  100. /* recv failed, bail out */
  101. strcpy (recv_buffer + recv_length, "");
  102. result = STATE_WARNING;
  103. break;
  104. }
  105. else if (recv_result == 0) {
  106. /* end of file ? */
  107. recv_buffer[recv_length] = 0;
  108. break;
  109. }
  110. else { /* we got data! */
  111. recv_length += recv_result;
  112. if (recv_length >= recv_size - 1) {
  113. /* buffer full, we're done */
  114. recv_buffer[recv_size - 1] = 0;
  115. break;
  116. }
  117. }
  118. }
  119. /* end if(!FD_ISSET(sd,&readfds)) */
  120. }
  121. /* end while(1) */
  122. close (sd);
  123. return result;
  124. }
  125. /* connects to a host on a specified port, sends a string, and gets a
  126. response */
  127. int
  128. process_request (const char *server_address, int server_port, int proto,
  129. const char *send_buffer, char *recv_buffer, int recv_size)
  130. {
  131. int result;
  132. int sd;
  133. result = STATE_OK;
  134. result = np_net_connect (server_address, server_port, &sd, proto);
  135. if (result != STATE_OK)
  136. return STATE_CRITICAL;
  137. result = send_request (sd, proto, send_buffer, recv_buffer, recv_size);
  138. close (sd);
  139. return result;
  140. }
  141. /* opens a tcp or udp connection to a remote host or local socket */
  142. int
  143. np_net_connect (const char *host_name, int port, int *sd, int proto)
  144. {
  145. struct addrinfo hints;
  146. struct addrinfo *r, *res;
  147. struct sockaddr_un su;
  148. char port_str[6], host[MAX_HOST_ADDRESS_LENGTH];
  149. size_t len;
  150. int socktype, result;
  151. socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
  152. /* as long as it doesn't start with a '/', it's assumed a host or ip */
  153. if(host_name[0] != '/'){
  154. memset (&hints, 0, sizeof (hints));
  155. hints.ai_family = address_family;
  156. hints.ai_protocol = proto;
  157. hints.ai_socktype = socktype;
  158. len = strlen (host_name);
  159. /* check for an [IPv6] address (and strip the brackets) */
  160. if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
  161. host_name++;
  162. len -= 2;
  163. }
  164. if (len >= sizeof(host))
  165. return STATE_UNKNOWN;
  166. memcpy (host, host_name, len);
  167. host[len] = '\0';
  168. snprintf (port_str, sizeof (port_str), "%d", port);
  169. result = getaddrinfo (host, port_str, &hints, &res);
  170. if (result != 0) {
  171. printf ("%s\n", gai_strerror (result));
  172. return STATE_UNKNOWN;
  173. }
  174. r = res;
  175. while (r) {
  176. /* attempt to create a socket */
  177. *sd = socket (r->ai_family, socktype, r->ai_protocol);
  178. if (*sd < 0) {
  179. printf ("%s\n", _("Socket creation failed"));
  180. freeaddrinfo (r);
  181. return STATE_UNKNOWN;
  182. }
  183. /* attempt to open a connection */
  184. result = connect (*sd, r->ai_addr, r->ai_addrlen);
  185. if (result == 0) {
  186. was_refused = FALSE;
  187. break;
  188. }
  189. if (result < 0) {
  190. switch (errno) {
  191. case ECONNREFUSED:
  192. was_refused = TRUE;
  193. break;
  194. }
  195. }
  196. close (*sd);
  197. r = r->ai_next;
  198. }
  199. freeaddrinfo (res);
  200. }
  201. /* else the hostname is interpreted as a path to a unix socket */
  202. else {
  203. if(strlen(host_name) >= UNIX_PATH_MAX){
  204. die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
  205. }
  206. memset(&su, 0, sizeof(su));
  207. su.sun_family = AF_UNIX;
  208. strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
  209. *sd = socket(PF_UNIX, SOCK_STREAM, 0);
  210. if(*sd < 0){
  211. die(STATE_UNKNOWN, _("Socket creation failed"));
  212. }
  213. result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
  214. if (result < 0 && errno == ECONNREFUSED)
  215. was_refused = TRUE;
  216. }
  217. if (result == 0)
  218. return STATE_OK;
  219. else if (was_refused) {
  220. switch (econn_refuse_state) { /* a user-defined expected outcome */
  221. case STATE_OK:
  222. case STATE_WARNING: /* user wants WARN or OK on refusal */
  223. return econn_refuse_state;
  224. break;
  225. case STATE_CRITICAL: /* user did not set econn_refuse_state */
  226. printf ("%s\n", strerror(errno));
  227. return econn_refuse_state;
  228. break;
  229. default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
  230. return STATE_UNKNOWN;
  231. break;
  232. }
  233. }
  234. else {
  235. printf ("%s\n", strerror(errno));
  236. return STATE_CRITICAL;
  237. }
  238. }
  239. int
  240. send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size)
  241. {
  242. int result = STATE_OK;
  243. int send_result;
  244. int recv_result;
  245. struct timeval tv;
  246. fd_set readfds;
  247. send_result = send (sd, send_buffer, strlen (send_buffer), 0);
  248. if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
  249. printf ("%s\n", _("Send failed"));
  250. result = STATE_WARNING;
  251. }
  252. /* wait up to the number of seconds for socket timeout minus one
  253. for data from the host */
  254. tv.tv_sec = socket_timeout - 1;
  255. tv.tv_usec = 0;
  256. FD_ZERO (&readfds);
  257. FD_SET (sd, &readfds);
  258. select (sd + 1, &readfds, NULL, NULL, &tv);
  259. /* make sure some data has arrived */
  260. if (!FD_ISSET (sd, &readfds)) {
  261. strcpy (recv_buffer, "");
  262. printf ("%s\n", _("No data was received from host!"));
  263. result = STATE_WARNING;
  264. }
  265. else {
  266. recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0);
  267. if (recv_result == -1) {
  268. strcpy (recv_buffer, "");
  269. if (proto != IPPROTO_TCP)
  270. printf ("%s\n", _("Receive failed"));
  271. result = STATE_WARNING;
  272. }
  273. else
  274. recv_buffer[recv_result] = 0;
  275. /* die returned string */
  276. recv_buffer[recv_size - 1] = 0;
  277. }
  278. return result;
  279. }
  280. int
  281. is_host (const char *address)
  282. {
  283. if (is_addr (address) || is_hostname (address))
  284. return (TRUE);
  285. return (FALSE);
  286. }
  287. void
  288. host_or_die(const char *str)
  289. {
  290. if(!str || (!is_addr(str) && !is_hostname(str)))
  291. usage_va(_("Invalid hostname/address - %s"), str);
  292. }
  293. int
  294. is_addr (const char *address)
  295. {
  296. #ifdef USE_IPV6
  297. if (address_family == AF_INET && is_inet_addr (address))
  298. return TRUE;
  299. else if (address_family == AF_INET6 && is_inet6_addr (address))
  300. return TRUE;
  301. #else
  302. if (is_inet_addr (address))
  303. return (TRUE);
  304. #endif
  305. return (FALSE);
  306. }
  307. int
  308. resolve_host_or_addr (const char *address, int family)
  309. {
  310. struct addrinfo hints;
  311. struct addrinfo *res;
  312. int retval;
  313. memset (&hints, 0, sizeof (hints));
  314. hints.ai_family = family;
  315. retval = getaddrinfo (address, NULL, &hints, &res);
  316. if (retval != 0)
  317. return FALSE;
  318. else {
  319. freeaddrinfo (res);
  320. return TRUE;
  321. }
  322. }