summaryrefslogtreecommitdiffstats
path: root/plugins/netutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/netutils.c')
-rw-r--r--plugins/netutils.c309
1 files changed, 175 insertions, 134 deletions
diff --git a/plugins/netutils.c b/plugins/netutils.c
index ee81912a..b4c6ff0a 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -28,13 +28,16 @@
28 *****************************************************************************/ 28 *****************************************************************************/
29 29
30#include "common.h" 30#include "common.h"
31#include "output.h"
32#include "states.h"
33#include <sys/types.h>
31#include "netutils.h" 34#include "netutils.h"
32 35
33unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 36unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
34unsigned int socket_timeout_state = STATE_CRITICAL; 37mp_state_enum socket_timeout_state = STATE_CRITICAL;
35 38mp_state_enum econn_refuse_state = STATE_CRITICAL;
36int econn_refuse_state = STATE_CRITICAL;
37bool was_refused = false; 39bool was_refused = false;
40
38#if USE_IPV6 41#if USE_IPV6
39int address_family = AF_UNSPEC; 42int address_family = AF_UNSPEC;
40#else 43#else
@@ -43,119 +46,129 @@ int address_family = AF_INET;
43 46
44/* handles socket timeouts */ 47/* handles socket timeouts */
45void socket_timeout_alarm_handler(int sig) { 48void socket_timeout_alarm_handler(int sig) {
46 if (sig == SIGALRM) 49 mp_subcheck timeout_sc = mp_subcheck_init();
47 printf(_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 50 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 else 51
49 printf(_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 52 if (sig == SIGALRM) {
53 xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
54 } else {
55 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
56 }
50 57
51 exit(socket_timeout_state); 58 mp_check overall = mp_check_init();
59 mp_add_subcheck_to_check(&overall, timeout_sc);
60
61 mp_exit(overall);
52} 62}
53 63
54/* connects to a host on a specified tcp port, sends a string, and gets a 64/* connects to a host on a specified tcp port, sends a string, and gets a
55 response. loops on select-recv until timeout or eof to get all of a 65 response. loops on select-recv until timeout or eof to get all of a
56 multi-packet answer */ 66 multi-packet answer */
57int process_tcp_request2(const char *server_address, int server_port, const char *send_buffer, char *recv_buffer, int recv_size) { 67mp_state_enum process_tcp_request2(const char *server_address, const int server_port,
68 const char *send_buffer, char *recv_buffer,
69 const int recv_size) {
58 70
59 int result; 71 int socket;
60 int send_result;
61 int recv_result;
62 int sd;
63 struct timeval tv;
64 fd_set readfds;
65 int recv_length = 0;
66 72
67 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP); 73 mp_state_enum connect_result =
68 if (result != STATE_OK) 74 np_net_connect(server_address, server_port, &socket, IPPROTO_TCP);
75 if (connect_result != STATE_OK) {
69 return STATE_CRITICAL; 76 return STATE_CRITICAL;
77 }
70 78
71 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 79 mp_state_enum result;
80 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
72 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 81 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
73 printf("%s\n", _("Send failed")); 82 // printf("%s\n", _("Send failed"));
74 result = STATE_WARNING; 83 result = STATE_WARNING;
75 } 84 }
76 85
77 while (1) { 86 fd_set readfds;
87 ssize_t recv_length = 0;
88 while (true) {
78 /* wait up to the number of seconds for socket timeout 89 /* wait up to the number of seconds for socket timeout
79 minus one for data from the host */ 90 minus one for data from the host */
80 tv.tv_sec = socket_timeout - 1; 91 struct timeval timeout = {
81 tv.tv_usec = 0; 92 .tv_sec = socket_timeout - 1,
93 .tv_usec = 0,
94 };
82 FD_ZERO(&readfds); 95 FD_ZERO(&readfds);
83 FD_SET(sd, &readfds); 96 FD_SET(socket, &readfds);
84 select(sd + 1, &readfds, NULL, NULL, &tv); 97 select(socket + 1, &readfds, NULL, NULL, &timeout);
85 98
86 /* make sure some data has arrived */ 99 /* make sure some data has arrived */
87 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */ 100 if (!FD_ISSET(socket, &readfds)) { /* it hasn't */
88 if (!recv_length) { 101 if (!recv_length) {
89 strcpy(recv_buffer, ""); 102 strcpy(recv_buffer, "");
90 printf("%s\n", _("No data was received from host!")); 103 // printf("%s\n", _("No data was received from host!"));
91 result = STATE_WARNING; 104 result = STATE_WARNING;
92 } else { /* this one failed, but previous ones worked */ 105 } else { /* this one failed, but previous ones worked */
93 recv_buffer[recv_length] = 0; 106 recv_buffer[recv_length] = 0;
94 } 107 }
95 break; 108 break;
96 } else { /* it has */ 109 } /* it has */
97 recv_result = recv(sd, recv_buffer + recv_length, (size_t)recv_size - recv_length - 1, 0); 110
98 if (recv_result == -1) { 111 ssize_t recv_result =
99 /* recv failed, bail out */ 112 recv(socket, recv_buffer + recv_length, (size_t)(recv_size - recv_length - 1), 0);
100 strcpy(recv_buffer + recv_length, ""); 113 if (recv_result == -1) {
101 result = STATE_WARNING; 114 /* recv failed, bail out */
102 break; 115 strcpy(recv_buffer + recv_length, "");
103 } else if (recv_result == 0) { 116 result = STATE_WARNING;
104 /* end of file ? */ 117 break;
105 recv_buffer[recv_length] = 0; 118 }
106 break; 119
107 } else { /* we got data! */ 120 if (recv_result == 0) {
108 recv_length += recv_result; 121 /* end of file ? */
109 if (recv_length >= recv_size - 1) { 122 recv_buffer[recv_length] = 0;
110 /* buffer full, we're done */ 123 break;
111 recv_buffer[recv_size - 1] = 0; 124 }
112 break; 125
113 } 126 /* we got data! */
114 } 127 recv_length += recv_result;
128 if (recv_length >= recv_size - 1) {
129 /* buffer full, we're done */
130 recv_buffer[recv_size - 1] = 0;
131 break;
115 } 132 }
116 /* end if(!FD_ISSET(sd,&readfds)) */ 133 /* end if(!FD_ISSET(sd,&readfds)) */
117 } 134 }
118 /* end while(1) */
119 135
120 close(sd); 136 close(socket);
121 return result; 137 return result;
122} 138}
123 139
124/* connects to a host on a specified port, sends a string, and gets a 140/* connects to a host on a specified port, sends a string, and gets a
125 response */ 141 response */
126int process_request(const char *server_address, int server_port, int proto, const char *send_buffer, char *recv_buffer, int recv_size) { 142mp_state_enum process_request(const char *server_address, const int server_port, const int proto,
127 int result; 143 const char *send_buffer, char *recv_buffer, const int recv_size) {
128 int sd;
129 144
130 result = STATE_OK; 145 mp_state_enum result = STATE_OK;
131 146 int socket;
132 result = np_net_connect(server_address, server_port, &sd, proto); 147 result = np_net_connect(server_address, server_port, &socket, proto);
133 if (result != STATE_OK) 148 if (result != STATE_OK) {
134 return STATE_CRITICAL; 149 return STATE_CRITICAL;
150 }
135 151
136 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size); 152 result = send_request(socket, proto, send_buffer, recv_buffer, recv_size);
137 153
138 close(sd); 154 close(socket);
139 155
140 return result; 156 return result;
141} 157}
142 158
143/* opens a tcp or udp connection to a remote host or local socket */ 159/* opens a tcp or udp connection to a remote host or local socket */
144int np_net_connect(const char *host_name, int port, int *sd, int proto) { 160mp_state_enum np_net_connect(const char *host_name, int port, int *socketDescriptor,
161 const int proto) {
145 /* send back STATE_UNKOWN if there's an error 162 /* send back STATE_UNKOWN if there's an error
146 send back STATE_OK if we connect 163 send back STATE_OK if we connect
147 send back STATE_CRITICAL if we can't connect. 164 send back STATE_CRITICAL if we can't connect.
148 Let upstream figure out what to send to the user. */ 165 Let upstream figure out what to send to the user. */
149 struct addrinfo hints; 166 bool is_socket = (host_name[0] == '/');
150 struct addrinfo *r, *res; 167 int socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
151 struct sockaddr_un su;
152 char port_str[6], host[MAX_HOST_ADDRESS_LENGTH];
153 size_t len;
154 int socktype, result;
155 short is_socket = (host_name[0] == '/');
156
157 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
158 168
169 struct addrinfo hints = {};
170 struct addrinfo *res = NULL;
171 int result;
159 /* as long as it doesn't start with a '/', it's assumed a host or ip */ 172 /* as long as it doesn't start with a '/', it's assumed a host or ip */
160 if (!is_socket) { 173 if (!is_socket) {
161 memset(&hints, 0, sizeof(hints)); 174 memset(&hints, 0, sizeof(hints));
@@ -163,37 +176,46 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
163 hints.ai_protocol = proto; 176 hints.ai_protocol = proto;
164 hints.ai_socktype = socktype; 177 hints.ai_socktype = socktype;
165 178
166 len = strlen(host_name); 179 size_t len = strlen(host_name);
167 /* check for an [IPv6] address (and strip the brackets) */ 180 /* check for an [IPv6] address (and strip the brackets) */
168 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') { 181 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
169 host_name++; 182 host_name++;
170 len -= 2; 183 len -= 2;
171 } 184 }
172 if (len >= sizeof(host)) 185
186 char host[MAX_HOST_ADDRESS_LENGTH];
187
188 if (len >= sizeof(host)) {
173 return STATE_UNKNOWN; 189 return STATE_UNKNOWN;
190 }
191
174 memcpy(host, host_name, len); 192 memcpy(host, host_name, len);
175 host[len] = '\0'; 193 host[len] = '\0';
194
195 char port_str[6];
176 snprintf(port_str, sizeof(port_str), "%d", port); 196 snprintf(port_str, sizeof(port_str), "%d", port);
177 result = getaddrinfo(host, port_str, &hints, &res); 197 int getaddrinfo_err = getaddrinfo(host, port_str, &hints, &res);
178 198
179 if (result != 0) { 199 if (getaddrinfo_err != 0) {
180 printf("%s\n", gai_strerror(result)); 200 // printf("%s\n", gai_strerror(result));
181 return STATE_UNKNOWN; 201 return STATE_UNKNOWN;
182 } 202 }
183 203
184 r = res; 204 struct addrinfo *addressPointer = res;
185 while (r) { 205 while (addressPointer) {
186 /* attempt to create a socket */ 206 /* attempt to create a socket */
187 *sd = socket(r->ai_family, socktype, r->ai_protocol); 207 *socketDescriptor =
208 socket(addressPointer->ai_family, socktype, addressPointer->ai_protocol);
188 209
189 if (*sd < 0) { 210 if (*socketDescriptor < 0) {
190 printf("%s\n", _("Socket creation failed")); 211 // printf("%s\n", _("Socket creation failed"));
191 freeaddrinfo(r); 212 freeaddrinfo(addressPointer);
192 return STATE_UNKNOWN; 213 return STATE_UNKNOWN;
193 } 214 }
194 215
195 /* attempt to open a connection */ 216 /* attempt to open a connection */
196 result = connect(*sd, r->ai_addr, r->ai_addrlen); 217 result =
218 connect(*socketDescriptor, addressPointer->ai_addr, addressPointer->ai_addrlen);
197 219
198 if (result == 0) { 220 if (result == 0) {
199 was_refused = false; 221 was_refused = false;
@@ -208,39 +230,48 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
208 } 230 }
209 } 231 }
210 232
211 close(*sd); 233 close(*socketDescriptor);
212 r = r->ai_next; 234 addressPointer = addressPointer->ai_next;
213 } 235 }
236
214 freeaddrinfo(res); 237 freeaddrinfo(res);
215 } 238
216 /* else the hostname is interpreted as a path to a unix socket */ 239 } else {
217 else { 240 /* else the hostname is interpreted as a path to a unix socket */
218 if (strlen(host_name) >= UNIX_PATH_MAX) { 241 if (strlen(host_name) >= UNIX_PATH_MAX) {
219 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket")); 242 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
220 } 243 }
221 memset(&su, 0, sizeof(su)); 244
245 struct sockaddr_un su = {};
222 su.sun_family = AF_UNIX; 246 su.sun_family = AF_UNIX;
223 strncpy(su.sun_path, host_name, UNIX_PATH_MAX); 247 strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
224 *sd = socket(PF_UNIX, SOCK_STREAM, 0); 248 *socketDescriptor = socket(PF_UNIX, SOCK_STREAM, 0);
225 if (*sd < 0) { 249
250 if (*socketDescriptor < 0) {
226 die(STATE_UNKNOWN, _("Socket creation failed")); 251 die(STATE_UNKNOWN, _("Socket creation failed"));
227 } 252 }
228 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 253
229 if (result < 0 && errno == ECONNREFUSED) 254 result = connect(*socketDescriptor, (struct sockaddr *)&su, sizeof(su));
255 if (result < 0 && errno == ECONNREFUSED) {
230 was_refused = true; 256 was_refused = true;
257 }
231 } 258 }
232 259
233 if (result == 0) 260 if (result == 0) {
234 return STATE_OK; 261 return STATE_OK;
235 else if (was_refused) { 262 }
263
264 if (was_refused) {
236 switch (econn_refuse_state) { /* a user-defined expected outcome */ 265 switch (econn_refuse_state) { /* a user-defined expected outcome */
237 case STATE_OK: 266 case STATE_OK:
238 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 267 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
239 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */ 268 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
240 if (is_socket) 269 if (is_socket) {
241 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 270 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
242 else 271 } else {
243 printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno)); 272 // printf("connect to address %s and port %d: %s\n", host_name, port,
273 // strerror(errno));
274 }
244 return STATE_CRITICAL; 275 return STATE_CRITICAL;
245 break; 276 break;
246 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */ 277 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
@@ -248,98 +279,108 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
248 break; 279 break;
249 } 280 }
250 } else { 281 } else {
251 if (is_socket) 282 if (is_socket) {
252 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 283 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
253 else 284 } else {
254 printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno)); 285 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
286 }
255 return STATE_CRITICAL; 287 return STATE_CRITICAL;
256 } 288 }
257} 289}
258 290
259int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size) { 291mp_state_enum send_request(const int socket, const int proto, const char *send_buffer,
260 int result = STATE_OK; 292 char *recv_buffer, const int recv_size) {
261 int send_result; 293 mp_state_enum result = STATE_OK;
262 int recv_result;
263 struct timeval tv;
264 fd_set readfds;
265 294
266 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 295 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
267 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 296 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
268 printf("%s\n", _("Send failed")); 297 // printf("%s\n", _("Send failed"));
269 result = STATE_WARNING; 298 result = STATE_WARNING;
270 } 299 }
271 300
272 /* wait up to the number of seconds for socket timeout minus one 301 /* wait up to the number of seconds for socket timeout minus one
273 for data from the host */ 302 for data from the host */
274 tv.tv_sec = socket_timeout - 1; 303 struct timeval timestamp = {
275 tv.tv_usec = 0; 304 .tv_sec = socket_timeout - 1,
305 .tv_usec = 0,
306 };
307 fd_set readfds;
276 FD_ZERO(&readfds); 308 FD_ZERO(&readfds);
277 FD_SET(sd, &readfds); 309 FD_SET(socket, &readfds);
278 select(sd + 1, &readfds, NULL, NULL, &tv); 310 select(socket + 1, &readfds, NULL, NULL, &timestamp);
279 311
280 /* make sure some data has arrived */ 312 /* make sure some data has arrived */
281 if (!FD_ISSET(sd, &readfds)) { 313 if (!FD_ISSET(socket, &readfds)) {
282 strcpy(recv_buffer, ""); 314 strcpy(recv_buffer, "");
283 printf("%s\n", _("No data was received from host!")); 315 // printf("%s\n", _("No data was received from host!"));
284 result = STATE_WARNING; 316 result = STATE_WARNING;
285 } 317 } else {
286 318 ssize_t recv_result = recv(socket, recv_buffer, (size_t)(recv_size - 1), 0);
287 else {
288 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
289 if (recv_result == -1) { 319 if (recv_result == -1) {
290 strcpy(recv_buffer, ""); 320 strcpy(recv_buffer, "");
291 if (proto != IPPROTO_TCP) 321 if (proto != IPPROTO_TCP) {
292 printf("%s\n", _("Receive failed")); 322 // printf("%s\n", _("Receive failed"));
323 }
293 result = STATE_WARNING; 324 result = STATE_WARNING;
294 } else 325 } else {
295 recv_buffer[recv_result] = 0; 326 recv_buffer[recv_result] = 0;
327 }
296 328
297 /* die returned string */ 329 /* die returned string */
298 recv_buffer[recv_size - 1] = 0; 330 recv_buffer[recv_size - 1] = 0;
299 } 331 }
332
300 return result; 333 return result;
301} 334}
302 335
303bool is_host(const char *address) { 336bool is_host(const char *address) {
304 if (is_addr(address) || is_hostname(address)) 337 if (is_addr(address) || is_hostname(address)) {
305 return (true); 338 return (true);
339 }
306 340
307 return (false); 341 return (false);
308} 342}
309 343
310void host_or_die(const char *str) { 344void host_or_die(const char *str) {
311 if (!str || (!is_addr(str) && !is_hostname(str))) 345 if (!str || (!is_addr(str) && !is_hostname(str))) {
312 usage_va(_("Invalid hostname/address - %s"), str); 346 usage_va(_("Invalid hostname/address - %s"), str);
347 }
313} 348}
314 349
315bool is_addr(const char *address) { 350bool is_addr(const char *address) {
316#ifdef USE_IPV6 351#ifdef USE_IPV6
317 if (address_family == AF_INET && is_inet_addr(address)) 352 if (address_family == AF_INET && is_inet_addr(address)) {
318 return true; 353 return true;
319 else if (address_family == AF_INET6 && is_inet6_addr(address)) 354 }
355
356 if (address_family == AF_INET6 && is_inet6_addr(address)) {
320 return true; 357 return true;
358 }
321#else 359#else
322 if (is_inet_addr(address)) 360 if (is_inet_addr(address)) {
323 return (true); 361 return true;
362 }
324#endif 363#endif
325 364
326 return (false); 365 return false;
327} 366}
328 367
329int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) { 368bool dns_lookup(const char *node_string, struct sockaddr_storage *ss, const int family) {
330 struct addrinfo hints; 369 struct addrinfo hints;
331 struct addrinfo *res;
332 int retval;
333
334 memset(&hints, 0, sizeof(struct addrinfo)); 370 memset(&hints, 0, sizeof(struct addrinfo));
335 hints.ai_family = family; 371 hints.ai_family = family;
336 372
337 retval = getaddrinfo(in, NULL, &hints, &res); 373 struct addrinfo *res;
338 if (retval != 0) 374 int retval = getaddrinfo(node_string, NULL, &hints, &res);
375 if (retval != 0) {
339 return false; 376 return false;
377 }
340 378
341 if (ss != NULL) 379 if (ss != NULL) {
342 memcpy(ss, res->ai_addr, res->ai_addrlen); 380 memcpy(ss, res->ai_addr, res->ai_addrlen);
381 }
382
343 freeaddrinfo(res); 383 freeaddrinfo(res);
384
344 return true; 385 return true;
345} 386}