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