summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins-root/Makefile.am3
-rw-r--r--plugins-root/check_dhcp.c867
-rw-r--r--plugins-root/check_dhcp.d/config.h50
-rw-r--r--plugins-root/t/check_dhcp.t24
4 files changed, 554 insertions, 390 deletions
diff --git a/plugins-root/Makefile.am b/plugins-root/Makefile.am
index fffc0575..b6342909 100644
--- a/plugins-root/Makefile.am
+++ b/plugins-root/Makefile.am
@@ -25,7 +25,8 @@ noinst_PROGRAMS = check_dhcp check_icmp @EXTRAS_ROOT@
25EXTRA_PROGRAMS = pst3 25EXTRA_PROGRAMS = pst3
26 26
27EXTRA_DIST = t pst3.c \ 27EXTRA_DIST = t pst3.c \
28 check_icmp.d 28 check_icmp.d \
29 check_dhcp.d
29 30
30BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a 31BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a
31NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS) 32NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
diff --git a/plugins-root/check_dhcp.c b/plugins-root/check_dhcp.c
index 6802232e..daed9cb0 100644
--- a/plugins-root/check_dhcp.c
+++ b/plugins-root/check_dhcp.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)
7 * Copyright (c) 2001-2023 Monitoring Plugins Development Team 7 * Copyright (c) 2001-2025 Monitoring Plugins Development Team
8 * 8 *
9 * Description: 9 * Description:
10 * 10 *
@@ -34,13 +34,17 @@
34 *****************************************************************************/ 34 *****************************************************************************/
35 35
36const char *progname = "check_dhcp"; 36const char *progname = "check_dhcp";
37const char *copyright = "2001-2024"; 37const char *copyright = "2001-2025";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "common.h" 40#include "../plugins/common.h"
41#include "netutils.h" 41#include "../plugins/utils.h"
42#include "utils.h" 42#include "./check_dhcp.d/config.h"
43#include "../lib/output.h"
44#include "../lib/utils_base.h"
43 45
46#include "states.h"
47#include <stdint.h>
44#include <ctype.h> 48#include <ctype.h>
45#include <stdio.h> 49#include <stdio.h>
46#include <stdlib.h> 50#include <stdlib.h>
@@ -111,8 +115,9 @@ static long mac_addr_dlpi(const char *, int, u_char *);
111 115
112/**** Common definitions ****/ 116/**** Common definitions ****/
113 117
114#define OK 0 118#define OK 0
115#define ERROR -1 119#define ERROR -1
120#define MAC_ADDR_LEN 6
116 121
117/**** DHCP definitions ****/ 122/**** DHCP definitions ****/
118 123
@@ -149,12 +154,6 @@ typedef struct dhcp_offer_struct {
149 struct dhcp_offer_struct *next; 154 struct dhcp_offer_struct *next;
150} dhcp_offer; 155} dhcp_offer;
151 156
152typedef struct requested_server_struct {
153 struct in_addr server_address;
154 bool answered;
155 struct requested_server_struct *next;
156} requested_server;
157
158#define BOOTREQUEST 1 157#define BOOTREQUEST 1
159#define BOOTREPLY 2 158#define BOOTREPLY 2
160 159
@@ -186,65 +185,60 @@ typedef struct requested_server_struct {
186#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */ 185#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */
187#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */ 186#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */
188 187
189static bool unicast = false; /* unicast mode: mimic a DHCP relay */
190static bool exclusive = false; /* exclusive mode aka "rogue DHCP server detection" */
191static struct in_addr my_ip; /* our address (required for relay) */
192static struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
193static unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
194static unsigned char *user_specified_mac = NULL;
195
196static char network_interface_name[IFNAMSIZ] = "eth0";
197
198static uint32_t packet_xid = 0;
199
200static uint32_t dhcp_lease_time = 0;
201static uint32_t dhcp_renewal_time = 0;
202static uint32_t dhcp_rebinding_time = 0;
203
204static int dhcpoffer_timeout = 2;
205
206static dhcp_offer *dhcp_offer_list = NULL;
207static requested_server *requested_server_list = NULL;
208
209static int valid_responses = 0; /* number of valid DHCPOFFERs we received */
210static int requested_servers = 0;
211static int requested_responses = 0;
212
213static bool request_specific_address = false;
214static bool received_requested_address = false;
215static int verbose = 0; 188static int verbose = 0;
216static struct in_addr requested_address;
217 189
218static int process_arguments(int, char **); 190typedef struct process_arguments_wrapper {
219static int call_getopt(int, char **); 191 int error;
220static int validate_arguments(int); 192 check_dhcp_config config;
193} process_arguments_wrapper;
194
195static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
221void print_usage(void); 196void print_usage(void);
222static void print_help(void); 197static void print_help(void);
223 198
224static void resolve_host(const char *in, struct in_addr *out); 199static void resolve_host(const char * /*in*/, struct in_addr * /*out*/);
225static unsigned char *mac_aton(const char *); 200static unsigned char *mac_aton(const char * /*string*/);
226static void print_hardware_address(const unsigned char *); 201static void print_hardware_address(const unsigned char * /*address*/);
227static int get_hardware_address(int, char *); 202static int get_hardware_address(int /*sock*/, char * /*interface_name*/, unsigned char *client_hardware_address);
228static int get_ip_address(int, char *); 203
229 204typedef struct get_ip_address_wrapper {
230static int send_dhcp_discover(int); 205 int error;
231static int get_dhcp_offer(int); 206 struct in_addr my_ip;
232 207} get_ip_address_wrapper;
233static int get_results(void); 208static get_ip_address_wrapper get_ip_address(int /*sock*/, char * /*interface_name*/);
234 209
235static int add_dhcp_offer(struct in_addr, dhcp_packet *); 210typedef struct send_dhcp_discover_wrapper {
236static int free_dhcp_offer_list(void); 211 int error;
237static int free_requested_server_list(void); 212 uint32_t packet_xid;
238 213} send_dhcp_discover_wrapper;
239static int create_dhcp_socket(void); 214static send_dhcp_discover_wrapper send_dhcp_discover(int socket, bool unicast, struct in_addr dhcp_ip, struct in_addr requested_address,
240static int close_dhcp_socket(int); 215 bool request_specific_address, struct in_addr my_ip,
241static int send_dhcp_packet(void *, int, int, struct sockaddr_in *); 216 unsigned char *client_hardware_address);
242static int receive_dhcp_packet(void *, int, int, int, struct sockaddr_in *); 217typedef struct get_dhcp_offer_wrapper {
218 int error;
219 int valid_responses;
220 dhcp_offer *dhcp_offer_list;
221} get_dhcp_offer_wrapper;
222static get_dhcp_offer_wrapper get_dhcp_offer(int /*sock*/, int dhcpoffer_timeout, uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
223 const unsigned char *client_hardware_address);
224
225static mp_subcheck get_results(bool exclusive, int requested_servers, struct in_addr requested_address, bool request_specific_address,
226 requested_server *requested_server_list, int valid_responses, dhcp_offer *dhcp_offer_list);
227
228typedef struct add_dhcp_offer_wrapper {
229 int error;
230 dhcp_offer *dhcp_offer_list;
231} add_dhcp_offer_wrapper;
232static add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr /*source*/, dhcp_packet * /*offer_packet*/, dhcp_offer *dhcp_offer_list);
233static int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list);
234static int free_requested_server_list(requested_server *requested_server_list);
235
236static int create_dhcp_socket(bool /*unicast*/, char *network_interface_name);
237static int close_dhcp_socket(int /*sock*/);
238static int send_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/, struct sockaddr_in * /*dest*/);
239static int receive_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/, int /*timeout*/, struct sockaddr_in * /*address*/);
243 240
244int main(int argc, char **argv) { 241int main(int argc, char **argv) {
245 int dhcp_socket;
246 int result = STATE_UNKNOWN;
247
248 setlocale(LC_ALL, ""); 242 setlocale(LC_ALL, "");
249 bindtextdomain(PACKAGE, LOCALEDIR); 243 bindtextdomain(PACKAGE, LOCALEDIR);
250 textdomain(PACKAGE); 244 textdomain(PACKAGE);
@@ -252,43 +246,80 @@ int main(int argc, char **argv) {
252 /* Parse extra opts if any */ 246 /* Parse extra opts if any */
253 argv = np_extra_opts(&argc, argv, progname); 247 argv = np_extra_opts(&argc, argv, progname);
254 248
255 if (process_arguments(argc, argv) != OK) { 249 process_arguments_wrapper tmp = process_arguments(argc, argv);
250
251 if (tmp.error != OK) {
256 usage4(_("Could not parse arguments")); 252 usage4(_("Could not parse arguments"));
257 } 253 }
258 254
255 check_dhcp_config config = tmp.config;
256 if (config.output_format_is_set) {
257 mp_set_format(config.output_format);
258 }
259
259 /* create socket for DHCP communications */ 260 /* create socket for DHCP communications */
260 dhcp_socket = create_dhcp_socket(); 261 int dhcp_socket = create_dhcp_socket(config.unicast_mode, config.network_interface_name);
261 262
262 /* get hardware address of client machine */ 263 /* get hardware address of client machine */
263 if (user_specified_mac != NULL) 264 unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
264 memcpy(client_hardware_address, user_specified_mac, 6); 265 if (config.user_specified_mac != NULL) {
265 else 266 memcpy(client_hardware_address, config.user_specified_mac, MAC_ADDR_LEN);
266 get_hardware_address(dhcp_socket, network_interface_name); 267 } else {
268 get_hardware_address(dhcp_socket, config.network_interface_name, client_hardware_address);
269 }
267 270
268 if (unicast) /* get IP address of client machine */ 271 struct in_addr my_ip = {0};
269 get_ip_address(dhcp_socket, network_interface_name); 272
273 if (config.unicast_mode) { /* get IP address of client machine */
274 get_ip_address_wrapper tmp_get_ip = get_ip_address(dhcp_socket, config.network_interface_name);
275 if (tmp_get_ip.error == OK) {
276 my_ip = tmp_get_ip.my_ip;
277 } else {
278 // TODO failed to get own IP
279 die(STATE_UNKNOWN, "Failed to retrieve my own IP address in unicast mode");
280 }
281 }
270 282
271 /* send DHCPDISCOVER packet */ 283 /* send DHCPDISCOVER packet */
272 send_dhcp_discover(dhcp_socket); 284 send_dhcp_discover_wrapper disco_res = send_dhcp_discover(dhcp_socket, config.unicast_mode, config.dhcp_ip, config.requested_address,
285 config.request_specific_address, my_ip, client_hardware_address);
286
287 if (disco_res.error != OK) {
288 // DO something?
289 die(STATE_UNKNOWN, "Failed to send DHCP discover");
290 }
273 291
274 /* wait for a DHCPOFFER packet */ 292 /* wait for a DHCPOFFER packet */
275 get_dhcp_offer(dhcp_socket); 293 get_dhcp_offer_wrapper offer_res =
294 get_dhcp_offer(dhcp_socket, config.dhcpoffer_timeout, disco_res.packet_xid, NULL, client_hardware_address);
295
296 int valid_responses = 0;
297 dhcp_offer *dhcp_offer_list = NULL;
298 if (offer_res.error == OK) {
299 valid_responses = offer_res.valid_responses;
300 dhcp_offer_list = offer_res.dhcp_offer_list;
301 } else {
302 die(STATE_UNKNOWN, "Failed to get DHCP offers");
303 }
276 304
277 /* close socket we created */ 305 /* close socket we created */
278 close_dhcp_socket(dhcp_socket); 306 close_dhcp_socket(dhcp_socket);
279 307
280 /* determine state/plugin output to return */ 308 mp_check overall = mp_check_init();
281 result = get_results();
282 309
310 /* determine state/plugin output to return */
311 mp_subcheck sc_res = get_results(config.exclusive_mode, config.num_of_requested_servers, config.requested_address,
312 config.request_specific_address, config.requested_server_list, valid_responses, dhcp_offer_list);
313 mp_add_subcheck_to_check(&overall, sc_res);
283 /* free allocated memory */ 314 /* free allocated memory */
284 free_dhcp_offer_list(); 315 free_dhcp_offer_list(dhcp_offer_list);
285 free_requested_server_list(); 316 free_requested_server_list(config.requested_server_list);
286 317
287 return result; 318 mp_exit(overall);
288} 319}
289 320
290/* determines hardware address on client machine */ 321/* determines hardware address on client machine */
291static int get_hardware_address(int sock, char *interface_name) { 322int get_hardware_address(int sock, char *interface_name, unsigned char *client_hardware_address) {
292 323
293#if defined(__linux__) 324#if defined(__linux__)
294 struct ifreq ifr; 325 struct ifreq ifr;
@@ -302,7 +333,7 @@ static int get_hardware_address(int sock, char *interface_name) {
302 exit(STATE_UNKNOWN); 333 exit(STATE_UNKNOWN);
303 } 334 }
304 335
305 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, 6); 336 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
306 337
307#elif defined(__bsd__) 338#elif defined(__bsd__)
308 /* King 2004 see ACKNOWLEDGEMENTS */ 339 /* King 2004 see ACKNOWLEDGEMENTS */
@@ -358,8 +389,9 @@ static int get_hardware_address(int sock, char *interface_name) {
358 int i; 389 int i;
359 p = interface_name + strlen(interface_name) - 1; 390 p = interface_name + strlen(interface_name) - 1;
360 for (i = strlen(interface_name) - 1; i > 0; p--) { 391 for (i = strlen(interface_name) - 1; i > 0; p--) {
361 if (isalpha(*p)) 392 if (isalpha(*p)) {
362 break; 393 break;
394 }
363 } 395 }
364 p++; 396 p++;
365 if (p != interface_name) { 397 if (p != interface_name) {
@@ -393,14 +425,15 @@ static int get_hardware_address(int sock, char *interface_name) {
393 exit(STATE_UNKNOWN); 425 exit(STATE_UNKNOWN);
394#endif 426#endif
395 427
396 if (verbose) 428 if (verbose) {
397 print_hardware_address(client_hardware_address); 429 print_hardware_address(client_hardware_address);
430 }
398 431
399 return OK; 432 return OK;
400} 433}
401 434
402/* determines IP address of the client interface */ 435/* determines IP address of the client interface */
403static int get_ip_address(int sock, char *interface_name) { 436get_ip_address_wrapper get_ip_address(int sock, char *interface_name) {
404#if defined(SIOCGIFADDR) 437#if defined(SIOCGIFADDR)
405 struct ifreq ifr; 438 struct ifreq ifr;
406 439
@@ -412,28 +445,28 @@ static int get_ip_address(int sock, char *interface_name) {
412 exit(STATE_UNKNOWN); 445 exit(STATE_UNKNOWN);
413 } 446 }
414 447
415 my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
416
417#else 448#else
418 printf(_("Error: Cannot get interface IP address on this platform.\n")); 449 printf(_("Error: Cannot get interface IP address on this platform.\n"));
419 exit(STATE_UNKNOWN); 450 exit(STATE_UNKNOWN);
420#endif 451#endif
421 452
422 if (verbose) 453 get_ip_address_wrapper result = {
423 printf(_("Pretending to be relay client %s\n"), inet_ntoa(my_ip)); 454 .error = OK,
455 .my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,
456 };
424 457
425 return OK; 458 if (verbose) {
459 printf(_("Pretending to be relay client %s\n"), inet_ntoa(result.my_ip));
460 }
461
462 return result;
426} 463}
427 464
428/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 465/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
429static int send_dhcp_discover(int sock) { 466static send_dhcp_discover_wrapper send_dhcp_discover(int sock, bool unicast, struct in_addr dhcp_ip, struct in_addr requested_address,
430 dhcp_packet discover_packet; 467 bool request_specific_address, struct in_addr my_ip,
431 struct sockaddr_in sockaddr_broadcast; 468 unsigned char *client_hardware_address) {
432 unsigned short opts; 469 dhcp_packet discover_packet = {0};
433
434 /* clear the packet data structure */
435 bzero(&discover_packet, sizeof(discover_packet));
436
437 /* boot request flag (backward compatible with BOOTP servers) */ 470 /* boot request flag (backward compatible with BOOTP servers) */
438 discover_packet.op = BOOTREQUEST; 471 discover_packet.op = BOOTREQUEST;
439 472
@@ -443,12 +476,15 @@ static int send_dhcp_discover(int sock) {
443 /* length of our hardware address */ 476 /* length of our hardware address */
444 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH; 477 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
445 478
479 send_dhcp_discover_wrapper result = {
480 .error = OK,
481 };
446 /* 482 /*
447 * transaction ID is supposed to be random. 483 * transaction ID is supposed to be random.
448 */ 484 */
449 srand(time(NULL) ^ getpid()); 485 srand(time(NULL) ^ getpid());
450 packet_xid = random(); 486 result.packet_xid = random();
451 discover_packet.xid = htonl(packet_xid); 487 discover_packet.xid = htonl(result.packet_xid);
452 488
453 /*discover_packet.secs=htons(65535);*/ 489 /*discover_packet.secs=htons(65535);*/
454 discover_packet.secs = 0xFF; 490 discover_packet.secs = 0xFF;
@@ -468,7 +504,7 @@ static int send_dhcp_discover(int sock) {
468 discover_packet.options[2] = '\x53'; 504 discover_packet.options[2] = '\x53';
469 discover_packet.options[3] = '\x63'; 505 discover_packet.options[3] = '\x63';
470 506
471 opts = 4; 507 unsigned short opts = 4;
472 /* DHCP message type is embedded in options field */ 508 /* DHCP message type is embedded in options field */
473 discover_packet.options[opts++] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 509 discover_packet.options[opts++] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */
474 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */ 510 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */
@@ -484,17 +520,19 @@ static int send_dhcp_discover(int sock) {
484 discover_packet.options[opts++] = (char)DHCP_OPTION_END; 520 discover_packet.options[opts++] = (char)DHCP_OPTION_END;
485 521
486 /* unicast fields */ 522 /* unicast fields */
487 if (unicast) 523 if (unicast) {
488 discover_packet.giaddr.s_addr = my_ip.s_addr; 524 discover_packet.giaddr.s_addr = my_ip.s_addr;
525 }
489 526
490 /* see RFC 1542, 4.1.1 */ 527 /* see RFC 1542, 4.1.1 */
491 discover_packet.hops = unicast ? 1 : 0; 528 discover_packet.hops = unicast ? 1 : 0;
492 529
493 /* send the DHCPDISCOVER packet to broadcast address */ 530 /* send the DHCPDISCOVER packet to broadcast address */
494 sockaddr_broadcast.sin_family = AF_INET; 531 struct sockaddr_in sockaddr_broadcast = {
495 sockaddr_broadcast.sin_port = htons(DHCP_SERVER_PORT); 532 .sin_family = AF_INET,
496 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; 533 .sin_port = htons(DHCP_SERVER_PORT),
497 bzero(&sockaddr_broadcast.sin_zero, sizeof(sockaddr_broadcast.sin_zero)); 534 .sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST,
535 };
498 536
499 if (verbose) { 537 if (verbose) {
500 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port)); 538 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port));
@@ -508,56 +546,56 @@ static int send_dhcp_discover(int sock) {
508 /* send the DHCPDISCOVER packet out */ 546 /* send the DHCPDISCOVER packet out */
509 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast); 547 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast);
510 548
511 if (verbose) 549 if (verbose) {
512 printf("\n\n"); 550 printf("\n\n");
551 }
513 552
514 return OK; 553 return result;
515} 554}
516 555
517/* waits for a DHCPOFFER message from one or more DHCP servers */ 556/* waits for a DHCPOFFER message from one or more DHCP servers */
518static int get_dhcp_offer(int sock) { 557get_dhcp_offer_wrapper get_dhcp_offer(int sock, int dhcpoffer_timeout, uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
519 dhcp_packet offer_packet; 558 const unsigned char *client_hardware_address) {
520 struct sockaddr_in source;
521 struct sockaddr_in via;
522 int result = OK;
523 int responses = 0;
524 int x;
525 time_t start_time; 559 time_t start_time;
526 time_t current_time;
527
528 time(&start_time); 560 time(&start_time);
529 561
562 int result = OK;
563 int responses = 0;
564 int valid_responses = 0;
530 /* receive as many responses as we can */ 565 /* receive as many responses as we can */
531 for (responses = 0, valid_responses = 0;;) { 566 for (;;) {
532 567 time_t current_time;
533 time(&current_time); 568 time(&current_time);
534 if ((current_time - start_time) >= dhcpoffer_timeout) 569 if ((current_time - start_time) >= dhcpoffer_timeout) {
535 break; 570 break;
571 }
536 572
537 if (verbose) 573 if (verbose) {
538 printf("\n\n"); 574 printf("\n\n");
575 }
539 576
540 bzero(&source, sizeof(source)); 577 struct sockaddr_in source = {0};
541 bzero(&via, sizeof(via)); 578 dhcp_packet offer_packet = {0};
542 bzero(&offer_packet, sizeof(offer_packet));
543 579
544 result = OK; 580 result = OK;
545 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout, &source); 581 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout, &source);
546 582
547 if (result != OK) { 583 if (result != OK) {
548 if (verbose) 584 if (verbose) {
549 printf(_("Result=ERROR\n")); 585 printf(_("Result=ERROR\n"));
586 }
550 587
551 continue; 588 continue;
552 } else { 589 }
553 if (verbose) 590 if (verbose) {
554 printf(_("Result=OK\n")); 591 printf(_("Result=OK\n"));
555
556 responses++;
557 } 592 }
558 593
594 responses++;
595
559 /* The "source" is either a server or a relay. */ 596 /* The "source" is either a server or a relay. */
560 /* Save a copy of "source" into "via" even if it's via itself */ 597 /* Save a copy of "source" into "via" even if it's via itself */
598 struct sockaddr_in via = {0};
561 memcpy(&via, &source, sizeof(source)); 599 memcpy(&via, &source, sizeof(source));
562 600
563 if (verbose) { 601 if (verbose) {
@@ -568,30 +606,37 @@ static int get_dhcp_offer(int sock) {
568 606
569 /* check packet xid to see if its the same as the one we used in the discover packet */ 607 /* check packet xid to see if its the same as the one we used in the discover packet */
570 if (ntohl(offer_packet.xid) != packet_xid) { 608 if (ntohl(offer_packet.xid) != packet_xid) {
571 if (verbose) 609 if (verbose) {
572 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"), ntohl(offer_packet.xid), packet_xid); 610 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"), ntohl(offer_packet.xid),
611 packet_xid);
612 }
573 613
574 continue; 614 continue;
575 } 615 }
576 616
577 /* check hardware address */ 617 /* check hardware address */
578 result = OK; 618 result = OK;
579 if (verbose) 619 if (verbose) {
580 printf("DHCPOFFER chaddr: "); 620 printf("DHCPOFFER chaddr: ");
621 }
581 622
582 for (x = 0; x < ETHERNET_HARDWARE_ADDRESS_LENGTH; x++) { 623 for (int i = 0; i < ETHERNET_HARDWARE_ADDRESS_LENGTH; i++) {
583 if (verbose) 624 if (verbose) {
584 printf("%02X", (unsigned char)offer_packet.chaddr[x]); 625 printf("%02X", offer_packet.chaddr[i]);
626 }
585 627
586 if (offer_packet.chaddr[x] != client_hardware_address[x]) 628 if (offer_packet.chaddr[i] != client_hardware_address[i]) {
587 result = ERROR; 629 result = ERROR;
630 }
588 } 631 }
589 if (verbose) 632 if (verbose) {
590 printf("\n"); 633 printf("\n");
634 }
591 635
592 if (result == ERROR) { 636 if (result == ERROR) {
593 if (verbose) 637 if (verbose) {
594 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); 638 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n"));
639 }
595 640
596 continue; 641 continue;
597 } 642 }
@@ -603,7 +648,12 @@ static int get_dhcp_offer(int sock) {
603 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr)); 648 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr));
604 } 649 }
605 650
606 add_dhcp_offer(source.sin_addr, &offer_packet); 651 add_dhcp_offer_wrapper add_res = add_dhcp_offer(source.sin_addr, &offer_packet, dhcp_offer_list);
652 if (add_res.error != OK) {
653 // TODO
654 } else {
655 dhcp_offer_list = add_res.dhcp_offer_list;
656 }
607 657
608 valid_responses++; 658 valid_responses++;
609 } 659 }
@@ -613,104 +663,101 @@ static int get_dhcp_offer(int sock) {
613 printf(_("Valid responses for this machine: %d\n"), valid_responses); 663 printf(_("Valid responses for this machine: %d\n"), valid_responses);
614 } 664 }
615 665
616 return OK; 666 get_dhcp_offer_wrapper ret_val = {
667 .error = OK,
668 .valid_responses = valid_responses,
669 .dhcp_offer_list = dhcp_offer_list,
670 };
671 return ret_val;
617} 672}
618 673
619/* sends a DHCP packet */ 674/* sends a DHCP packet */
620static int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) { 675int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) {
621 int result; 676 int result = sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
622
623 result = sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
624 677
625 if (verbose) 678 if (verbose) {
626 printf(_("send_dhcp_packet result: %d\n"), result); 679 printf(_("send_dhcp_packet result: %d\n"), result);
680 }
627 681
628 if (result < 0) 682 if (result < 0) {
629 return ERROR; 683 return ERROR;
684 }
630 685
631 return OK; 686 return OK;
632} 687}
633 688
634/* receives a DHCP packet */ 689/* receives a DHCP packet */
635static int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address) { 690int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address) {
636 struct timeval tv;
637 fd_set readfds;
638 fd_set oobfds;
639 int recv_result;
640 socklen_t address_size;
641 struct sockaddr_in source_address;
642 int nfound;
643
644 /* wait for data to arrive (up time timeout) */ 691 /* wait for data to arrive (up time timeout) */
645 tv.tv_sec = timeout; 692 struct timeval timeout_val = {
646 tv.tv_usec = 0; 693 .tv_sec = timeout,
694 .tv_usec = 0,
695 };
696 fd_set readfds;
647 FD_ZERO(&readfds); 697 FD_ZERO(&readfds);
698 fd_set oobfds;
648 FD_ZERO(&oobfds); 699 FD_ZERO(&oobfds);
649 FD_SET(sock, &readfds); 700 FD_SET(sock, &readfds);
650 FD_SET(sock, &oobfds); 701 FD_SET(sock, &oobfds);
651 nfound = select(sock + 1, &readfds, NULL, &oobfds, &tv); 702 int nfound = select(sock + 1, &readfds, NULL, &oobfds, &timeout_val);
652 703
653 /* make sure some data has arrived */ 704 /* make sure some data has arrived */
654 if (!FD_ISSET(sock, &readfds)) { 705 if (!FD_ISSET(sock, &readfds)) {
655 if (verbose) 706 if (verbose) {
656 printf(_("No (more) data received (nfound: %d)\n"), nfound); 707 printf(_("No (more) data received (nfound: %d)\n"), nfound);
708 }
657 return ERROR; 709 return ERROR;
658 } 710 }
659 711
660 else { 712 struct sockaddr_in source_address = {0};
661 bzero(&source_address, sizeof(source_address)); 713 socklen_t address_size = sizeof(source_address);
662 address_size = sizeof(source_address); 714 int recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)&source_address, &address_size);
663 recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)&source_address, &address_size); 715 if (verbose) {
664 if (verbose) 716 printf("recv_result: %d\n", recv_result);
665 printf("recv_result: %d\n", recv_result); 717 }
666
667 if (recv_result == -1) {
668 if (verbose) {
669 printf(_("recvfrom() failed, "));
670 printf("errno: (%d) -> %s\n", errno, strerror(errno));
671 }
672 return ERROR;
673 } else {
674 if (verbose) {
675 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
676 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
677 }
678 718
679 memcpy(address, &source_address, sizeof(source_address)); 719 if (recv_result == -1) {
680 return OK; 720 if (verbose) {
721 printf(_("recvfrom() failed, "));
722 printf("errno: (%d) -> %s\n", errno, strerror(errno));
681 } 723 }
724 return ERROR;
725 }
726 if (verbose) {
727 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
728 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
682 } 729 }
683 730
731 memcpy(address, &source_address, sizeof(source_address));
684 return OK; 732 return OK;
685} 733}
686 734
687/* creates a socket for DHCP communication */ 735/* creates a socket for DHCP communication */
688static int create_dhcp_socket(void) { 736int create_dhcp_socket(bool unicast, char *network_interface_name) {
689 struct sockaddr_in myname;
690 struct ifreq interface;
691 int sock;
692 int flag = 1;
693
694 /* Set up the address we're going to bind to. */ 737 /* Set up the address we're going to bind to. */
695 bzero(&myname, sizeof(myname));
696 myname.sin_family = AF_INET;
697 /* listen to DHCP server port if we're in unicast mode */ 738 /* listen to DHCP server port if we're in unicast mode */
698 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); 739 struct sockaddr_in myname = {
699 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; 740 .sin_family = AF_INET,
700 bzero(&myname.sin_zero, sizeof(myname.sin_zero)); 741 .sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT),
742 // TODO previously the next line was trying to use our own IP, we was not set
743 // until some point later, so it was removed. Recheck whether it is actually
744 // necessary/useful
745 .sin_addr.s_addr = INADDR_ANY,
746 };
701 747
702 /* create a socket for DHCP communications */ 748 /* create a socket for DHCP communications */
703 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 749 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
704 if (sock < 0) { 750 if (sock < 0) {
705 printf(_("Error: Could not create socket!\n")); 751 printf(_("Error: Could not create socket!\n"));
706 exit(STATE_UNKNOWN); 752 exit(STATE_UNKNOWN);
707 } 753 }
708 754
709 if (verbose) 755 if (verbose) {
710 printf("DHCP socket: %d\n", sock); 756 printf("DHCP socket: %d\n", sock);
757 }
711 758
712 /* set the reuse address flag so we don't get errors when restarting */ 759 /* set the reuse address flag so we don't get errors when restarting */
713 flag = 1; 760 int flag = 1;
714 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) { 761 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) {
715 printf(_("Error: Could not set reuse address option on DHCP socket!\n")); 762 printf(_("Error: Could not set reuse address option on DHCP socket!\n"));
716 exit(STATE_UNKNOWN); 763 exit(STATE_UNKNOWN);
@@ -722,6 +769,7 @@ static int create_dhcp_socket(void) {
722 exit(STATE_UNKNOWN); 769 exit(STATE_UNKNOWN);
723 } 770 }
724 771
772 struct ifreq interface;
725 /* bind socket to interface */ 773 /* bind socket to interface */
726#if defined(__linux__) 774#if defined(__linux__)
727 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1); 775 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1);
@@ -746,105 +794,116 @@ static int create_dhcp_socket(void) {
746} 794}
747 795
748/* closes DHCP socket */ 796/* closes DHCP socket */
749static int close_dhcp_socket(int sock) { 797int close_dhcp_socket(int sock) {
750
751 close(sock); 798 close(sock);
752
753 return OK; 799 return OK;
754} 800}
755 801
756/* adds a requested server address to list in memory */ 802/* adds a requested server address to list in memory */
757static int add_requested_server(struct in_addr server_address) { 803int add_requested_server(struct in_addr server_address, int *requested_servers, requested_server **requested_server_list) {
758 requested_server *new_server; 804 requested_server *new_server = (requested_server *)malloc(sizeof(requested_server));
759 805 if (new_server == NULL) {
760 new_server = (requested_server *)malloc(sizeof(requested_server));
761 if (new_server == NULL)
762 return ERROR; 806 return ERROR;
807 }
763 808
764 new_server->server_address = server_address; 809 new_server->server_address = server_address;
765 new_server->answered = false; 810 new_server->answered = false;
766 811
767 new_server->next = requested_server_list; 812 new_server->next = *requested_server_list;
768 requested_server_list = new_server; 813 *requested_server_list = new_server;
769 814
770 requested_servers++; 815 *requested_servers += 1;
771 816
772 if (verbose) 817 if (verbose) {
773 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address)); 818 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address));
819 }
774 820
775 return OK; 821 return OK;
776} 822}
777 823
778/* adds a DHCP OFFER to list in memory */ 824/* adds a DHCP OFFER to list in memory */
779static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) { 825add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet, dhcp_offer *dhcp_offer_list) {
826 if (offer_packet == NULL) {
827 add_dhcp_offer_wrapper tmp = {
828 .error = ERROR,
829 };
830 return tmp;
831 }
832
833 uint32_t dhcp_lease_time = 0;
834 uint32_t dhcp_renewal_time = 0;
835 uint32_t dhcp_rebinding_time = 0;
780 dhcp_offer *new_offer; 836 dhcp_offer *new_offer;
781 int x;
782 unsigned option_type;
783 unsigned option_length;
784 struct in_addr serv_ident = {0}; 837 struct in_addr serv_ident = {0};
785
786 if (offer_packet == NULL)
787 return ERROR;
788
789 /* process all DHCP options present in the packet */ 838 /* process all DHCP options present in the packet */
790 for (x = 4; x < MAX_DHCP_OPTIONS_LENGTH - 1;) { 839 for (int dchp_opt_idx = 4; dchp_opt_idx < MAX_DHCP_OPTIONS_LENGTH - 1;) {
791 840
792 if ((int)offer_packet->options[x] == -1) 841 if ((int)offer_packet->options[dchp_opt_idx] == -1) {
793 break; 842 break;
843 }
794 844
795 /* get option type */ 845 /* get option type */
796 option_type = offer_packet->options[x++]; 846 unsigned option_type = offer_packet->options[dchp_opt_idx++];
797 847
798 /* get option length */ 848 /* get option length */
799 option_length = offer_packet->options[x++]; 849 unsigned option_length = offer_packet->options[dchp_opt_idx++];
800 850
801 if (verbose) 851 if (verbose) {
802 printf("Option: %d (0x%02X)\n", option_type, option_length); 852 printf("Option: %d (0x%02X)\n", option_type, option_length);
853 }
803 854
804 /* get option data */ 855 /* get option data */
805 switch (option_type) { 856 switch (option_type) {
806 case DHCP_OPTION_LEASE_TIME: 857 case DHCP_OPTION_LEASE_TIME:
807 memcpy(&dhcp_lease_time, &offer_packet->options[x], sizeof(dhcp_lease_time)); 858 memcpy(&dhcp_lease_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_lease_time));
808 dhcp_lease_time = ntohl(dhcp_lease_time); 859 dhcp_lease_time = ntohl(dhcp_lease_time);
809 break; 860 break;
810 case DHCP_OPTION_RENEWAL_TIME: 861 case DHCP_OPTION_RENEWAL_TIME:
811 memcpy(&dhcp_renewal_time, &offer_packet->options[x], sizeof(dhcp_renewal_time)); 862 memcpy(&dhcp_renewal_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_renewal_time));
812 dhcp_renewal_time = ntohl(dhcp_renewal_time); 863 dhcp_renewal_time = ntohl(dhcp_renewal_time);
813 break; 864 break;
814 case DHCP_OPTION_REBINDING_TIME: 865 case DHCP_OPTION_REBINDING_TIME:
815 memcpy(&dhcp_rebinding_time, &offer_packet->options[x], sizeof(dhcp_rebinding_time)); 866 memcpy(&dhcp_rebinding_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_rebinding_time));
816 dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 867 dhcp_rebinding_time = ntohl(dhcp_rebinding_time);
817 break; 868 break;
818 case DHCP_OPTION_SERVER_IDENTIFIER: 869 case DHCP_OPTION_SERVER_IDENTIFIER:
819 memcpy(&serv_ident.s_addr, &offer_packet->options[x], sizeof(serv_ident.s_addr)); 870 memcpy(&serv_ident.s_addr, &offer_packet->options[dchp_opt_idx], sizeof(serv_ident.s_addr));
820 break; 871 break;
821 } 872 }
822 873
823 /* skip option data we're ignoring */ 874 /* skip option data we're ignoring */
824 if (option_type == 0) /* "pad" option, see RFC 2132 (3.1) */ 875 if (option_type == 0) { /* "pad" option, see RFC 2132 (3.1) */
825 x += 1; 876 dchp_opt_idx += 1;
826 else 877 } else {
827 x += option_length; 878 dchp_opt_idx += option_length;
879 }
828 } 880 }
829 881
830 if (verbose) { 882 if (verbose) {
831 if (dhcp_lease_time == DHCP_INFINITE_TIME) 883 if (dhcp_lease_time == DHCP_INFINITE_TIME) {
832 printf(_("Lease Time: Infinite\n")); 884 printf(_("Lease Time: Infinite\n"));
833 else 885 } else {
834 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time); 886 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time);
835 if (dhcp_renewal_time == DHCP_INFINITE_TIME) 887 }
888 if (dhcp_renewal_time == DHCP_INFINITE_TIME) {
836 printf(_("Renewal Time: Infinite\n")); 889 printf(_("Renewal Time: Infinite\n"));
837 else 890 } else {
838 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time); 891 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time);
839 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) 892 }
893 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) {
840 printf(_("Rebinding Time: Infinite\n")); 894 printf(_("Rebinding Time: Infinite\n"));
895 }
841 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time); 896 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time);
842 } 897 }
843 898
844 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer)); 899 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer));
845 900
846 if (new_offer == NULL) 901 if (new_offer == NULL) {
847 return ERROR; 902 add_dhcp_offer_wrapper tmp = {
903 .error = ERROR,
904 };
905 return tmp;
906 }
848 907
849 /* 908 /*
850 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the 909 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the
@@ -874,15 +933,18 @@ static int add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet) {
874 new_offer->next = dhcp_offer_list; 933 new_offer->next = dhcp_offer_list;
875 dhcp_offer_list = new_offer; 934 dhcp_offer_list = new_offer;
876 935
877 return OK; 936 add_dhcp_offer_wrapper result = {
937 .error = OK,
938 .dhcp_offer_list = dhcp_offer_list,
939 };
940
941 return result;
878} 942}
879 943
880/* frees memory allocated to DHCP OFFER list */ 944/* frees memory allocated to DHCP OFFER list */
881static int free_dhcp_offer_list(void) { 945int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list) {
882 dhcp_offer *this_offer;
883 dhcp_offer *next_offer; 946 dhcp_offer *next_offer;
884 947 for (dhcp_offer *this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) {
885 for (this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) {
886 next_offer = this_offer->next; 948 next_offer = this_offer->next;
887 free(this_offer); 949 free(this_offer);
888 } 950 }
@@ -891,11 +953,9 @@ static int free_dhcp_offer_list(void) {
891} 953}
892 954
893/* frees memory allocated to requested server list */ 955/* frees memory allocated to requested server list */
894static int free_requested_server_list(void) { 956int free_requested_server_list(requested_server *requested_server_list) {
895 requested_server *this_server;
896 requested_server *next_server; 957 requested_server *next_server;
897 958 for (requested_server *this_server = requested_server_list; this_server != NULL; this_server = next_server) {
898 for (this_server = requested_server_list; this_server != NULL; this_server = next_server) {
899 next_server = this_server->next; 959 next_server = this_server->next;
900 free(this_server); 960 free(this_server);
901 } 961 }
@@ -904,39 +964,60 @@ static int free_requested_server_list(void) {
904} 964}
905 965
906/* gets state and plugin output to return */ 966/* gets state and plugin output to return */
907static int get_results(void) { 967mp_subcheck get_results(bool exclusive, const int requested_servers, const struct in_addr requested_address, bool request_specific_address,
908 dhcp_offer *temp_offer, *undesired_offer = NULL; 968 requested_server *requested_server_list, int valid_responses, dhcp_offer *dhcp_offer_list) {
909 requested_server *temp_server; 969 mp_subcheck sc_dhcp_results = mp_subcheck_init();
910 int result; 970 sc_dhcp_results = mp_set_subcheck_default_state(sc_dhcp_results, STATE_OK);
911 uint32_t max_lease_time = 0;
912 971
913 received_requested_address = false; 972 /* we didn't receive any DHCPOFFERs */
914 973 if (dhcp_offer_list == NULL) {
915 /* checks responses from requested servers */ 974 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
916 requested_responses = 0; 975 xasprintf(&sc_dhcp_results.output, "%s", "No DHCPOFFERs were received");
917 if (requested_servers > 0) { 976 return sc_dhcp_results;
977 }
918 978
919 for (temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) { 979 if (valid_responses == 0) {
980 // No valid responses at all, so early exit here
981 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
982 xasprintf(&sc_dhcp_results.output, "No valid responses received");
983 return sc_dhcp_results;
984 }
920 985
921 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 986 if (valid_responses == 1) {
987 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFER", valid_responses);
988 } else {
989 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFERs", valid_responses);
990 }
922 991
992 bool received_requested_address = false;
993 dhcp_offer *undesired_offer = NULL;
994 uint32_t max_lease_time = 0;
995 /* checks responses from requested servers */
996 int requested_responses = 0;
997 if (requested_servers > 0) {
998 for (requested_server *temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) {
999 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
923 /* get max lease time we were offered */ 1000 /* get max lease time we were offered */
924 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1001 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) {
925 max_lease_time = temp_offer->lease_time; 1002 max_lease_time = temp_offer->lease_time;
1003 }
926 1004
927 /* see if we got the address we requested */ 1005 /* see if we got the address we requested */
928 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1006 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) {
929 received_requested_address = true; 1007 received_requested_address = true;
1008 }
930 1009
931 /* see if the servers we wanted a response from talked to us or not */ 1010 /* see if the servers we wanted a response from, talked to us or not */
932 if (!memcmp(&temp_offer->server_address, &temp_server->server_address, sizeof(temp_server->server_address))) { 1011 if (!memcmp(&temp_offer->server_address, &temp_server->server_address, sizeof(temp_server->server_address))) {
933 if (verbose) { 1012 if (verbose) {
934 printf(_("DHCP Server Match: Offerer=%s"), inet_ntoa(temp_offer->server_address)); 1013 printf(_("DHCP Server Match: Offerer=%s"), inet_ntoa(temp_offer->server_address));
935 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address)); 1014 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address));
936 if (temp_server->answered) 1015 if (temp_server->answered) {
937 printf(_(" (duplicate)")); 1016 printf(_(" (duplicate)"));
1017 }
938 printf(_("\n")); 1018 printf(_("\n"));
939 } 1019 }
1020
940 if (!temp_server->answered) { 1021 if (!temp_server->answered) {
941 requested_responses++; 1022 requested_responses++;
942 temp_server->answered = true; 1023 temp_server->answered = true;
@@ -947,94 +1028,115 @@ static int get_results(void) {
947 } 1028 }
948 1029
949 /* exclusive mode: check for undesired offers */ 1030 /* exclusive mode: check for undesired offers */
950 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1031 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
951 if (!temp_offer->desired) { 1032 if (!temp_offer->desired) {
952 undesired_offer = temp_offer; /* Checks only for the first undesired offer */ 1033 undesired_offer = temp_offer; /* Checks only for the first undesired offer */
953 break; /* no further checks needed */ 1034 break; /* no further checks needed */
954 } 1035 }
955 } 1036 }
956 }
957 1037
958 /* else check and see if we got our requested address from any server */ 1038 mp_subcheck sc_rqust_srvs = mp_subcheck_init();
959 else { 1039 xasprintf(&sc_rqust_srvs.output, "%d of %d requested servers responded", requested_responses, requested_servers);
960 1040
961 for (temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) { 1041 if (requested_responses == requested_servers) {
1042 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_OK);
1043 } else if (requested_responses == 0) {
1044 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_CRITICAL);
1045 } else if (requested_responses < requested_servers) {
1046 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1047 } else {
1048 // We received more(!) responses than we asked for?
1049 // This case shouldn't happen, but is here for completion
1050 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1051 }
1052 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqust_srvs);
962 1053
1054 } else {
1055 /* else check and see if we got our requested address from any server */
1056 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
963 /* get max lease time we were offered */ 1057 /* get max lease time we were offered */
964 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) 1058 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) {
965 max_lease_time = temp_offer->lease_time; 1059 max_lease_time = temp_offer->lease_time;
1060 }
966 1061
967 /* see if we got the address we requested */ 1062 /* see if we got the address we requested */
968 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) 1063 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) {
969 received_requested_address = true; 1064 received_requested_address = true;
1065 }
970 } 1066 }
971 } 1067 }
972 1068
973 result = STATE_OK; 1069 if (max_lease_time == DHCP_INFINITE_TIME) {
974 if (valid_responses == 0) 1070 xasprintf(&sc_dhcp_results.output, "%s, max lease time = Infinity", sc_dhcp_results.output);
975 result = STATE_CRITICAL; 1071 } else {
976 else if (requested_servers > 0 && requested_responses == 0) 1072 xasprintf(&sc_dhcp_results.output, "%s, max lease time = %" PRIu32 " seconds", sc_dhcp_results.output, max_lease_time);
977 result = STATE_CRITICAL;
978 else if (requested_responses < requested_servers)
979 result = STATE_WARNING;
980 else if (request_specific_address && !received_requested_address)
981 result = STATE_WARNING;
982
983 if (exclusive && undesired_offer)
984 result = STATE_CRITICAL;
985
986 if (result == 0) /* garrett honeycutt 2005 */
987 printf("OK: ");
988 else if (result == 1)
989 printf("WARNING: ");
990 else if (result == 2)
991 printf("CRITICAL: ");
992 else if (result == 3)
993 printf("UNKNOWN: ");
994
995 /* we didn't receive any DHCPOFFERs */
996 if (dhcp_offer_list == NULL) {
997 printf(_("No DHCPOFFERs were received.\n"));
998 return result;
999 } 1073 }
1000 1074
1001 printf(_("Received %d DHCPOFFER(s)"), valid_responses); 1075 if (exclusive) {
1076 mp_subcheck sc_rogue_server = mp_subcheck_init();
1002 1077
1003 if (exclusive && undesired_offer) { 1078 if (undesired_offer != NULL) {
1004 printf(_(", Rogue DHCP Server detected! Server %s"), inet_ntoa(undesired_offer->server_address)); 1079 // We wanted to get a DHCPOFFER exclusively from one machine, but another one
1005 printf(_(" offered %s \n"), inet_ntoa(undesired_offer->offered_address)); 1080 // sent one (too)
1006 return result; 1081 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_CRITICAL);
1007 }
1008 1082
1009 if (requested_servers > 0) 1083 // Get the addresses for printout
1010 printf(_(", %s%d of %d requested servers responded"), ((requested_responses < requested_servers) && requested_responses > 0) ? "only " : "", requested_responses, 1084 // 1.address of the sending server
1011 requested_servers); 1085 char server_address[INET_ADDRSTRLEN];
1086 const char *server_address_transformed =
1087 inet_ntop(AF_INET, &undesired_offer->server_address, server_address, sizeof(server_address));
1012 1088
1013 if (request_specific_address) 1089 if (server_address != server_address_transformed) {
1014 printf(_(", requested address (%s) was %soffered"), inet_ntoa(requested_address), (received_requested_address) ? "" : _("not ")); 1090 die(STATE_UNKNOWN, "inet_ntop failed");
1091 }
1015 1092
1016 printf(_(", max lease time = ")); 1093 // 2.address offered
1017 if (max_lease_time == DHCP_INFINITE_TIME) 1094 char offered_address[INET_ADDRSTRLEN];
1018 printf(_("Infinity")); 1095 const char *offered_address_transformed =
1019 else 1096 inet_ntop(AF_INET, &undesired_offer->offered_address, offered_address, sizeof(offered_address));
1020 printf("%lu sec", (unsigned long)max_lease_time);
1021 1097
1022 printf(".\n"); 1098 if (offered_address != offered_address_transformed) {
1099 die(STATE_UNKNOWN, "inet_ntop failed");
1100 }
1023 1101
1024 return result; 1102 xasprintf(&sc_rogue_server.output, "Rogue DHCP Server detected! Server %s offered %s", server_address, offered_address);
1103 } else {
1104 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_OK);
1105 xasprintf(&sc_rogue_server.output, "No Rogue DHCP Server detected");
1106 }
1107 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rogue_server);
1108 }
1109
1110 if (request_specific_address) {
1111 mp_subcheck sc_rqustd_addr = mp_subcheck_init();
1112
1113 if (received_requested_address) {
1114 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_OK);
1115 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was offered", inet_ntoa(requested_address));
1116 } else {
1117 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_WARNING);
1118 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was NOT offered", inet_ntoa(requested_address));
1119 }
1120
1121 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqustd_addr);
1122 }
1123
1124 return sc_dhcp_results;
1025} 1125}
1026 1126
1027/* process command-line arguments */ 1127/* process command-line arguments */
1028static int process_arguments(int argc, char **argv) { 1128process_arguments_wrapper process_arguments(int argc, char **argv) {
1029 if (argc < 1) 1129 if (argc < 1) {
1030 return ERROR; 1130 process_arguments_wrapper tmp = {
1131 .error = ERROR,
1132 };
1133 return tmp;
1134 }
1031 1135
1032 call_getopt(argc, argv); 1136 enum {
1033 return validate_arguments(argc); 1137 output_format_index = CHAR_MAX + 1,
1034} 1138 };
1035 1139
1036static int call_getopt(int argc, char **argv) {
1037 extern int optind;
1038 int option_index = 0; 1140 int option_index = 0;
1039 static struct option long_options[] = {{"serverip", required_argument, 0, 's'}, 1141 static struct option long_options[] = {{"serverip", required_argument, 0, 's'},
1040 {"requestedip", required_argument, 0, 'r'}, 1142 {"requestedip", required_argument, 0, 'r'},
@@ -1046,61 +1148,55 @@ static int call_getopt(int argc, char **argv) {
1046 {"verbose", no_argument, 0, 'v'}, 1148 {"verbose", no_argument, 0, 'v'},
1047 {"version", no_argument, 0, 'V'}, 1149 {"version", no_argument, 0, 'V'},
1048 {"help", no_argument, 0, 'h'}, 1150 {"help", no_argument, 0, 'h'},
1151 {"output-format", required_argument, 0, output_format_index},
1049 {0, 0, 0, 0}}; 1152 {0, 0, 0, 0}};
1050 1153
1051 int c = 0; 1154 check_dhcp_config config = check_dhcp_config_init();
1155 int option_char = 0;
1052 while (true) { 1156 while (true) {
1053 c = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index); 1157 option_char = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index);
1054 1158
1055 if (c == -1 || c == EOF || c == 1) 1159 if (option_char == -1 || option_char == EOF || option_char == 1) {
1056 break; 1160 break;
1161 }
1057 1162
1058 switch (c) { 1163 switch (option_char) {
1059
1060 case 's': /* DHCP server address */ 1164 case 's': /* DHCP server address */
1061 resolve_host(optarg, &dhcp_ip); 1165 resolve_host(optarg, &config.dhcp_ip);
1062 add_requested_server(dhcp_ip); 1166 add_requested_server(config.dhcp_ip, &config.num_of_requested_servers, &config.requested_server_list);
1063 break; 1167 break;
1064 1168
1065 case 'r': /* address we are requested from DHCP servers */ 1169 case 'r': /* address we are requested from DHCP servers */
1066 resolve_host(optarg, &requested_address); 1170 resolve_host(optarg, &config.requested_address);
1067 request_specific_address = true; 1171 config.request_specific_address = true;
1068 break; 1172 break;
1069 1173
1070 case 't': /* timeout */ 1174 case 't': /* timeout */
1071 1175 if (atoi(optarg) > 0) {
1072 /* 1176 config.dhcpoffer_timeout = atoi(optarg);
1073 if(is_intnonneg(optarg)) 1177 }
1074 */
1075 if (atoi(optarg) > 0)
1076 dhcpoffer_timeout = atoi(optarg);
1077 /*
1078 else
1079 usage("Time interval must be a nonnegative integer\n");
1080 */
1081 break; 1178 break;
1082 1179
1083 case 'm': /* MAC address */ 1180 case 'm': /* MAC address */
1084 1181 if ((config.user_specified_mac = mac_aton(optarg)) == NULL) {
1085 if ((user_specified_mac = mac_aton(optarg)) == NULL)
1086 usage("Cannot parse MAC address.\n"); 1182 usage("Cannot parse MAC address.\n");
1087 if (verbose) 1183 }
1088 print_hardware_address(user_specified_mac); 1184 if (verbose) {
1089 1185 print_hardware_address(config.user_specified_mac);
1186 }
1090 break; 1187 break;
1091 1188
1092 case 'i': /* interface name */ 1189 case 'i': /* interface name */
1093 1190 strncpy(config.network_interface_name, optarg, sizeof(config.network_interface_name) - 1);
1094 strncpy(network_interface_name, optarg, sizeof(network_interface_name) - 1); 1191 config.network_interface_name[sizeof(config.network_interface_name) - 1] = '\x0';
1095 network_interface_name[sizeof(network_interface_name) - 1] = '\x0';
1096
1097 break; 1192 break;
1098 1193
1099 case 'u': /* unicast testing */ 1194 case 'u': /* unicast testing */
1100 unicast = true; 1195 config.unicast_mode = true;
1101 break; 1196 break;
1197
1102 case 'x': /* exclusive testing aka "rogue DHCP server detection" */ 1198 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1103 exclusive = true; 1199 config.exclusive_mode = true;
1104 break; 1200 break;
1105 1201
1106 case 'V': /* version */ 1202 case 'V': /* version */
@@ -1114,6 +1210,18 @@ static int call_getopt(int argc, char **argv) {
1114 case 'v': /* verbose */ 1210 case 'v': /* verbose */
1115 verbose = 1; 1211 verbose = 1;
1116 break; 1212 break;
1213 case output_format_index: {
1214 parsed_output_format parser = mp_parse_output_format(optarg);
1215 if (!parser.parsing_success) {
1216 // TODO List all available formats here, maybe add anothoer usage function
1217 printf("Invalid output format: %s\n", optarg);
1218 exit(STATE_UNKNOWN);
1219 }
1220
1221 config.output_format_is_set = true;
1222 config.output_format = parser.output_format;
1223 break;
1224 }
1117 case '?': /* help */ 1225 case '?': /* help */
1118 usage5(); 1226 usage5();
1119 break; 1227 break;
@@ -1122,15 +1230,16 @@ static int call_getopt(int argc, char **argv) {
1122 break; 1230 break;
1123 } 1231 }
1124 } 1232 }
1125 return optind;
1126}
1127 1233
1128static int validate_arguments(int argc) { 1234 if (argc - optind > 0) {
1129
1130 if (argc - optind > 0)
1131 usage(_("Got unexpected non-option argument")); 1235 usage(_("Got unexpected non-option argument"));
1236 }
1132 1237
1133 return OK; 1238 process_arguments_wrapper result = {
1239 .config = config,
1240 .error = OK,
1241 };
1242 return result;
1134} 1243}
1135 1244
1136#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1245#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
@@ -1249,7 +1358,7 @@ static int dl_bind(int fd, int sap, u_char *addr) {
1249 * 1358 *
1250 ***********************************************************************/ 1359 ***********************************************************************/
1251 1360
1252static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) { 1361long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1253 int fd; 1362 int fd;
1254 u_char mac_addr[25]; 1363 u_char mac_addr[25];
1255 1364
@@ -1268,51 +1377,53 @@ static long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1268#endif 1377#endif
1269 1378
1270/* resolve host name or die (TODO: move this to netutils.c!) */ 1379/* resolve host name or die (TODO: move this to netutils.c!) */
1271static void resolve_host(const char *in, struct in_addr *out) { 1380void resolve_host(const char *name, struct in_addr *out) {
1272 struct addrinfo hints, *ai; 1381 struct addrinfo hints = {
1382 .ai_family = PF_INET,
1383 };
1384 struct addrinfo *addr_info;
1273 1385
1274 memset(&hints, 0, sizeof(hints)); 1386 if (getaddrinfo(name, NULL, &hints, &addr_info) != 0) {
1275 hints.ai_family = PF_INET;
1276 if (getaddrinfo(in, NULL, &hints, &ai) != 0)
1277 usage_va(_("Invalid hostname/address - %s"), optarg); 1387 usage_va(_("Invalid hostname/address - %s"), optarg);
1388 }
1278 1389
1279 memcpy(out, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(*out)); 1390 memcpy(out, &((struct sockaddr_in *)addr_info->ai_addr)->sin_addr, sizeof(*out));
1280 freeaddrinfo(ai); 1391 freeaddrinfo(addr_info);
1281} 1392}
1282 1393
1283/* parse MAC address string, return 6 bytes (unterminated) or NULL */ 1394/* parse MAC address string, return 6 bytes (unterminated) or NULL */
1284static unsigned char *mac_aton(const char *string) { 1395unsigned char *mac_aton(const char *string) {
1285 static unsigned char result[6]; 1396 static unsigned char result[MAC_ADDR_LEN];
1286 char tmp[3]; 1397 char tmp[3];
1287 unsigned i, j; 1398 unsigned byte_counter = 0;
1288 1399
1289 for (i = 0, j = 0; string[i] != '\0' && j < sizeof(result); i++) { 1400 for (int i = 0; string[i] != '\0' && byte_counter < sizeof(result); i++) {
1290 /* ignore ':' and any other non-hex character */ 1401 /* ignore ':' and any other non-hex character */
1291 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) 1402 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) {
1292 continue; 1403 continue;
1404 }
1293 tmp[0] = string[i]; 1405 tmp[0] = string[i];
1294 tmp[1] = string[i + 1]; 1406 tmp[1] = string[i + 1];
1295 tmp[2] = '\0'; 1407 tmp[2] = '\0';
1296 result[j] = strtol(tmp, (char **)NULL, 16); 1408 result[byte_counter] = strtol(tmp, (char **)NULL, 16);
1297 i++; 1409 i++;
1298 j++; 1410 byte_counter++;
1299 } 1411 }
1300 1412
1301 return (j == 6) ? result : NULL; 1413 return (byte_counter == MAC_ADDR_LEN) ? result : NULL;
1302} 1414}
1303 1415
1304static void print_hardware_address(const unsigned char *address) { 1416void print_hardware_address(const unsigned char *address) {
1305 int i;
1306 1417
1307 printf(_("Hardware address: ")); 1418 printf(_("Hardware address: "));
1308 for (i = 0; i < 5; i++) 1419 for (int addr_idx = 0; addr_idx < MAC_ADDR_LEN; addr_idx++) {
1309 printf("%2.2x:", address[i]); 1420 printf("%2.2x:", address[addr_idx]);
1310 printf("%2.2x", address[i]); 1421 }
1311 putchar('\n'); 1422 putchar('\n');
1312} 1423}
1313 1424
1314/* print usage help */ 1425/* print usage help */
1315static void print_help(void) { 1426void print_help(void) {
1316 1427
1317 print_revision(progname, NP_VERSION); 1428 print_revision(progname, NP_VERSION);
1318 1429
@@ -1328,6 +1439,7 @@ static void print_help(void) {
1328 printf(UT_HELP_VRSN); 1439 printf(UT_HELP_VRSN);
1329 printf(UT_EXTRA_OPTS); 1440 printf(UT_EXTRA_OPTS);
1330 1441
1442 printf(UT_OUTPUT_FORMAT);
1331 printf(UT_VERBOSE); 1443 printf(UT_VERBOSE);
1332 1444
1333 printf(" %s\n", "-s, --serverip=IPADDRESS"); 1445 printf(" %s\n", "-s, --serverip=IPADDRESS");
@@ -1346,7 +1458,6 @@ static void print_help(void) {
1346 printf(" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s")); 1458 printf(" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s"));
1347 1459
1348 printf(UT_SUPPORT); 1460 printf(UT_SUPPORT);
1349 return;
1350} 1461}
1351 1462
1352void print_usage(void) { 1463void print_usage(void) {
@@ -1354,6 +1465,4 @@ void print_usage(void) {
1354 printf("%s\n", _("Usage:")); 1465 printf("%s\n", _("Usage:"));
1355 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname); 1466 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname);
1356 printf(" [-i interface] [-m mac]\n"); 1467 printf(" [-i interface] [-m mac]\n");
1357
1358 return;
1359} 1468}
diff --git a/plugins-root/check_dhcp.d/config.h b/plugins-root/check_dhcp.d/config.h
new file mode 100644
index 00000000..f189068b
--- /dev/null
+++ b/plugins-root/check_dhcp.d/config.h
@@ -0,0 +1,50 @@
1#pragma once
2
3#include "../../config.h"
4#include "../lib/states.h"
5#include <stdbool.h>
6#include <netinet/in.h>
7#include "net/if.h"
8#include "output.h"
9
10typedef struct requested_server_struct {
11 struct in_addr server_address;
12 bool answered;
13 struct requested_server_struct *next;
14} requested_server;
15
16typedef struct check_dhcp_config {
17 bool unicast_mode; /* unicast mode: mimic a DHCP relay */
18 bool exclusive_mode; /* exclusive mode aka "rogue DHCP server detection" */
19 int num_of_requested_servers;
20 struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
21 struct in_addr requested_address;
22 bool request_specific_address;
23
24 int dhcpoffer_timeout;
25 unsigned char *user_specified_mac;
26 char network_interface_name[IFNAMSIZ];
27 requested_server *requested_server_list;
28
29 mp_output_format output_format;
30 bool output_format_is_set;
31} check_dhcp_config;
32
33check_dhcp_config check_dhcp_config_init(void) {
34 check_dhcp_config tmp = {
35 .unicast_mode = false,
36 .exclusive_mode = false,
37 .num_of_requested_servers = 0,
38 .dhcp_ip = {0},
39 .requested_address = {0},
40 .request_specific_address = false,
41
42 .dhcpoffer_timeout = 2,
43 .user_specified_mac = NULL,
44 .network_interface_name = "eth0",
45 .requested_server_list = NULL,
46
47 .output_format_is_set = false,
48 };
49 return tmp;
50}
diff --git a/plugins-root/t/check_dhcp.t b/plugins-root/t/check_dhcp.t
index ce627736..70392154 100644
--- a/plugins-root/t/check_dhcp.t
+++ b/plugins-root/t/check_dhcp.t
@@ -12,14 +12,14 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 6; 15 plan tests => 7;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_dhcp"; 17 plan skip_all => "Need sudo to test check_dhcp";
18} 18}
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./'; 21my $successOutput = '/Received \d+ DHCPOFFER(s)*, max lease time = \d+ seconds/';
22my $failureOutput = '/CRITICAL: (No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/'; 22my $failureOutput = '/(No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
23my $invalidOutput = '/Invalid hostname/'; 23my $invalidOutput = '/Invalid hostname/';
24 24
25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE", 25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE",
@@ -34,6 +34,8 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
34 "An invalid (not known to DNS) hostname", 34 "An invalid (not known to DNS) hostname",
35 "nosuchhost" ); 35 "nosuchhost" );
36 36
37my $output_format = "--output-format mp-test-json";
38
37# try to determince interface 39# try to determince interface
38my $interface = ''; 40my $interface = '';
39 41
@@ -49,19 +51,21 @@ my $res;
49SKIP: { 51SKIP: {
50 skip('need responsive test host', 2) unless $host_responsive; 52 skip('need responsive test host', 2) unless $host_responsive;
51 $res = NPTest->testCmd( 53 $res = NPTest->testCmd(
52 "$sudo ./check_dhcp $interface -u -s $host_responsive" 54 "$sudo ./check_dhcp $interface -u -s $host_responsive $output_format"
53 ); 55 );
54 is( $res->return_code, 0, "Syntax ok" ); 56 is( $res->return_code, 0, "with JSON test format result should always be OK" );
55 like( $res->output, $successOutput, "Output OK" ); 57 like( $res->{'mp_test_result'}->{'state'}, "/OK/", "Output OK" );
58 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $successOutput, "Output OK" );
56}; 59};
57 60
58SKIP: { 61SKIP: {
59 skip('need nonresponsive test host', 2) unless $host_nonresponsive; 62 skip('need nonresponsive test host', 2) unless $host_nonresponsive;
60 $res = NPTest->testCmd( 63 $res = NPTest->testCmd(
61 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive" 64 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive $output_format"
62 ); 65 );
63 is( $res->return_code, 2, "Exit code - host nonresponsive" ); 66 is( $res->return_code, 0, "with JSON test format result should always be OK" );
64 like( $res->output, $failureOutput, "Output OK" ); 67 like( $res->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Exit code - host nonresponsive" );
68 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $failureOutput, "Output OK" );
65}; 69};
66 70
67SKIP: { 71SKIP: {
@@ -69,6 +73,6 @@ SKIP: {
69 $res = NPTest->testCmd( 73 $res = NPTest->testCmd(
70 "$sudo ./check_dhcp $interface -u -s $hostname_invalid" 74 "$sudo ./check_dhcp $interface -u -s $hostname_invalid"
71 ); 75 );
72 is( $res->return_code, 3, "Exit code - host invalid" ); 76 is( $res->return_code, 3, "invalid hostname/address should return UNKNOWN" );
73 like( $res->output, $invalidOutput, "Output OK" ); 77 like( $res->output, $invalidOutput, "Output OK" );
74}; 78};