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